unit uSendFileInChunks2;

interface

uses
  System.IOUtils,
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,System.Types,
  System.NetEncoding,idGlobal,IdHTTP,IdTCPClient,IdTCPConnection, System.SyncObjs,
  System.RegularExpressions,

  //myUnits

  uEtcetra_PS_HTTPClient,uCreateUniqueName,uDivideAndGatherFile
  ;


type
TUploadInChunksEvents = procedure (Sender: TObject; ACountBytes:Int64)  of object;


type
  TSendFileInChunks2 = class(TDataModule)
  private
    { Private declarations }


    FOutputDirOnServer:String;
    FTempDirChunksOnServer:string;
    FTempDirChunksOnClient:string;

    FFileSizeBytes:Int64;
    FOriginFileName:string;
    FOriginFileNameEncoded:String;
    FSomeUniqueName:string;
    FTempDirWasCreatedOnServer:Boolean;
    FChunksInfoFileName:String;



    FOnUploadInChunksBegin:TUploadInChunksEvents;
    {< field for Event OnUploadInChunksBegin}

    FOnDivideInChunksOnClient:TUploadInChunksEvents;
    {< field for Event FOnDivideInChunksOnClient}

    FOnSendingChunksInfo:TUploadInChunksEvents;
    {< field for Event FOnDivideInChunksOnClient}

    FOnSendingChunksToServer:TUploadInChunksEvents;
    {< field for Event FOnSendingChunksToServer}


    FOnGatherChunksOnServer:TUploadInChunksEvents;
    {< field for Event FOnSendingChunksToServer}

    FOnUploadInChunks:TUploadInChunksEvents;
    {< field for Event FOnUploadInChunks}
    FOnUploadInChunksEnd:TUploadInChunksEvents;
    {< field for Events FOnUploadInChunksEnd}



    function CreateOutputDirOnServer: string;
     {<this method will create output dir on server - dir to upload file
     Example--ExtractFilePath(Application.Exename)\public\files\UserID\2016\28\10
     }

    function CreateTempDirOnServer:string;

    {<this method will create temp dir on server, last folder is filename
      Example--ExtractFilePath(Application.Exename)\public\files\UserID\2016\28\10\temp\filename+GUID
      !!! filename here is folder
    }

    function CreateTempDirOnClient(): string;
      {<  //------- Create temp dir for chunks on client
     //Example--ExtractFilePath(Application.Exename)\files\User_UserID\2016\28\10\temp\filename+GUID
      }


    procedure SendOneWholeFile(AFilePath: String);

    procedure SendChunksInfo(

    AChunksInfoFileName: string;
    AdirTempChunksClient,
    AdirTempServer: string;
    AFileSizeBytes: Int64

    );
    procedure GatherChunksOnServerInOneFile;


  public
    { Public declarations }

    constructor Create(AOwner: TComponent); override;


    procedure SendFileInChunks(AFilePath:String; AChunkSize:Int64);

    // properties for events in chronological order

    property OnUploadInChunksBegin:TUploadInChunksEvents read FOnUploadInChunksBegin write FOnUploadInChunksBegin;
    property OnDivideInChunksOnClient:TUploadInChunksEvents read FOnDivideInChunksOnClient write FOnDivideInChunksOnClient;
    property OnSendingChunksInfo:TUploadInChunksEvents read FOnSendingChunksInfo write FOnSendingChunksInfo;
    property OnSendingChunksToServer:TUploadInChunksEvents read FOnSendingChunksToServer write FOnSendingChunksToServer;
    property OnGatherChunksOnServer:TUploadInChunksEvents read FOnGatherChunksOnServer write FOnGatherChunksOnServer;
    property OnUploadInChunks:TUploadInChunksEvents read FOnUploadInChunks write FOnUploadInChunks;
    property OnUploadInChunksEnd:TUploadInChunksEvents read FOnUploadInChunksEnd write FOnUploadInChunksEnd;


  end;



implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

uses uVisualFrame;

var VisualFrame_HTTP_UnitVar:TVisualFrame_HTTP;


{ TSendFileInChunks2 }

constructor TSendFileInChunks2.Create(AOwner: TComponent);
begin
  inherited;

    if (AOwner is TVisualFrame_HTTP) then
    VisualFrame_HTTP_UnitVar:=(AOwner as TVisualFrame_HTTP);

end;

function TSendFileInChunks2.CreateOutputDirOnServer: string;
var
  Year: Word;
  Month: Word;
  Day: Word;
  Filename: string;



begin

  DecodeDate(Now, Year, Month, Day);
//  Filename := ExtractFileName(AFilePath);

  with VisualFrame_HTTP_UnitVar do
  begin

    FOutputDirOnServer := 'public' +'\'+
    'files' + '\' +
