 constructor THeoGorDownPDFThread.Create (AOnTerminate: TNotifyEvent; AService: TService);
  begin
   inherited Create (false);          // Create thread in NOT suspended mode
   FMainService:= AService;
   FLock:= TCriticalSection.Create;
   FRunning:= false;
   FTermEvent:= TEvent.Create (nil, False, False, '');


//   OnTerminate:= AOnTerminate;
//   FreeOnTerminate:= true;
   FreeOnTerminate:= false;          // Ensure manual freeing of thread resources
  end;




 destructor THeoGorDownPDFThread.Destroy;
  begin
{$IFDEF DEBUG}
   Write('Ukoncuji thread GOR Download PDF...');
{$ENDIF}
   if (FTimer<>0) then
    CloseHandle (FTimer);
   FTermEvent.Free;
   FRunning:= false;
   FMainService:= nil;
   Terminate;
   FLock.Free;
   inherited;
{$IFDEF DEBUG}
   WriteLn('OK');
{$ENDIF}
  end;



 procedure THeoGorDownPDFThread.TerminatedSet;
  begin
   FTermEvent.SetEvent;
  end;



 procedure THeoGorDownPDFThread.ThreadTerminate;
  begin
   Terminate;
   WaitFor;
  end;



 procedure THeoGorDownPDFThread.Execute;
  const _Second = 10_000_000;
  var lSQL, errMsg, url, outData, fName, loopCasTyp: string;
      lLoop, idDigiFile, cnt, idx: Integer;
      lLoopMax, koefProCas: integer;
      logRunCnt: integer;
      Msg: TMsg;
      firstRun, inProg, inDL: boolean;
      lQry: TFDQuery;
      sqlConnX, sqlConnX2: TFDConnection;
      sqlTrans: IFDPhysTransaction;
      f, lOpenSSLLib: string;

      lBusy: LongInt;
      liDueTime: LARGE_INTEGER;

      mamSSLLibs: boolean;
      sslLibPath: string;
      http1: System.Net.HTTPClient.THTTPClient;
      iResp: System.Net.HTTPClient.IHTTPResponse;
      aResp: TMemoryStream;
      http2: TIdHttp;
      sslHndlr: TIdSSLIOHandlerSocketOpenSSL;
      respHttp2: TStream;
      i: integer;
      sTemp, outData2: string;

      cfgFile: string;
      specCfgXML: XML.XmlIntf.IXMLDocument;
      n1: XML.XmlIntf.IXMLNode;
      attribs: IXMLNodeList;
      attrIdx: integer;

    function StringToHex (const inStr: string): string;
     var i: integer;
     begin
      result:= '';
      for i:=1 to Length(inStr) do
       result:= result + IntToHex(Ord(inStr[i]), 2); // 2 means two hex digits per character
     end;

   function MemStreamToHex (aStream: TMemoryStream): string;
    var i: integer;
        b: byte;
    begin
     result:= '';
     for i:=0 to aStream.Size-1 do
      begin
       b:= PByte(TMemoryStream(aStream).Memory)[i];
       result:= result + IntToHex(b,2);
      end;
    end;

  begin
   lLoop:= 0;
   idDigiFile:= 0;
   logRunCnt:= 1;

