{********************************************************

 SlavaNap source code.

 Copyright 2001,2002 by SlavaNap development team
 Released under GNU General Public License

 Latest version is available at
 http://www.slavanap.org

**********************************************************

 Unit: class_cmd2list

 TNapCmd2, TNapCmd2List declarations (VCL version)
 TSlavaCmd2, TSlavaCmd2List declarations (non-VCL version)

*********************************************************}
unit class_cmd2list;

interface

uses
 Windows, Classes2, SysUtils;

{$I defines.pas}

type
  TNapCmd2Save     = (cmd2SaveAll, cmd2ID2CRC, cmd2ID2CRCLC); // cmd2SaveAll = save all data, cmd2ID2CRC = id2=crc of cmd and not saved, cmd2ID2CRCLC = same as previous but crc is in lower case
  TNapCmd2         = packed record
       id1        : Integer; // signed long
       id2        : LongInt; // unsigned long
       cmd        : String;
  end;
  PNapCmd2        = ^TNapCmd2;
  TNapCmd2List    = class(TMyList)
    function  Add(Value: TNapCmd2): Integer;
    function  AddEx(Value: TNapCmd2): PNapCmd2;
    procedure Insert(Index:Integer; Value: TNapCmd2);
    procedure Clear; override;
    procedure Delete(Index: Integer);
    function  AddCmd(id1, id2: Integer; cmd:String): Integer;
    function  AddCmdEx(id1, id2: Integer; cmd:String): PNapCmd2;
    function  Cmd(index: Integer): TNapCmd2;
    function  Id1(index: Integer): Integer;
    function  Id2(index: Integer): Integer;
    function  Str(index: Integer): String;
    function  FindByCmd(cmd: String): Integer;
    function  FindByCmdEx(cmd: String): Pointer;
    constructor Create;
    destructor Destroy; override;
    function  GetLength: Integer;
    procedure SaveToFile(filename: String; mode: TNapCmd2Save);
    procedure LoadFromFile(filename: String; mode: TNapCmd2Save);
    procedure SortByID1;
  end;
  PSlavaCmd2      = ^TSlavaCmd2;
  TSlavaCmd2      = packed record
    id1        : Integer;
    id2        : Integer;
    cmd        : String;
    prev,
    next       : PSlavaCmd2;
  end;
  TSlavaCmd2List = packed record
    first      : PSlavaCmd2;
    count      : Integer;
  end;
  PSlavaCmd2List = ^TSlavaCmd2List;

// TNapCmd2List
function  CreateCmd2List: TNapCmd2List;
procedure FreeCmd2List(list: TNapCmd2List);
{$IFNDEF DISABLE_MEMORY_MANAGER}
procedure ExpireCmd2Lists;
{$ENDIF}
// TSlavaCmd2List
function  SlavaCmd2List_Create: PSlavaCmd2List;
procedure SlavaCmd2List_Free(list: PSlavaCmd2List);
procedure SlavaCmd2List_Clear(list: PSlavaCmd2List);
function  SlavaCmd2List_AddItem(list: PSlavaCmd2List; id1,id2: Integer; cmd: String): PSlavaCmd2;
procedure SlavaCmd2List_DeleteItem(list: PSlavaCmd2List; item: PSlavaCmd2);


var
 count_napcmd2list,
 count_napcmd2list_max: Integer;
 count_napcmd2list_items,
 count_napcmd2list_items_max: Integer;

implementation

uses vars, thread, stypes, memory_manager;

{$IFNDEF DISABLE_MEMORY_MANAGER}
var
 lists, items: TMyList; 
{$ENDIF}

function  CreateCmd2List: TNapCmd2List;
begin
{$IFNDEF DISABLE_MEMORY_MANAGER}
 if lists.count>0 then
 begin
  Result:=lists.Items[lists.count-1];
  lists.Delete(lists.count-1);
 end
 else
{$ENDIF}
  Result:=TNapCmd2List.Create;
end;