//    HTTP_ConnectionParams.User +
//    '_ID'+
    HTTP_ConnectionParams.IDUser + '\' +
    Year.ToString + '\' +
    Month.ToString + '\' +
    Day.ToString;


    HTTPRequests.CreateDirOnServer(FOutputDirOnServer);
    Result:=FOutputDirOnServer;

  end;


end;




function TSendFileInChunks2.CreateTempDirOnServer: string;
var

  Year: Word;
  Month: Word;
  Day: Word;
  Filename: string;
  dirTempServer: string;



begin
//

//CreatingSomeUniqueName


//TCreateUniqueName.CreateUniqueNameAddingGUID(F)

  DecodeDate(Now, Year, Month, Day);
//  Filename := ExtractFileName(AFilePath);

  with VisualFrame_HTTP_UnitVar do
  begin
    dirTempServer := 'public' +'\'+
    'files' + '\' +
    //HTTP_ConnectionParams.User +
    //'_ID' +
    HTTP_ConnectionParams.IDUser + '\' +
    Year.ToString + '\' +
    Month.ToString + '\' +
    Day.ToString + '\' +
    'temp' + '\' +
    FSomeUniqueName+'\';



  HTTPRequests.CreateDirOnServer(dirTempServer);

  end;

  Result:=dirTempServer;







end;




function TSendFileInChunks2.CreateTempDirOnClient():string;
var
  Year: Word;
  Month: Word;
  Day: Word;
  Filename: string;
  tempDirOnClient: string;

begin

  try

        DecodeDate(Now, Year, Month, Day);


        with VisualFrame_HTTP_UnitVar do
        begin
          tempDirOnClient := ExtractFilePath(Application.Exename) +
          'files' + '\' +
          //HTTP_ConnectionParams.User +
          //'_ID' +
          HTTP_ConnectionParams.IDUser + '\' +
          Year.ToString + '\' +
          Month.ToString + '\' +
          Day.ToString + '\' +
          'temp' + '\' +
          FSomeUniqueName +'\';

        end;


        Result:=tempDirOnClient;

      if not TDirectory.Exists(tempDirOnClient)
         then
         TDirectory.CreateDirectory(tempDirOnClient) else

         begin

           //deleting
            TDirectory.Delete(tempDirOnClient,true);
           //creating
            TDirectory.CreateDirectory(tempDirOnClient);


         end;



  except

   on E:Exception do

    raise Exception.Create('Error creating temp directory on client EClassName'+E.ClassName+' '
    +'EMessage '+E.Message);

  end;


end;








procedure TSendFileInChunks2.SendFileInChunks(AFilePath: String; AChunkSize:Int64);

var DivideAndGatherFile:TDivideAndGatherFile;
    NChunks:Integer;

begin

//Creating output dir on Server
FOutputDirOnServer:=CreateOutputDirOnServer;
FOriginFileName:=ExtractFileName(AFilePath);
FOriginFileName:=TEtcetra.Translit(FOriginFileName);
FOriginFileNameEncoded:=TNetEncoding.URL.Encode(FOriginFileName);


try

//------------------PREPARATION--------------


FFileSizeBytes:=TEtcetra.GetFileSize(AFilePath);

