{
    This file is part of Chentrah,
    Copyright (C) 2004-2008 Anton Rzheshevski (chebmaster@mail.ru).

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses/

 **********************************************************************}
{
  Type
    TMd5List = class(TStringList)
    public
      constructor Create;
      procedure AddMd5(s: string; age: TDateTime; h: PMd5Digest);
      procedure Delete(i: integer); override;
      function Hash(i: integer): PMd5Digest; overload;
      function Age(i: integer): TDateTime;
      function Hash(s: PAnsiChar): PMd5Digest; overload;
      function GetIsHashvalid (phash: pMd5Digest): boolean;
      Destructor Destroy; Override;
    end;

    TMd5Entry = class(TObject)
    public
      age: TDateTime;
      hash: TMd5Digest;
      Constructor Create(var f: file); overload;
      Constructor Create(a: TDateTime; h: TMD5Digest); overload;
      procedure Update(a: TDateTime; h: TMD5Digest);
      procedure Save(var f: file);
    end;


  Var
    MD5List: TMD5List;
    
}

  function _GetIsHashvalid (phash: pMd5Digest): boolean; cdecl;
  begin
   Result:= false;
{   try
//addlog(' - GetIsHashValid...');
    Result:=Md5List.GetIsHashValid(phash);
//addlogComment(BoolChars(Result));
   except
    ProcessGuardedException();
   end;
}
  end;

  function _GetFileDateTime (name: PAnsiChar): TDateTime; cdecl; begin Result:= 0; end;