procedure FreeCmd2List(list: TNapCmd2List);
begin
{$IFNDEF DISABLE_MEMORY_MANAGER}
 list.Clear;
 lists.Add(list);
{$ELSE}
 list.Free;
{$ENDIF}
end;

function CreateItem: PNapCmd2;
var
 data: PNapCmd2;
begin
{$IFNDEF DISABLE_MEMORY_MANAGER}
 if items.count>0 then
 begin
  data:=items.Items[items.count-1];
  items.Delete(items.count-1);
 end
 else
 begin
{$ENDIF}
  data:=AllocMem(sizeof(TNapCmd2));
  Pointer(data^.cmd):=nil;
  inc(count_napcmd2list_items);
  if count_napcmd2list_items>count_napcmd2list_items_max then count_napcmd2list_items_max:=count_napcmd2list_items;
{$IFNDEF DISABLE_MEMORY_MANAGER}
 end;
{$ENDIF}
 Result:=data;
end;

procedure FreeItem(item: PNapCmd2);
begin
 if Pointer(item^.cmd)<>nil then SetLength(item^.cmd,0);
 Finalize(item^);
 FreeMem(item,sizeof(TNapCmd2));
 dec(count_napcmd2list_items);
end;

procedure DeleteItem(item: PNapCmd2);
begin
 if Pointer(item^.cmd)<>nil then SetLength(item^.cmd,0);
{$IFDEF DISABLE_MEMORY_MANAGER}
 FreeItem(item);
{$ELSE}
 items.Add(item);
{$ENDIF}
end;

{$IFNDEF DISABLE_MEMORY_MANAGER}
procedure ExpireCmd2Lists;
var
 list: TNapCmd2List;
 item: PNapCmd2;
begin
 if lists.count>1000 then
 while (lists.count * 3) > count_napcmd2list do
 try
   list:=lists.items[lists.count-1];
   lists.Delete(lists.count-1);
   list.Free;
  except
 end;
 if items.count>10000 then
 while (items.count * 3) > count_napcmd2list_items do
 try
   item:=items.Items[items.count-1];
   items.Delete(items.count-1);
   FreeItem(item);
  except
 end;
end;
{$ENDIF}

{* * * * *  TNapCmd2List  * * * * *}

function TNapCmd2List.Add(Value: TNapCmd2):Integer;
var
 data:PNapCmd2;
begin
 data:=CreateItem;
 with data^ do
 begin
  cmd:=Value.cmd;
  id1:=Value.id1;
  id2:=Value.id2;
 end;
 Result:=inherited Add(data);
end;

function TNapCmd2List.AddEx(Value: TNapCmd2):PNapCmd2;
var
 data:PNapCmd2;
begin
 data:=CreateItem;
 with data^ do
 begin
  cmd:=Value.cmd;
  id1:=Value.id1;
  id2:=Value.id2;
 end;
 inherited Add(data);
 Result:=data;
end;

function TNapCmd2List.AddCmd(id1,id2: Integer; cmd:String): Integer;
var
 data:PNapCmd2;
begin
 data:=CreateItem;
 data^.cmd:=cmd;
 data^.id1:=id1;
 data^.id2:=id2;
 Result:=inherited Add(data);
end;

function TNapCmd2List.AddCmdEx(id1,id2: Integer; cmd:String): PNapCmd2;
var
 data:PNapCmd2;
begin
 data:=CreateItem;
 data^.cmd:=cmd;
 data^.id1:=id1;
 data^.id2:=id2;
 inherited Add(data);
 Result:=data;
end;

procedure TNapCmd2List.Insert(Index:Integer; Value: TNapCmd2);
var
 data:PNapCmd2;
begin
 data:=CreateItem;
 with data^ do
 begin
  cmd:=Value.cmd;
  id1:=Value.id1;
  id2:=Value.id2;
 end;
 inherited Insert(Index,data);
end;

