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

 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_cmdlist

 TNapCmd and TNapCmdList declarations

*********************************************************}
unit class_cmdlist;

interface

uses
 Windows, Classes2, SysUtils;

{$I defines.pas}

type
  TNapCmd         = record
       id         : Integer;
       cmd        : String;
  end;
  PNapCmd         = ^TNapCmd;
  TNapCmdList     = class(TMyList)
    function  Add(Value: TNapCmd):Integer;
    procedure Insert(Index:Integer; Value: TNapCmd);
    procedure Clear; override;
    procedure Delete(Index: Integer);
    function  AddCmd(id: Integer; cmd:String): Integer;
    function  Cmd(index: Integer): TNapCmd;
    function  Id(index: Integer): Integer;
    function  Str(index: Integer): String;
    function  FindByCmd(cmd: String; ignore_case: Boolean): Integer;
    function  FindById(id: Integer): Integer;
    function  FindItem(id: Integer; cmd: String): Integer;
    procedure SaveToFile(filename: String);
    procedure LoadFromFile(filename: String);
    procedure Sort;
    constructor Create;
    destructor Destroy; override;
    function  GetLength: Integer;
  end;

function  CreateCmdList: TNapCmdList;
procedure FreeCmdList(list: TNapCmdList);
{$IFNDEF DISABLE_MEMORY_MANAGER}
procedure ExpireCmdLists;
{$ENDIF}

var
 count_napcmdlist,
 count_napcmdlist_max: Integer;
 count_napcmdlist_items,
 count_napcmdlist_items_max: Integer;

implementation

uses vars, thread, stypes, memory_manager;

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

function  CreateCmdList: TNapCmdList;
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:=TNapCmdList.Create;
end;

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

function CreateItem: PNapCmd;
var
 data: PNapCmd;
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(TNapCmd));
  Pointer(data^.cmd):=nil;
  inc(count_napcmdlist_items);
  if count_napcmdlist_items>count_napcmdlist_items_max then count_napcmdlist_items_max:=count_napcmdlist_items;
{$IFNDEF DISABLE_MEMORY_MANAGER}
 end;  
{$ENDIF}
 Result:=data;
end;

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

procedure DeleteItem(item: PNapCmd);
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 ExpireCmdLists;
var
 list: TNapCmdList;
 item: PNapCmd;
begin
 if lists.count>1000 then
 while (lists.count * 3) > count_napcmdlist 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_napcmdlist_items do
 try
   item:=items.Items[items.count-1];
   items.Delete(items.count-1);
   FreeItem(item);
  except
 end;
end;
{$ENDIF}

{* * * * *  TNapCmdList  * * * * *}

function TNapCmdList.Add(Value: TNapCmd):Integer;
var
 data:PNapCmd;
begin
 data:=CreateItem;
 with data^ do
 begin
  cmd:=Value.cmd;
  id:=Value.id;
 end;
 Result:=inherited Add(data);
end;

procedure TNapCmdList.Insert(Index:Integer; Value: TNapCmd);
var
 data:PNapCmd;
begin
 data:=CreateItem;
 with data^ do
 begin
  cmd:=Value.cmd;
  id:=Value.id;
 end;
 inherited Insert(Index,data);
end;

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

procedure TNapCmdList.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 TNapCmdList.AddCmd(id: Integer; cmd:String): Integer;
var
 data:TNapCmd;
begin
 data.id:=id;
 data.cmd:=cmd;
 Result:=Add(data);
end;

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

function  TNapCmdList.Id(index: Integer): Integer;
var
 data:PNapCmd;
begin
 if (index>=0) and (index<count) then
 begin
  data:=PNapCmd(Items[index]);
  Result:=data^.id;
  exit;
 end;
 Result:=-1;
end;

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

function  TNapCmdList.FindByCmd(cmd: String; ignore_case: Boolean): Integer;
var
 i, len: Integer;
begin
 len:=Length(cmd);
 if ignore_case then
 begin
   cmd:=AnsiLowerCase(cmd);
   for i:=0 to count-1 do
    if Length(PNapCmd(Items[i])^.cmd)=len then
    if AnsiLowerCase(PNapCmd(Items[i])^.cmd)=cmd then
    begin
      Result:=i;
      exit;
    end;
   Result:=-1;
   exit;
 end;
 for i:=0 to count-1 do
  if Length(PNapCmd(Items[i])^.cmd)=len then
  if PNapCmd(Items[i]).cmd=cmd then
  begin
    Result:=i;
    exit;
  end;
 Result:=-1;
end;

function  TNapCmdList.FindById(id: Integer): Integer;
var
 i: Integer;
begin
 for i:=0 to count-1 do
  if PNapCmd(Items[i]).id=id then
  begin
    Result:=i;
    exit;
  end;
 Result:=-1;
end;

function  TNapCmdList.FindItem(id: Integer; cmd: String): Integer;
var
 i, len: Integer;
begin
 len:=Length(cmd);
 for i:=0 to count-1 do
  if PNapCmd(Items[i])^.id=id then
   if Length(PNapCmd(Items[i])^.cmd)=len then
   if PNapCmd(Items[i]).cmd=cmd then
   begin
     Result:=i;
     exit;
   end;
 Result:=-1;
end;

constructor TNapCmdList.Create;
begin
 inc(count_napcmdlist);
 if count_napcmdlist>count_napcmdlist_max then count_napcmdlist_max:=count_napcmdlist;
 inherited Create;
end;

destructor TNapCmdList.Destroy;
begin
 Clear;
 dec(count_napcmdlist);
 inherited Destroy;
end;

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

procedure TNapCmdList.SaveToFile(filename: String);
var
 list: TMyStringList;
 i: Integer;
begin
 list:=CreateStringList;
 for i:=0 to count-1 do
 begin
  list.Add(IntToStr(id(i))+' '+str(i));
  if (i mod 50)=0 then
  begin
   {$I checksync.pas}
  end;
 end;
 try
  list.SaveToFile(filename);
  except
 end;
 FreeStringList(list);
end;

procedure TNapCmdList.LoadFromFile(filename: String);
var
 list: TMyStringList;
 i,j: Integer;
 str: String;
begin
 list:=CreateStringList;
 Clear;
 try
  list.LoadFromFile(filename);
  except
 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]);
    AddCmd(j,str);
  end;
 end;
 FreeStringList(list);
end;

procedure TNapCmdList.Sort;
var
 c1,c2: PNapCmd;
 i,j: Integer;
begin
 for i:=1 to count-1 do
  for j:=0 to i-1 do
  begin
    c1:=Items[i];
    c2:=Items[j];
    if c1^.id>c2^.id then
    begin
      Items[i]:=c2;
      Items[j]:=c1;
    end
    else if c1^.id=c2^.id then
    if c1^.cmd>c2^.cmd then
    begin
      Items[i]:=c2;
      Items[j]:=c1;
    end;
  end;
end;

{$IFNDEF DISABLE_MEMORY_MANAGER}
procedure ClearCmdLists;
var
 i: Integer;
 p: PNapCmd;
begin
 for i:=0 to lists.count-1 do
  TNapCmdList(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}

initialization
begin
 count_napcmdlist:=0;
 count_napcmdlist_max:=0;
 count_napcmdlist_items:=0;
 count_napcmdlist_items_max:=0;
{$IFNDEF DISABLE_MEMORY_MANAGER}
 lists:=TMyList.Create;
 items:=TMyList.Create;
{$ENDIF}
end;

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