{  var n: WideString;
  begin
   try
    if name^ = '$' then Die(MI_ERROR_PROGRAMMER_NO_BAKA, ['GetFileDateTime() for containers not implemented yet!']);
    n:= _UnmangleFileName(name);
    Result:=FileDateToDateTime(FileAge(n));
   except
    ProcessGuardedException();
   end;
  end;
}

  var stubhash: TResourceHash;
  procedure _GetFileHash (name: PAnsiChar; phash: pResourceHash); cdecl; begin phash:= @(stubhash); end;
{
var
    n: WideString;
    s: AnsiString;
    i: integer;
    a: TDateTime;
  begin
ErrorMessageBox('Блять', WideString(PCharToString(name)));
   try
    if name^ = '$' then Die(MI_ERROR_PROGRAMMER_NO_BAKA, ['GetFileHash() for containers not implemented yet!']);
    n:= _UnmangleFileName(name);
    if not FileExists(n) then FillChar(phash^, SizeOf(phash^), 0)
    else begin
      s:=PCharToString(name);
      a:=_GetFileDateTime(name);
      CheckForGuardedException;
      i:=Md5List.IndexOf(s);
      if i < 0 then begin
        phash^.Md5Hash:=Md5File(n);
        Md5List.AddMd5(s, a, @(phash^.Md5Hash));
        if MotherState.DebugMode then AddLog ('MD5 hash added for "%0" as "%1"', [s, Md5Print(phash^.Md5Hash)]);
      end
      else begin
        if a = Md5List.Age(i)
        then
          phash^:=PResourceHash(Md5List.Hash(i))^
        else begin
          TMD5Digest(phash^):=Md5File(n);
          (Md5List.GetObject(i) as TMd5Entry).Update(a, TMd5Digest(phash^));
        if MotherState.DebugMode then AddLog ('MD5 hash updated for "%0" as "%1"', [s, Md5Print(phash^.Md5Hash)]);
        end;
      end;
    end;
   except
    ProcessGuardedException();
   end;
  end;

  Constructor TMd5Entry.Create(var f: file); overload;
  begin
    inherited Create;
    BlockRead(f, age, SizeOf(age));
    BlockRead(f, hash, Sizeof(hash));
  end;

  Constructor TMd5Entry.Create(a: TDateTime; h: TMD5Digest); overload;
  begin
    inherited Create;
    Update(a, h);
  end;

  procedure TMd5Entry.Update(a: TDateTime; h: TMD5Digest);
  begin
    age:=a;
    hash:=h;
  end;

  procedure TMd5Entry.Save(var f: file);
  begin
    BlockWrite(f, age, SizeOf(age));
    BlockWrite(f, hash, Sizeof(hash));
  end;

  function TMd5List.GetIsHashvalid (phash: pMd5Digest): boolean;
  var
    i: integer;
    a: TDateTime;
  begin
    Result:=False;
    for i:=0 to Count - 1 do
      if Md5Match(phash^, (GetObject(i) as TMD5Entry).hash)
      then begin
        a:= _GetFileDateTime(PChar(Strings[i]));
        CheckForGuardedException;
        if a = (GetObject(i) as TMD5Entry).age
          then Exit(Yes)
          else (GetObject(i) as TMD5Entry).age :=a;
      end;
  end;

  constructor TMd5List.Create;
  var
    h: file;
    i: integer;
    tn, rn: WideString;
  begin
    if SizeOf(TResourceHash) <> 16 then Die(MI_ERROR_PROGRAMMER_NO_BAKA, ['SizeOf(TResourceHash) != 16']);
    inherited;
    tn:=_UnmangleFileName('*C/md5table.txt');
    rn:=_UnmangleFileName('*C/md5table');
    if FileExists(tn) and FileExists(rn)
    then try
      _MakeSurePathExists(PChar(MotherState.CacheDir));
      CheckForGuardedException;
      LoadFromFile(tn);
      AssignFile(h, rn);
      Reset(h, 1);
      if FileSize(h) <> Count * (SizeOf(TMd5Digest) + SizeOf(TDateTime))
      then begin
        CloseFile(h);
        Clear;
        Exit;
      end;

      For i:=0 to Count - 1 do begin
        PutObject(i, TMD5Entry.Create(h));
//addlog('-- "%0" %1', [Strings[i], Md5Print((GetObject(i) as TMD5Entry).hash)])
      end;
      CloseFile(h);
    except
//      addlog('ERROR LOADING MD5 DATABASE! %0', [StopDying]);
      Clear;
      Try closeFile(h) except end;
    end;
  end;

function TMd5List.Hash(s: PAnsiChar): PMd5Digest;
var
  i: integer;
begin
  Result:= nil;

  i:=Self.IndexOf(PCharToString(s));
  if i < 0 then Result:=nil
           else Result:= Self.Hash(i);

end;

  procedure TMd5List.AddMd5(s: string; age: TDateTime; h: PMd5Digest);
  var
    i: integer;
  begin
//    i:=IndexOf(s);
//    if i < 0  then
AddObject(s, TMd5Entry.Create(age, h^))
//      else (GetObject(i) as TMD5Entry).Update(age, h^);
  end;

  procedure TMd5List.Delete(i: integer);
  begin
    Try GetObject(i).Free; Except End;
    inherited Delete(i);
  end;

  function TMd5List.Hash(i: integer): PMd5Digest;
  var o: TObject;
  begin
    o:= GetObject(i);
    if not Assigned(o) then Exit(nil);
    Result:=@((o as TMD5Entry).hash);
  end;


  function TMd5List.Age(i: integer): TDateTime;
  begin
    Result:=(GetObject(i) as TMD5Entry).age;
  end;
  



  Destructor TMd5List.Destroy;
  var
    h: file;
    i: integer;
  begin
    Try
      _MakeSurePathExists(PChar(MotherState.CacheDir));
      //CheckForGuardedException;
      SaveToFile(_UnmangleFileName('*C/md5table.txt'));
      //CheckForGuardedException;
      AssignFile(h, _UnmangleFileName('*C/md5table'));
      //CheckForGuardedException;
      Rewrite(h, 1);
      For i:=0 to Count - 1 do
        (GetObject(i) as TMD5Entry).Save(h);
      CloseFile(h);
    Except
      Try CloseFile(h); Except End;
    End;
    pointer(MD5List):= nil;
    inherited;
  end;
 }
  