{
   koefProCas:= 0; // default vteriny
   loopCasTyp:= '???';
   case DZTaksZapisTypCas of
    0: koefProCas:= 1;
    1: koefProCas:= 60;
    2: koefProCas:= 3600;
   end;
   lLoopMax:= koefProCas * intProcessDZTasksSec;
   case DZTaksZapisTypCas of
    0: loopCasTyp:= 'sek';
    1: loopCasTyp:= 'min';
    2: loopCasTyp:= 'hod';
   end;
}

   lLoopMax:= 10; // v minutach !!!!
   try
     try
       CoInitialize(nil);
       cfgFile:= ExtractFilePath(ParamStr(0)) + 'gornicky.xml';
       if (FileExists(cfgFile)) then
        begin
         specCfgXML:= Xml.XMLDoc.TXMLDocument.Create(nil);
         specCfgXML.LoadFromFile (cfgFile);
         specCfgXML.Active:= true;
         if not(specCfgXML.IsEmptyDoc) then
          begin
           if (specCfgXML.DocumentElement<>nil) then
            begin
             n1:= specCfgXML.DocumentElement;
             if (n1.NodeName='config') then
              begin
               attribs:= n1.AttributeNodes;

               attrIdx:= attribs.IndexOf('downPDFintMins');
               if (attrIdx>-1) then
                if (attribs.Get(attrIdx).NodeValue<>null) then
                 lLoopMax:= attribs.Get(attrIdx).NodeValue;
              end; // n1 = config
            end; // specCfgXML.DocumentElement<>nil
          end; // not specCfgXML.IsEmptyDoc
        end; // FileExists(cfgFile)
      except
     end;
    finally
     begin
      if (specCfgXML<>nil) then
       specCfgXML:= nil;
      CoUninitialize;
     end;
   end;
   
   datMod.LogInfo (Quick.Logger.etInfo, 'Download PDF interval: ' + lLoopMax.ToString + ' min.');
   lLoopMax:= lLoopMax * 60; // minuty na vteriny


   firstRun:= true;
   inProg:= false;

   sslLibPath:= '';
   f:= ExtractFilePath (ParamStr(0));
   mamSSLLibs:= false;
   for lOpenSSLLib in OPENSSL_LIBS do
    begin
     if (FileExists(TPath.Combine(f, lOpenSSLLib))) then
      begin
       mamSSLLibs:= true;
       sslLibPath:= ExcludeTrailingPathDelimiter (f);
      end;
    end;


   FRunning:= false;
   if not(datMod.SQLTableExists(tblAPIDigiSoubory)) then
    Exit;

   FRunning:= true;


   if (1=1) then // pro rychle vypnuti
    begin
     FTimer:= CreateWaitableTimer (nil, true, 'GorDownloadPDFWaitableTimer');
     liDueTime.QuadPart:= -1*_Second;


     try
      while not(Terminated) or not(FRunning) do
       begin
        if (HDCDZApiService<>nil) then
         if (HDCDZApiService.Terminated) then
          begin
           Terminate;
           FRunning:= false;
          end;

        PeekMessage (&Msg, 0, 0, 0, PM_NOREMOVE); { Create message queue }

        if (lLoop=lLoopMax) or (firstRun) then  // pri startu a pak kazdou minutu
         begin
          idDigiFile:= 0;
          firstRun:= false;

          if (logRunCnt<4) then
           datMod.LogInfo (Quick.Logger.etInfo, 'Spoustim download ' + logRunCnt.toString + '...');
          if (logRunCnt=4) then
           datMod.LogInfo (Quick.Logger.etInfo, 'Spoustim download - bezi ale dal neloguju');

          try
            if not(inProg) then // nebezi uz ?
             begin

              if (1=1) then // pro rychle vypnuti
               begin

                sqlConnX:= TFDConnection.Create (nil);
                sqlConnX.Params.SetStrings (datMod.sqlConnParams);
//                sqlConnX.TxOptions.AutoCommit:= false;
                sqlConnX.Open;
                
                if (sqlConnX.Connected) then
                 begin
//                  sqlConnX.ExecSQL('DECLARE @i INT; SET @i=ISNULL( (SELECT MAX(ID) FROM dbo.TabDokumenty), 1); DBCC CHECKIDENT (TabDokumenty, RESEED, @i)');

                  lSQL:= '/* hdcDZApiSvc */ SELECT ID FROM ' + tblAPIDigiSoubory + ' WHERE Blokovano=0 AND Zpracovano=0 AND Zpracovat=1'
                       + ' AND IDDokument IS NULL ORDER BY ID';

                  lQry:= TFDQuery.Create(nil);
                  try
                    lQry.Connection:= sqlConnX;
                    lQry.Open(lSQL);
                    if (lQry.RecordCount>0) then
                     begin
                      lQry.First;
                      if (sqlConnX.TxOptions.AutoCommit=false) then
                       sqlConnX.StartTransaction;
                      inProg:= true;

                      while not(lQry.EOF) do
                       begin

                        PeekMessage (&Msg, 0, 0, 0, PM_NOREMOVE); { Create message queue }
                        helUtils.ProcessPendingVCLMessages;

                        idDigiFile:= lQry.FieldByName('ID').asInteger;
                        if (idDigiFile>0) then
                         begin
                          try
// musim to zablokovat uz tady aby se to nezpracovavalo znovu
                            sqlConnX.ExecSQL('UPDATE ' + tblAPIDigiSoubory + ' SET Blokovano=1 WHERE ID=' + idDigiFile.ToString);
//                            datMod.LogInfo (Quick.Logger.etInfo, 'Zablokovani downloadPDF id ' + idDigiFile.ToString + ' pred zpracovanim');


                            url:= datMod.SQLGetString ('SELECT DocURL FROM ' + tblAPIDigiSoubory + ' WHERE ID=' + idDigiFile.ToString);
                            if (url<>'') then
                             begin
    
                              datMod.LogInfo (Quick.Logger.etInfo, 'Mam URL downloadPDF id ' + idDigiFile.ToString);
                              outData:= '';

                              if (sslLibPath='') then
                                begin
                                 try
                                   http1:= System.Net.HTTPClient.THTTPClient.Create;
                                   datMod.LogInfo (Quick.Logger.etInfo, 'HTTP klient NET vytvoren downloadPDF id ' + idDigiFile.ToString);
                                   aResp:= TMemoryStream.Create;
    //                               datMod.LogInfo (Quick.Logger.etInfo, 'Vytvoren memStream downloadPDF id ' + idDigiFile.ToString);
                                   try
                                     if (Assigned(http1)) then
                                      begin
                                       http1.AllowCookies:= false;
                                       http1.UserAgent:= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/144.0';
                                       http1.Accept:= 'application/pdf';

