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

 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_CmdExList

 TNapCmdEx and TNapCmdExList Declarations

*********************************************************}
unit Class_CmdExList;

interface

uses
  Windows, Classes2, SysUtils;

type
  TNapCmdEx = record
    Id: Integer;
    Cmd: string;
    Data: string;
  end;
  PNapCmdEx = ^TNapCmdEx;
  TNapCmdExList = class(TMyList)
    function Add(Value: TNapCmdEx): Integer;
    procedure Insert(Index: Integer; Value: TNapCmdEx);
    procedure Clear; override;
    procedure Delete(Index: Integer);
    procedure AddCmd(Id: Integer; Cmd: string; Data: string);
    function CmdEx(Index: Integer): TNapCmdEx;
    function FindByCmd(Cmd: string): Integer;
    constructor Create;
    destructor Destroy; override;
  end;

function CreateCmdExList: TNapCmdExList;
procedure FreeCmdExList(List: TNapCmdExList);
{$IFNDEF DISABLE_MEMORY_MANAGER}
procedure ExpireCmdExLists;
{$ENDIF}

var
  Count_NapCmdExList,
    Count_NapCmdExList_Max: Integer;
  Count_NapCmdExList_Items,
    Count_NapCmdExList_Items_Max: Integer;

implementation

uses Vars, Thread, STypes, Memory_Manager;

{$IFNDEF DISABLE_MEMORY_MANAGER}
var
  Lists, Items: TMyList;
{$ENDIF}

function CreateCmdExList: TNapCmdExList;
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 := TNapCmdExList.Create;
end;

procedure FreeCmdExList(List: TNapCmdExList);
begin
  List.Clear;
{$IFDEF DISABLE_MEMORY_MANAGER}
  List.Free;
{$ELSE}
  Lists.Add(List);
{$ENDIF}
end;

function CreateItem: PNapCmdEx;
var
  Data: PNapCmdEx;
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(TNapCmdEx));
    Pointer(Data^.Cmd) := nil;
    Pointer(Data^.Data) := nil;
    Inc(Count_NapCmdExList_Items);
    if Count_NapCmdExList_Items > Count_NapCmdExList_Items_Max then
      Count_NapCmdExList_Items_Max := Count_NapCmdExList_Items;
{$IFNDEF DISABLE_MEMORY_MANAGER}
  end;
{$ENDIF}
  Result := Data;
end;

procedure FreeItem(Item: PNapCmdEx);
begin
  if Pointer(Item^.Data) <> nil then
    SetLength(Item^.Data, 0);
  if Pointer(Item^.Cmd) <> nil then
    SetLength(Item^.Cmd, 0);
  Finalize(Item^);
  FreeMem(Item, SizeOf(TNapCmdEx));
  Dec(Count_NapCmdExList_Items);
end;

procedure DeleteItem(Item: PNapCmdEx);
begin
{$IFDEF DISABLE_MEMORY_MANAGER}
  FreeItem(Item);
{$ELSE}
  if Pointer(Item^.Data) <> nil then
    SetLength(Item^.Data, 0);
  if Pointer(Item^.Cmd) <> nil then
    SetLength(Item^.Cmd, 0);
  Items.Add(Item);
{$ENDIF}
end;

{$IFNDEF DISABLE_MEMORY_MANAGER}

procedure ExpireCmdExLists;
var
  List: TNapCmdExList;
  Item: PNapCmdEx;
begin
  if Lists.Count > 1000 then
    while (Lists.Count * 3) > Count_NapCmdExList 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_NapCmdExList_Items do
    try
      Item := Items.Items[Items.Count - 1];
      Items.Delete(Items.Count - 1);
      FreeItem(Item);
    except
    end;
end;
{$ENDIF}

{* * * * *  TNapCmdExList  * * * * *}

function TNapCmdExList.Add(Value: TNapCmdEx): Integer;
var
  Item: PNapCmdEx;
begin
  Item := CreateItem;
  with Item^ do
  begin
    Cmd := Value.Cmd;
    Data := Value.Data;
    Id := Value.Id;
  end;
  Result := inherited Add(Item);
end;

procedure TNapCmdExList.Insert(Index: Integer; Value: TNapCmdEx);
var
  Item: PNapCmdEx;
begin
  Item := CreateItem;
  with Item^ do
  begin
    Cmd := Value.Cmd;
    Data := Value.Data;
    Id := Value.Id;
  end;
  inherited Insert(Index, Item);
end;

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

procedure TNapCmdExList.Delete(Index: Integer);
begin
  if (Index < 0) or (Index >= Count) then Exit;
  if Items[Index] <> nil then
    DeleteItem(Items[Index]);
  inherited Delete(Index);
end;

procedure TNapCmdExList.AddCmd(Id: Integer; Cmd: string; Data: string);
var
  Item: TNapCmdEx;
begin
  Item.Id := Id;
  Item.Cmd := Cmd;
  Item.Data := Data;
  Add(Item);
end;

function TNapCmdExList.CmdEx(Index: Integer): TNapCmdEx;
var
  Data: TNapCmdEx;
begin
  if (Index >= 0) and (Index < Count) then
  begin
    Data := TNapCmdEx(Items[Index]^);
    Result := Data;
    Exit;
  end;
  Data.Id := -1;
  Data.Cmd := '';
  Data.Data := '';
  Result := Data;
end;

function TNapCmdExList.FindByCmd(Cmd: string): Integer;
var
  I: Integer;
  P: PNapCmdEx;
begin
  for I := 0 to Count - 1 do
  begin
    P := Items[I];
    if P^.Cmd = Cmd then
    begin
      Result := I;
      Exit;
    end;
  end;
  Result := -1;
end;

constructor TNapCmdExList.Create;
begin
  Inc(Count_NapCmdExList);
  if Count_NapCmdExList > Count_NapCmdExList_Max then
    Count_NapCmdExList_Max := Count_NapCmdExList;
  inherited Create;
end;

destructor TNapCmdExList.Destroy;
begin
  Clear;
  Dec(Count_NapCmdExList);
  inherited Destroy;
end;

{$IFNDEF DISABLE_MEMORY_MANAGER}

procedure ClearCmdExLists;
var
  I: Integer;
  P: PNapCmdEx;
begin
  for I := 0 to Lists.Count - 1 do
    TNapCmdExList(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_NapCmdExList := 0;
    Count_NapCmdExList_Max := 0;
    Count_NapCmdExList_Items := 0;
    Count_NapCmdExList_Items_Max := 0;
{$IFNDEF DISABLE_MEMORY_MANAGER}
    Lists := TMyList.Create;
    Items := TMyList.Create;
{$ENDIF}
  end;

{$IFNDEF DISABLE_MEMORY_MANAGER}
finalization
  begin
    ClearCmdExLists;
    Lists.Free;
    Items.Free;
  end;
{$ENDIF}
end.
