unit uCreateUniqueName_TPS_ChunkUploader;
{< this unit contains methods that will Create Unique Name}

interface

uses
  System.SysUtils, System.Classes, vcl.dialogs,
  System.RegularExpressions,uSortStringList,StrUtils;

type
  TCreateUniqueName = class(TDataModule)
  private





    { Private declarations }
  public
    { Public declarations }

  class function CreateUniqueNameAddingGUID(

    FileName:string;
    MaxOriginNameLength:Integer


    ):string;
    {< CreateUniqueNameAddingGUID - all clear from the name. This is class function}

    class function AddNumberOnTheEnd(ANameWithNumberOnTheEnd:String):String;


    class function CreateUniqueNameAddingNumber(ANamesToCompare:TStringList; ANameThatShouldBeUnique:String):String;
    {< this method will Create Unique Name like SomeName(1),SomeName(2), Etc.}

    class function IsFileNameUnique(ANameThatShouldBeUnique:String; AAllNamesToCompareSL:TStringList):boolean;
    {< this method will Create Unique Name like SomeName(1),SomeName(2), Etc.}

    class function AddParamAndValueToName(FileName,
    Param,
    Value: string):

    string; static;

    {<this will add Param=Value to someName }

    class function GetParamValueFromFileName(FileName: string; const ParamName: string):string; static;
    {<this will get ParamValue from Name like Param=Value   }

    class function GetNumberInBracketsFromTheEnd(AFileName: string): string; static;

    class function FindAllOffsetsOfSubstrings(ASomeString: string; ASomeSubString:String): TStringList; static;


    class function GetSubStringWithoutLastBracketsInTheEnd(ASomeString, AValueInBrackets: String): String; static;

    class function IsValueInBracketsAtEndOfString(ASomeString, AValueInBrackets: String): Boolean; static;

    class function LimitNameLength(AName:string; AMaxLength:integer): String; static;

    class function GetStringWithoutExtension(AFileName: string; var Extension:String): string; static;

  end;

//var
//  CreateUniqueName: TCreateUniqueName;

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

{ TCreateUniqueName }

{Creating New Unique Name with a rest of old name, using GUID}
class function TCreateUniqueName.CreateUniqueNameAddingGUID(FileName: string; MaxOriginNameLength: Integer): string;

var
    Extension:string;
    SplittedString: TArray<String>;
    SomeStringToChange: string;
    newguid:tguid;
    i: Integer;

    FileNameTemp:string;

begin

//Checks
if FileName='' then Exit;
//if MaxOriginNameLength=0 then exit;  // if MaxOriginNameLength=0 will be only GUID as a result


//1--------- First of all we need to extract extension if it is
SplittedString:=FileName.Split(['.']);

    //we suppose that extensions are symbols after last '.', so...

    // if FileName has extension like 'SomeFileName.exe'

    if Length(SplittedString)>0 //1 and more, for example somename.ext [somename,ext]
    then

begin
    Extension:=SplittedString[ High(SplittedString)  ];


    //Lets join everything except extension
      for i := Low(SplittedString) to High(SplittedString)-1 do
         begin

         if i=0 then
         SomeStringToChange:=SomeStringToChange+SplittedString[i] else
         SomeStringToChange:=SomeStringToChange+'.'+SplittedString[i];
         end;

         //Cutting name up to the MaxOriginNameLength
      if Length( SomeStringToChange )> MaxOriginNameLength then
      SomeStringToChange:=SomeStringToChange.Substring(0,MaxOriginNameLength);

      //Adding GUID
      Createguid(newguid);
      SomeStringToChange:=SomeStringToChange+newguid.ToString;

      // Joining Extension
      SomeStringToChange:=SomeStringToChange+'.'+Extension;

      Result:=SomeStringToChange;

end else

     // if FileName without Extension like 'SomeFileName'
     if Length(SplittedString)=0 then

     begin

     FileNameTemp:=FileName;


      //Cutting name up to the MaxOriginNameLength
      if Length( FileNameTemp )> MaxOriginNameLength then
      FileNameTemp:=FileNameTemp.Substring(0,MaxOriginNameLength);

      //Adding GUID
      Createguid(newguid);
      FileNameTemp:=FileNameTemp+newguid.ToString;


      Result:=FileNameTemp;
     end;

//ShowMessage(Result);
end;



class function TCreateUniqueName.CreateUniqueNameAddingNumber(
  ANamesToCompare: TStringList;
  ANameThatShouldBeUnique: String): String;

begin

 if ANamesToCompare.IndexOf(ANameThatShouldBeUnique)<>-1 then

 begin

  Result:=AddNumberOnTheEnd(ANameThatShouldBeUnique);

 end else
 // Name Already Unique in that list
 Result:=ANameThatShouldBeUnique;



