/// unit zaoberajuci sa zobrazovanim tabulky stavov pre DFA automat
unit DFAtable;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ExtCtrls, StdCtrls, Grids, main, hashmap,constants;

type
  /// trieda zobrazujuca tabulku stavov DFA automatu
  TDFATableForm = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;
    StatusBar1: TStatusBar;
    ScrollBar1: TScrollBar;
    StringGrid1: TStringGrid;
    procedure StringGrid1DblClick(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure ScrollBar1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    lastcol1: Integer;
    procedure showState(state: Integer);
    procedure fill(state: Integer; T: TStrIntHashMap; D: TDFA);
    { Private declarations }
  public
    procedure newlexer(D: TDFA);
    { Public declarations }
  end;

var
  DFATableForm: TDFATableForm;

implementation

{$R *.dfm}

uses grammaredit, langres, folderdiff, mainframe, tableframe;

/// procedura, ktora vytvori okno zobrazujuce tabulku stavov DFA automatu
procedure TDFATableForm.FormCreate(Sender: TObject);
begin
  DoubleBuffered := true;
  StringGrid1.Enabled := false;
  StringGrid1.Tag := -1;
  lastcol1 := -1;
end;

/// procedura, ktora naplni tabulku prechodov DFA automatu (pre vstupny stav state a vstupne mena tokenov T a vstupny automat D)
procedure TDFATableForm.fill(state: Integer; T: TStrIntHashMap; D: TDFA);
var I: Integer;
    symbol,J: Integer;
    k: Integer;
    S: xString;
    pos: Integer;
begin
  if (state > Pred(D.getSize)) or (state < 0) then begin
    Exit;
  end;

  k := 1 + D.a[state].moves.getSize;
  if D.a[state].accepts > 0 then
    k := k + 1;

  with StringGrid1 do begin
    cells[0,0] := GetLangString(STR_SYMBOL);
    cells[1,0] := GetLangString(STR_STATE);
    I := 1;
    with D do begin
        if k > 1 then
          StringGrid1.RowCount := k;
        a[state].moves.getnextreset;
        while a[state].moves.getNext(symbol,J) do begin
          if symbol >= 32 then
            cells[0,I] := char(symbol)
          else
            cells[0,I] := '''\' + IntToStr(symbol) + '''';
          cells[1,I] := IntToStr(J);
          I := I + 1;
        end;
        if a[state].accepts > 0 then begin
          cells[0,I] := getlangstring(STR_ACCEPT);
          if not T.getByValue(a[state].accepts,S,pos) then
            S := '?' + IntToStr(a[state].accepts) + '?';
          cells[1,I] := S;
          I := I + 1;
        end;
    end;
  end;

  //sort

  if lastcol1 <> -1 then begin
    i := lastcol1 shr 1;
    if lastcol1 mod 2 = 0 then
      StringGrid1.Tag := -1
    else
      StringGrid1.Tag := lastcol1 shr 1;
    if (i = 1) then begin
      GridSort(StringGrid1,i,1,StringGrid1.RowCount-1,celltypeInteger);
    end
    else begin
      GridSort(StringGrid1,i,1,StringGrid1.RowCount-1,celltypeString);
    end;
    if lastcol1 mod 2 = 0 then
      StringGrid1.Tag := lastcol1 shr 1
    else
      StringGrid1.Tag := -1;
  end;

  Panel1.Caption := '[DFA State: ' + IntToStr(state) + '/' + IntToStr(Pred(D.getSize)) + ']';
  StatusBar1.Panels[0].Text := 'Number Of States: ' + IntToStr(D.getSize);
end;

/// procedura, ktora vytvori okno zobrazujuce tabulku prechodov DFA automatu (pre dany konkretny stav state)
procedure TDFATableForm.showState(state: Integer);
begin
  if GrammarEditForm.FDFA <> nil then begin
    StringGrid1.Enabled := true;
    fill(state,GrammarEditForm.FGFL.getTokenNameTypeTable,GrammarEditForm.FDFA);
  end
  else begin
    StringGrid1.Enabled := false;
    ScrollBar1.Min := 0;
    ScrollBar1.Max := 0;
    StringGrid1.Tag := -1;
    lastcol1 := -1;
    Panel1.Caption := '';
    StatusBar1.Panels[0].Text := '';
  end;
end;

/// procedura na obsluhu posunu scrollbaru, pri zmene sa zmeni zobrazovany stav na momentalnu poziciu scrollbaru
procedure TDFATableForm.ScrollBar1Change(Sender: TObject);
begin
  showState(ScrollBar1.Position);
end;

/// procedura, ktora automaticky meni velkost stlpcov pri zmene velkosti okna
procedure TDFATableForm.FormResize(Sender: TObject);
var i: Integer;
begin
  for i := 0 to Pred(StringGrid1.ColCount) do
    StringGrid1.ColWidths[i] := StringGrid1.ClientWidth div StringGrid1.ColCount - 1;
end;

/// procedura na reinicializaciu tabulky stavov DFA automatu
procedure TDFATableForm.newlexer(D: TDFA);
begin
  if GrammarEditForm.FDFA <> nil then begin
    ScrollBar1.Min := 0;
    ScrollBar1.Max := Pred(GrammarEditForm.FDFA.getSize);
    showState(0);
  end;
end;

/// procedura na obsluhu dvojkliku vo vnutri tabulky
procedure TDFATableForm.StringGrid1DblClick(Sender: TObject);
var SG,SG2: TStringGrid;
    S: xString;
    s2: xString;
    sname,s2name: xString;
    mpos: TPoint;
    i,X,Y: Integer;
    ACol,ARow: Integer;
    TGR: TGridRect;
begin
  if GrammarEditForm.FDFA = nil then begin
    showState(0);
    Exit;
  end;

  SG := StringGrid1;

  mpos := Mouse.CursorPos;
  X := SG.ScreenToClient(mpos).X;
  Y := SG.ScreenToClient(mpos).Y;
  SG.MouseToCell(X, Y, ACol, ARow);

  if ARow = 0 then begin
    if (ACol = 1) then begin
      GridSort(SG,ACol,1,SG.RowCount-1,celltypeInteger);
    end
    else begin
      GridSort(SG,ACol,1,SG.RowCount-1,celltypeString);
    end;
    if SG.Tag <> -1 then
      lastcol1 := ACol shl 1
    else
      lastcol1 := ACol shl 1 + 1;
    Exit;
  end
  else if (ARow > 0) and (ARow < SG.RowCount) then begin
    S := StringGrid1.Cells[0,StringGrid1.Row];
    if S = getlangstring(STR_ACCEPT) then begin
      S := StringGrid1.Cells[1,StringGrid1.Row];
      for i := 0 to Pred(TokenTableForm.StringGrid1.RowCount) do begin
        if TokenTableForm.StringGrid1.Cells[1,i] = S then begin
          TokenTableForm.StringGrid1.Row := i;
          MainForm.ShowTokenTableTBClick(Sender);
          break;
        end;
      end;
    end
    else begin
      i := StrToIntDef(StringGrid1.Cells[1,ARow],-1);
      if (i >= ScrollBar1.Min) and (i <= ScrollBar1.Max) then
        ScrollBar1.Position := i;
    end;
  end;
end;

end.
