unit LStack;

interface

uses
  SysUtils, Windows, Forms, Classes, Contnrs;

function PushValues(Name: string; Value: Variant; NewValue: Variant): Variant; overload;
procedure PushValues(Form: TForm; Value: Variant); overload;
function PushValues(Form: TForm; Value: Variant; NewValue: Variant): Variant; overload;
procedure PushValues(DataModule: TDataModule; Value: Variant); overload;
function PushValues(DataModule: TDataModule; Value: Variant; NewValue: Variant): Variant; overload;

function PopValues(Name: string): Variant; overload;
function PopValues(Form: TForm): Variant; overload;
function PopValues(DataModule: TDataModule): Variant; overload;

implementation

var
  TL: TStringList;

function PushValues(Name: string; Value: Variant; NewValue: Variant): Variant; overload;
var
  tmp: PVariant;
  Idx: Integer;
  Stack: TStack;
begin
  Idx := TL.IndexOf(Name);
  if Idx = -1 then begin
    Idx := TL.Add(Name);
    Stack := TStack.Create;
    TL.Objects[Idx] := Stack;
  end;

  Stack := (TL.Objects[Idx] as TStack);

  New(tmp);
  tmp^ := Value;
  Stack.Push(tmp);
  Result := NewValue;
end;

procedure PushValues(Form: TForm; Value: Variant); overload;
begin
  PushValues(Form.Name, Value, Null);
end;

procedure PushValues(DataModule: TDataModule; Value: Variant); overload;
begin
  PushValues(DataModule.Name, Value, Null);
end;

function PushValues(Form: TForm; Value: Variant; NewValue: Variant): Variant; overload;
begin
  Result := PushValues(Form.Name, Value, NewValue);
end;

function PushValues(DataModule: TDataModule; Value: Variant; NewValue: Variant): Variant; overload;
begin
  Result := PushValues(DataModule.Name, Value, NewValue);
end;

function PopValues(Name: string): Variant; overload;
var
  tmp: PVariant;
  Idx: Integer;
  Stack: TStack;
begin
  Idx := TL.IndexOf(Name);
  if Idx = -1 then begin
    Result := Null;
    Exit;
  end;

  Stack := (TL.Objects[Idx] as TStack);

  if Stack.Count > 0 then begin
    tmp := Stack.Pop;
    Result := tmp^;
    Dispose(tmp);
  end
  else
    Result := Null;

  if Stack.Count = 0 then begin
    Stack.Free;
    TL.Delete(Idx);
  end;
end;

function PopValues(Form: TForm): Variant; overload;
begin
  Result := PopValues(Form.Name);
end;

function PopValues(DataModule: TDataModule): Variant; overload;
begin
  Result := PopValues(DataModule.Name);
end;

procedure Initialize;
begin
  TL := TStringList.Create;
end;

procedure Finalize;
var
  tmp: PVariant;
  Stack: TStack;
  TLIdx: Integer;
begin
  for TLIdx := 0 to TL.Count - 1 do begin
    Stack := (TL.Objects[TLIdx] as TStack);
    while Stack.Count > 0 do begin
      tmp := Stack.Pop;
      Dispose(tmp);
    end;
    Stack.Free;
  end;
  TL.Free;
end;

initialization
  Initialize;
finalization
  Finalize;
end.