end;



class function TCreateUniqueName.AddNumberOnTheEnd(ANameWithNumberOnTheEnd: String): String;

  var SplittedString:TArray<String>;
      i: integer;
      NameWithoutExtension:string;

      NumberInTheEnd: Integer;
      SubStringWithoutLastBrackets: string;
      StringWithoutExtension:String;
      Extension: string;
      StringWithoutBracketsInTheEnd: string;


begin

// Check of Uniquiness

 StringWithoutExtension:=GetStringWithoutExtension(ANameWithNumberOnTheEnd,Extension);

if GetNumberInBracketsFromTheEnd(ANameWithNumberOnTheEnd)='' then

   begin

    Result:=ANameWithNumberOnTheEnd+'(1)'; // adding first number
    if Extension<>'' then Result:=Result+'.'+Extension;
    

   end else

   begin

   NumberInTheEnd:=GetNumberInBracketsFromTheEnd(StringWithoutExtension).ToInteger;

    if IsValueInBracketsAtEndOfString(StringWithoutExtension,NumberInTheEnd.ToString()) then

       begin


       StringWithoutBracketsInTheEnd:=
       GetSubStringWithoutLastBracketsInTheEnd(StringWithoutExtension,NumberInTheEnd.ToString());

       NumberInTheEnd:=NumberInTheEnd+1;
       Result:=StringWithoutBracketsInTheEnd+'('+NumberInTheEnd.ToString()+')';

       end else

       begin

         Result:=ANameWithNumberOnTheEnd+'(1)'; // adding first number


       end;

      if Extension<>'' then Result:=Result+'.'+Extension;

   end;




{

   SplittedString:=ANameThatShouldBeUnique.Split(['.']);// for test

 if not IsFileNameUnique(ANameThatShouldBeUnique,AAllNamesToCompare) then

    begin

     // if filename has extension like SomeFileName(1).SomeExtension
     // - extracting only FileName withouth Extension

      SplittedString:=ANameThatShouldBeUnique.Split(['.']);

      // if some Extension is...
      if High(SplittedString)>=1 then

        begin

        //Gather all splitted elements except extension
          NameWithoutExtension:='';
          for i := 0 to High(SplittedString) do begin
          NameWithoutExtension:=NameWithoutExtension+SplittedString[i];
          end;
          // we will get here SomeFileName(1)

        //Check if (SomeNumber) for example (1) are on the end of the filename
        //for example someFIleName(1) - also that there is number not letter

        NumberInBrackets:=ExtractNumberInBracketsFromTheEnd(NameWithoutExtension).ToInteger;
        NumberInBrackets:=NumberInBrackets+1;

        SubStringWithoutLastBrackets:=GetSubStringWithoutLastBrackets(NameWithoutExtension,NumberInBrackets.ToString());



        Result:=SubStringWithoutLastBrackets+'('+NumberInBrackets.ToString()+')';

        end else

            begin


            end;




    end else

    Result:=ANameThatShouldBeUnique;
 }


end;


class function TCreateUniqueName.GetStringWithoutExtension(AFileName: string; var Extension:String ): string;

var SplittedString:TArray<String>;
    i: Integer;

begin


 SplittedString:=AFileName.Split(['.']);

      // if some Extension is...
      if High(SplittedString)>=1 then

        begin

        //Gather all splitted elements except extension
          Result:='';
          for i := 0 to High(SplittedString)-1 do begin
          Result:=Result+SplittedString[i];
          end;

          // Remembering Extension;
          Extension:=SplittedString[High(SplittedString)];

        end else

        begin
        Result:=AFileName;
        Extension:='';
        end;





end;


class function TCreateUniqueName.GetNumberInBracketsFromTheEnd(AFileName: string ): string;
var RegEx:TRegEx;
    M:TMatchCollection;
    s:String;
    NumberInBrackets:String;

    RegEx2:TRegEx;
    M2:TMatchCollection;

begin

Result:='';

   RegEx:=TRegEx.Create('\([\d]+\)'); // Extracting (1) from SomeFile(1) - will receive (1)
   M:=RegEx.Matches(AFileName);

   if M.Count>0 then begin
    NumberInBrackets:=M.Item[M.Count-1].Value; // Extracting Last One

   end;

   RegEx2:=TRegEx.Create('[\d]+'); // Extracting 1 from  (1)
   M2:=RegEx2.Matches(NumberInBrackets);

   if M2.Count>0 then begin
    Result:=M2.Item[M.Count-1].Value; // Extracting Last One

   end;


end;


class function TCreateUniqueName.FindAllOffsetsOfSubstrings(ASomeString: string; ASomeSubString:String ): TStringList;
var
  Len: Integer;
  P: Integer;
begin