//firing event here
if Assigned(FOnUploadInChunksBegin) then FOnUploadInChunksBegin(Self,FFileSizeBytes);



          //---------------MAIN WORK OF SENDING FILES------------------

          if FFileSizeBytes<=AChunkSize then

          //---------------SEND WHOLE FILE

             begin

             SendOneWholeFile(AFilePath);
             FTempDirWasCreatedOnServer:=False;
             end

          else

          if FFileSizeBytes>AChunkSize then

          //------------SEND FILE IN CHUNKS

             begin


              FSomeUniqueName:=TCreateUniqueName.CreateUniqueNameAddingGUID( FOriginFileName,15 );

              //Creating temp dir for chunks on Client
              FTempDirChunksOnClient:=CreateTempDirOnClient;

              //Creating temp dir for chunks on Server
              FSomeUniqueName:=TNetEncoding.URL.Encode(FSomeUniqueName);
              FTempDirChunksOnServer:=CreateTempDirOnServer;
              FTempDirWasCreatedOnServer:=true;

             // Dividing file on chunks on client

             //firing event
             if Assigned(FOnDivideInChunksOnClient) then FOnDivideInChunksOnClient(Self,FFileSizeBytes);

             DivideAndGatherFile:=TDivideAndGatherFile.Create(Self);

             DivideAndGatherFile.DivideFileInChunks2(      // Error handling Ok here
             AFilePath,
             AChunkSize,
             FTempDirChunksOnClient,
             FSomeUniqueName
             );


                    // How many chunks?

               if ( TEtcetra.GetFileSize(AFilePath) mod AChunkSize  )<>0 then

               NChunks:=( TEtcetra.GetFileSize(AFilePath) div AChunkSize  )+1 else
               NChunks:=( TEtcetra.GetFileSize(AFilePath) mod AChunkSize  );


             //*-----Sending ChunksInfo


             //firing event
             if Assigned(FOnSendingChunksInfo) then FOnSendingChunksInfo(Self,FFileSizeBytes);

               FChunksInfoFileName:='ChunksInfo.txt';

             SendChunksInfo(

             FChunksInfoFileName,
             FTempDirChunksOnClient,
             FTempDirChunksOnServer,
             FFileSizeBytes

             );


             //----------- Send many files to Server


             if Assigned(FOnSendingChunksToServer) then FOnSendingChunksToServer(Self,FFileSizeBytes);

             VisualFrame_HTTP_UnitVar.
             HTTPRequests.SendManyFiles2(FTempDirChunksOnClient,FTempDirChunksOnServer); // Error Handling OK


             //------------GatherChunksOnServerInOneFile

             if Assigned(FOnGatherChunksOnServer) then FOnGatherChunksOnServer(Self,FFileSizeBytes);
             GatherChunksOnServerInOneFile;



             //Firing OnUploadEnd Event
             if Assigned(FOnUploadInChunksEnd) then FOnUploadInChunksEnd(Self,FFileSizeBytes);

             end;





finally

//Delete tempdir on Client
if TDirectory.Exists( TNetEncoding.URL.Decode(FTempDirChunksOnClient) ) then
TDirectory.Delete(TNetEncoding.URL.Decode(FTempDirChunksOnClient),true);

if FTempDirWasCreatedOnServer then
//Delete tempdir on Server
VisualFrame_HTTP_UnitVar.HTTPRequests.DeleteDirOnServer(FTempDirChunksOnServer);

end;



end;



procedure TSendFileInChunks2.GatherChunksOnServerInOneFile;

begin

if
VisualFrame_HTTP_UnitVar.
HTTPRequests.
IsCheckChunksIntegrityOk(FTempDirChunksOnServer,FChunksInfoFileName) then

 begin

 VisualFrame_HTTP_UnitVar.
 HTTPRequests.GatherFileFromChunks(FTempDirChunksOnServer,FOutputDirOnServer,FOriginFileNameEncoded);

 end;


end;


procedure TSendFileInChunks2.SendChunksInfo(

 AChunksInfoFileName:string;
 AdirTempChunksClient:String;
 AdirTempServer:string;
 AFileSizeBytes:Int64

);


var EncodedAdirTempServer:string;

begin


           {in dir that we send to Server may be Russian Symbols, so we have to encode it here
           it will be decoded on Server
           }
           EncodedAdirTempServer:=TNetEncoding.URL.Encode(AdirTempServer);

           VisualFrame_HTTP_UnitVar.
           HTTPRequests.
           SendChunksInfoInFile(AdirTempChunksClient,EncodedAdirTempServer, AFileSizeBytes,AChunksInfoFileName);  // Error Handling Ok


end;





procedure TSendFileInChunks2.SendOneWholeFile(AFilePath:String);

var EncodedFileName:String;

begin
//



          EncodedFileName:=TNetEncoding.URL.Encode(FOriginFileName);


          VisualFrame_HTTP_UnitVar.HTTPRequests.
          SendOneFileWithoutLog(AFilePath,FoutputDirOnServer,FOriginFileName);


           // firing Event Here
           if Assigned(FOnUploadInChunks) then
           FOnUploadInChunks(Self,FFileSizeBytes);


           //Firing OnUploadEnd Event
            if Assigned(FOnUploadInChunksEnd) then
           FOnUploadInChunksEnd(Self,FFileSizeBytes);


       {
       //Write File to DataBase

       begin
       // Adding Record To DataBase
       VisualFrame_HTTP_UnitVar.HTTPRequests.
       AddFileToDB(FoutputDirOnServer,FNewUniqueName, VisualFrame_HTTP_UnitVar.HTTP_ConnectionParams.IDUser);
       ;

       VisualFrame_HTTP_UnitVar.UpdateCurrentFolder;



          //Firing OnUploadInChunksEnd Event
//       if Assigned(OnUploadInChunksEnd) then OnUploadInChunksEnd(Self,FFileSizeBytes);

       end;

       }

       VisualFrame_HTTP_UnitVar.UpdateCurrentFolder;

end;


end.