//                                       datMod.LogInfo (Quick.Logger.etInfo, 'Nacitam data PDF pro downloadPDF id ' + idDigiFile.ToString);
                                       iResp:= http1.Get (url);
                                       aResp:= (iResp.ContentStream as TMemoryStream);
                                       outData:= MemStreamToHex (aResp);
//                                       datMod.LogInfo (Quick.Logger.etInfo, 'Mam data PDF pro downloadPDF id ' + idDigiFile.ToString);

                                      end;
                                    except on E:Exception do
                                     begin
                                      sqlConnX.ExecSQL ('UPDATE ' + tblAPIDigiSoubory + ' SET Blokovano=0 WHERE ID=' + idDigiFile.ToString);
                                      datMod.LogInfo (Quick.Logger.etError, 'Chyba downloadPDF id  ' + idDigiFile.ToString + ' : ' + E.Message);
         {$IFDEF DEBUG}
                                      WriteLn ('Chyba downloadPDF id ' + idDigiFile.ToString + ' >> ' + E.Message);
         {$ENDIF}
                                     end;
                                   end;
                                  finally
                                   http1.Free;
                                   http1:= nil;
                                   aResp.Free;
                                   aResp:= nil;
    //                               datMod.LogInfo (Quick.Logger.etInfo, 'Uvolnen Net HTTP klient a memStream pro downloadPDF id ' + idDigiFile.ToString);
                                 end;
                                end
                               else
                                begin
                                 IdOpenSSLSetLibPath (sslLibPath);
                                 http2:= TIdHttp.Create (nil);
                                 sslHndlr:= TIdSSLIOHandlerSocketOpenSSL.Create (http2);
                                 respHttp2:= TMemoryStream.Create;
                                 try
                                   try
                                     sslHndlr.SSLOptions.Method:= sslvTLSv1_2;
                                     sslHndlr.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_1];
                                     http2.IOHandler:= sslHndlr;

                                     http2.Request.Accept:= 'application/pdf';
                                     http2.Request.BasicAuthentication := False;
                                     http2.HTTPOptions:= http2.HTTPOptions + [hoKeepOrigProtocol] + [hoNoProtocolErrorException];
                                     http2.Request.ContentType:= 'application/pdf; charset=utf-8';
                                     http2.Get (url, respHttp2);
                                     outData:= MemStreamToHex (respHttp2 as TMemoryStream);
                                    except on E:Exception do
                                     begin
                                      sqlConnX.ExecSQL ('UPDATE ' + tblAPIDigiSoubory + ' SET Blokovano=0 WHERE ID=' + idDigiFile.ToString);
                                      datMod.LogInfo (Quick.Logger.etError, 'Chyba downloadPDF (SSL) id  ' + idDigiFile.ToString + ' : ' + E.Message + CRLF + url);
         {$IFDEF DEBUG}
                                      WriteLn ('Chyba downloadPDF (SSL) id ' + idDigiFile.ToString + ' >> ' + E.Message + CRLF + url);
         {$ENDIF}
                                     end;
                                   end;
                                  finally
                                   FreeAndNil (sslHndlr); // must be freed before IdHttp
                                   FreeAndNil (http2);
                                   FreeAndNil (respHttp2);
    //                               datMod.LogInfo (Quick.Logger.etInfo, 'Uvolnen Indy HTTP klient a memStream pro downloadPDF id ' + idDigiFile.ToString);
                                 end;

                                end;


                              if (outData<>'') then
                               begin
    //                            datMod.LogInfo (Quick.Logger.etInfo, 'Mam data 2 PDF pro downloadPDF id ' + idDigiFile.ToString);
                                fName:= '';
                                i:= LastDelimiter ('/\', url);
                                if (i>0) then
                                 fName:= Copy (url, i+1, Length(url)-i);

                                  if (LeftStr(outData,4)='5025') then
                                   begin
                                    outData2:= '';
                                    for i:=1 to Length(outData) div 2 do
                                     outData2:= outData2 + MidStr(outData, (4*i)-1, 2) + MidStr(outData, (4*i)-3, 2);
                                    if (outData2<>'') then
                                     outData:= outData2;
                                   end;

                                  lSQL:= 'DECLARE @i INT' + CRLF + 'SET @i=(SELECT ID FROM dbo.TabDokumenty WHERE JmenoACesta=N' + url.QuotedString
                                       + ')' + CRLF + 'IF (@i IS NULL)' + CRLF
                                       + ' BEGIN' + CRLF + '  INSERT dbo.TabDokumenty (Popis, JmenoACesta, Poznamka, Autor, Dokument) SELECT N' + fName.QuotedString
                                       + ', N' + fName.QuotedString + ', N' + url.QuotedString + ', N''apiImport'''
                                       + ', CONVERT(varbinary(max), 0x' + outData +', 1)' + CRLF + '  SET @i=SCOPE_IDENTITY()' + CRLF + ' END'
                                       + CRLF + 'SELECT @i';
                                  sTemp:= datMod.SQLGetString (lSQL);
                                  if (sTemp<>'') then
                                   begin
    //                                datMod.LogInfo (Quick.Logger.etInfo, 'Update zapisu downloadPDF id ' + idDigiFile.ToString);
                                    lSQL:= 'UPDATE ' + tblAPIDigiSoubory + ' SET IDDokument=' + sTemp + ', DatZpracovani=GETDATE(), Blokovano=0 WHERE ID=' + idDigiFile.ToString;
                                    sqlConnX.ExecSQL(lSQL);
    //                                datMod.LogInfo (Quick.Logger.etInfo, 'Update zapisu/odblokovani downloadPDF id ' + idDigiFile.ToString + ' - OK');
                                   end;
                               end;

                             end; // url<>''


                            if (url='') then
                             begin
                              lSQL:= 'UPDATE ' + tblAPIDigiSoubory + ' SET DatZpracovani=GETDATE(), Blokovano=0 WHERE ID=' + idDigiFile.ToString;
                              sqlConnX.ExecSQL (lSQL);
                             end;


                           except on E:Exception do
                            begin
                             sqlConnX.ExecSQL ('UPDATE ' + tblAPIDigiSoubory + ' SET Blokovano=0 WHERE ID=' + idDigiFile.ToString);
                             errMsg:= E.Message; // datMod.sqlQry11.FieldByName('ErrMsg').AsString;
{$IFDEF DEBUG}
                             WriteLn ('Chyba 2 zpracovani downloadPDF id ' + idDigiFile.ToString + ' >> ' + errMsg);
{$ENDIF}
      //                       sqlConnX.ExecSQL('UPDATE ' + tblAPIDigiSoubory + ' SET PosledniChyba=N' + errMsg.QuotedString + ' WHERE ID=' + idDigiFile.ToString);
                             datMod.LogInfo(Quick.Logger.etError, 'Chyba 2 zpracovani downloadPDF ID ' + idDigiFile.ToString + ' : ' + errMsg);
                            end;
                          end;
                         end;
                        lQry.Next;
                       end; // while
                     end;
                   finally
                    lQry.Close;
                    FreeAndNil (lQry);
//                    lQry.Free;
//                    lQry:= nil;
                  end;
//                  datMod.LogInfo (Quick.Logger.etInfo, 'Uzavrena SQL query - downloadPDF id ' + idDigiFile.ToString);

                  if (sqlConnX.InTransaction) then
                   sqlConnX.Commit;
                  inProg:= false;
                 end; // sql Connected
                sqlConnX.Close;
                FreeAndNil (sqlConnX);
//                sqlConnX.Free;
//                sqlConnX:= nil;

//                datMod.LogInfo (Quick.Logger.etInfo, 'Zrusena SQL connection - downloadPDF id ' + idDigiFile.ToString);
               end;
             end;

           except on E:Exception do
            begin
             inProg:= false;
             if (lQry<>nil) then
              begin
               lQry.Close;
               FreeAndNil (lQry);
              end;
             if (sqlConnX<>nil) then
              begin
               if (sqlConnX.InTransaction) then
                sqlConnX.Rollback;
               sqlConnX.Close;
               FreeAndNil (sqlConnX);
//               sqlConnX.Free;
//               sqlConnX:= nil;
              end;
             errMsg:= E.Message; // datMod.sqlQry11.FieldByName('ErrMsg').AsString;
             if (mamTabPrijataData) then
              datMod.LogInfo (Quick.Logger.etError, 'Chyba zpracovani API souboru ID ' + idDigiFile.ToString + ' : ' + errMsg);
            end;
          end;


          lLoop:= 0;
          if (logRunCnt<5) then
           Inc (logRunCnt);
         end;
        Inc (lLoop);

        if (FTimer<>0) then
         SetWaitableTimer (FTimer, TLargeInteger(liDueTime), 0, nil, nil, false);
        repeat
         lBusy:= MsgWaitForMultipleObjects (1, FTimer, false, INFINITE, QS_ALLINPUT);
        until lBusy = WAIT_OBJECT_0;
//        Sleep (998);

       end;
     finally
     end;

    end;

   if (sqlConnX2<>nil) then
    begin
     if (sqlConnX2.Connected) then
      sqlConnX2.Close;
     FreeAndNil (sqlConnX2);
    end;

  end;