Result:=TStringList.Create;
//

  Len := Length(ASomeSubString);

  P := PosEx(ASomeSubString, ASomeString, 1);

  while P > 0 do begin

    Result.Add(P.ToString());
    P := PosEx(ASomeSubString, ASomeString, P + Len); // Recursievely call this for next possible substring

  end;


end;



class function TCreateUniqueName.GetSubStringWithoutLastBracketsInTheEnd(ASomeString: string; AValueInBrackets:String ): String;
begin
//

if (ASomeString.Length>0)
and (AValueInBrackets.Length>0)
and (ASomeString.Length-AValueInBrackets.Length>=3) // 3 means (1) for example

then


Result:=ASomeString.
Substring(0,ASomeString.Length-AValueInBrackets.Length-2);// -2 means brackets around value for ex. (1)


end;


class function TCreateUniqueName.
IsValueInBracketsAtEndOfString(ASomeString: string; AValueInBrackets:String ): Boolean;

var ValueInBrackets:String;
    EndOfString:String;

begin

Result:=false;

if ASomeString.Length>=ValueInBrackets.Length then

 begin

 ValueInBrackets:='('+AValueInBrackets+')';
 EndOfString:=ASomeString.Substring(ASomeString.Length-ValueInBrackets.Length);


 if EndOfString=ValueInBrackets then Result:=True;


 end;






end;




class function TCreateUniqueName.LimitNameLength(AName: string; AMaxLength: integer): String;

var Extension:String;
    SubStringWithoutExtension:String;

begin

SubStringWithoutExtension:=GetStringWithoutExtension(AName,Extension);

if AMaxLength<=SubStringWithoutExtension.Length then
Result:=SubStringWithoutExtension.Substring(0,AMaxLength) else
Result:=SubStringWithoutExtension;

if Extension<>'' then Result:=Result+'.'+Extension;


end;


// {Adding Params to FileName, so FileName.exe will be FileName{Param=Value}.exe }
class function TCreateUniqueName.AddParamAndValueToName(FileName: string; Param:string; Value:string ): string;

var
    Extension:string;
    SplittedString: TArray<String>;
    SomeStringToChange:string;
    i: Integer;

    FileNameTemp:string;

begin

//Checks
if FileName='' then Exit;



//1--------- First of all we need to extract extension if it is
SplittedString:=FileName.Split(['.']);

    //we suppose that extensions are symbols after last '.', so...

    // if FileName has extension like 'SomeFileName.exe'

    if Length(SplittedString)>1 //2 and more, for example somename.ext [somename,ext]
    then

begin
    Extension:=SplittedString[ High(SplittedString)  ];


//ShowMessage(Extension); // for test

//2----------Now lets change previous massive Element if it is

      SomeStringToChange:=SplittedString[ High(SplittedString)-1  ];


      //Adding Param And Value
      SomeStringToChange:=SomeStringToChange+'{'+Param+'='+Value+'}';
      SplittedString[ High(SplittedString)-1  ]:=SomeStringToChange;

//3-------Now our name is Unique we can join it back
                Result:='';

                for i := Low(SplittedString) to High(SplittedString)-1 do
                Result:=Result+SplittedString[i]+'.';

                //At last adding Extension
                Result:=Result+Extension;


end else

     // if FileName without Extension like 'SomeFileName'
     if Length(SplittedString)=1 then

     begin

     FileNameTemp:=FileName;
     FileNameTemp:=FileNameTemp+'{'+Param+'='+Value+'}';

      Result:=FileNameTemp;
     end;

//ShowMessage(Result); //for test
end;


{Get Param Value from FileName}
class function TCreateUniqueName.GetParamValueFromFileName(FileName: string; const ParamName:string):string;

var

     RegEx:TRegEx;
     M: TMatchCollection;
     M2: TMatchCollection;
     M3: TMatchCollection;

begin

Result:='';

M:=RegEx.Matches( FileName ,'{'+ParamName+'=[\w\d]*}');//chunkNumber=[\w\d]*[\d]\b //chunkNumber=[\w]*[\d]\b
if M.Count>0 then M2:=RegEx.Matches( M.Item[M.Count-1].Value ,'=[\w\d]*');
if M2.Count>0 then M3:=RegEx.Matches( M2.Item[M2.Count-1].Value ,'[\w\d]*');
if M3.Count>0
     then
         Result:=M3.Item[M3.Count-1].Value;


end;






class function TCreateUniqueName.IsFileNameUnique(ANameThatShouldBeUnique: String;
  AAllNamesToCompareSL: TStringList): boolean;

var SplittedString:TArray<String>;
    i: Integer;


begin


Result:=false;
if AAllNamesToCompareSL.IndexOf(ANameThatShouldBeUnique)<>-1 then Result:=true;



end;

end.