procedure TNapCmd2List.Clear;
begin
 while count>0 do
  Delete(count-1);
 inherited Clear;
end;

procedure TNapCmd2List.Delete(Index: Integer);
begin
 if (Index<0) or (Index>=Count) then exit;
 if Items[Index]<>nil then
  DeleteItem(Items[Index]);
 Inherited Delete(index);
end;

function TNapCmd2List.Cmd(index :Integer): TNapCmd2;
var
 data:TNapCmd2;
begin
 if (index>=0) and (index<count) then
 begin
  Result:=TNapCmd2(Items[index]^);
  exit;
 end;
 data.id1:=-1;
 data.id2:=-1;
 data.cmd:='';
 Result:=data;
end;

function  TNapCmd2List.Id1(index: Integer): Integer;
var
 data:PNapCmd2;
begin
 if (index>=0) and (index<count) then
 begin
  data:=PNapCmd2(Items[index]);
  Result:=data^.id1;
  exit;
 end;
 Result:=-1;
end;

function  TNapCmd2List.Id2(index: Integer): Integer;
var
 data:PNapCmd2;
begin
 if (index>=0) and (index<count) then
 begin
  data:=PNapCmd2(Items[index]);
  Result:=data^.id2;
  exit;
 end;
 Result:=-1;
end;

function  TNapCmd2List.Str(index: Integer): String;
var
 data:PNapCmd2;
begin
 if (index>=0) and (index<count) then
 begin
  data:=PNapCmd2(Items[index]);
  Result:=data^.cmd;
  exit;
 end;
 Result:='';
end;

function  TNapCmd2List.FindByCmd(cmd: String): Integer;
var
 i: Integer;
begin
 cmd:=AnsiLowerCase(cmd);
 for i:=0 to count-1 do
  if AnsiLowerCase(PNapCmd2(Items[i]).cmd)=cmd then
  begin
    Result:=i;
    exit;
  end;
 Result:=-1;
end;

function  TNapCmd2List.FindByCmdEx(cmd: String): Pointer;
// Warning: this function doesn't ignore letters case
var
 i: Integer;
begin
 for i:=0 to count-1 do
  if PNapCmd2(Items[i]).cmd=cmd then
  begin
    Result:=Items[i];
    exit;
  end;
 Result:=nil;
end;

constructor TNapCmd2List.Create;
begin
 inc(count_napcmd2list);
 if count_napcmd2list>count_napcmd2list_max then count_napcmd2list_max:=count_napcmd2list;
 inherited Create;
end;

destructor TNapCmd2List.Destroy;
begin
 Clear;
 dec(count_napcmd2list);
 inherited Destroy;
end;

function  TNapCmd2List.GetLength: Integer;
var
 i,j: Integer;
begin
 j:=0;
 for i:=0 to count-1 do
  inc(j,Length(PNapCmd2(Items[i])^.cmd));
 Result:=j;
end;

procedure TNapCmd2List.SaveToFile(filename: String; mode: TNapCmd2Save);
var
 list: TMyStringList;
 i: Integer;
 item: PNapCmd2;
begin
 list:=TMyStringList.Create;
 for i:=0 to count-1 do
 begin
  item:=items[i];
  case mode of
    cmd2SaveAll: list.Add(IntToStr(item^.id1)+' '+IntToStr(item^.id2)+' '+item^.cmd);
    cmd2ID2CRC, cmd2ID2CRCLC: list.Add(IntToStr(item^.id1)+' '+item^.cmd);
  end;
  if (i mod 200)=50 then
  begin
   {$I checksync.pas}
  end;
 end;
 try
  list.SaveToFile(filename);
  except
 end;
 list.Free;
end;

procedure TNapCmd2List.LoadFromFile(filename: String; mode: TNapCmd2Save);
var
 list: TMyStringList;
 i,j,k: Integer;
 str: String;
begin
 list:=TMyStringList.Create;
 Clear;
 try
  list.LoadFromFile(filename);
  except
   list.Free;
   exit;
 end;
 for i:=0 to list.count-1 do
 begin
  str:=FirstParam(list.Strings[i]);
  if isDigit(str) then
  begin
    j:=StrToIntDef(str,0);
    str:=NextParamEx(list.Strings[i]);
    if mode=cmd2SaveAll then
    begin
      j:=StrToIntDef(FirstParam(str),0);
      str:=NextParamEx(str);
    end
    else
    begin
      if mode=cmd2ID2CRC then k:=StringCRC(str,false)
      else k:=StringCRC(str,true);
    end;
    AddCmd(j,k,str);
  end;
 end;
 list.Free;
end;

procedure TNapCmd2List.SortByID1;
var
 i,j: Integer;
 t: Pointer;
begin
 if count<2 then exit;
 for i:=0 to count-2 do
  for j:=i+1 to count-1 do
  begin
    if PNapCmd2(Items[i])^.id1>PNapCmd2(Items[j])^.id1 then
    begin
      t:=Items[i];
      Items[i]:=Items[j];
      Items[j]:=t;
    end;
  end
end;


{$IFNDEF DISABLE_MEMORY_MANAGER}
procedure ClearCmd2Lists;
var
 i: Integer;
 p: PNapCmd2;
begin
 for i:=0 to lists.count-1 do
  TNapCmd2List(lists.items[i]).Free;
 lists.Clear;
 for i:=0 to items.count-1 do
 begin
   p:=items.Items[i];
   FreeItem(p);
 end;
 items.Clear;
end;
{$ENDIF}

function  SlavaCmd2List_Create: PSlavaCmd2List;
begin
 result:=AllocMem(Sizeof(TSlavaCmd2List));
 result^.first:=nil;
 result^.count:=0;
end;

procedure SlavaCmd2List_Free(list: PSlavaCmd2List);
begin
 SlavaCmd2List_Clear(list);
 FreeMem(list,Sizeof(TSlavaCmd2List));
end;

procedure SlavaCmd2List_Clear(list: PSlavaCmd2List);
var
 p,n: PSlavaCmd2;
begin
 p:=list^.first;
 while p<>nil do
 begin
   n:=p^.next;
   p^.cmd:='';
   FreeMem(p,Sizeof(TSlavaCmd2));
   p:=n;
 end;
 list^.count:=0;
 list^.first:=nil;
end;

function  SlavaCmd2List_AddItem(list: PSlavaCmd2List; id1,id2: Integer; cmd: String): PSlavaCmd2;
begin
 result:=AllocMem(Sizeof(TSlavaCmd2));
 result^.next:=list^.first;
 Pointer(result^.cmd):=nil;
 result^.id1:=id1;
 result^.id2:=id2;
 result^.cmd:=cmd;
 if list^.first<>nil then
  list^.first^.prev:=result;
 list^.first:=result;
 inc(list^.count);
end;

procedure SlavaCmd2List_DeleteItem(list: PSlavaCmd2List; item: PSlavaCmd2);
var
 prev, next: PSlavaCmd2;
begin
 prev:=item^.prev;
 next:=item^.next;
 item^.cmd:='';
 FreeMem(item,Sizeof(TSlavaCmd2));
 if prev=nil then
 begin
  list^.first:=next;
  next^.prev:=nil;
 end
 else
 begin
  prev^.next:=next;
  if next<>nil then
    next^.prev:=prev;
 end;
 dec(list^.count);
end;


initialization
begin
 count_napcmd2list:=0;
 count_napcmd2list_max:=0;
 count_napcmd2list_items:=0;
 count_napcmd2list_items_max:=0;
{$IFNDEF DISABLE_MEMORY_MANAGER}
 lists:=TMyList.Create;
 items:=TMyList.Create;
{$ENDIF}
end;

{$IFNDEF DISABLE_MEMORY_MANAGER}
finalization
begin
 ClearCmd2Lists;
 lists.Free;
 items.Free;
end;
{$ENDIF}

end.
