unit Receipt;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ExtCtrls, Grids;

type
  RcpZdvRec = record
    TagName: string;
    TagSostIdx: integer;
    Sost: integer;
    BadFlag: boolean;
    Rcp: array of integer;
  end;

  RcpDynRec = record
    TagName: string;
    TagSostIdx: integer;
    ZdvNum: integer;
    RcpNum: integer;
    Value: integer;
    Sost: integer;
    BadFlag: boolean;
  end;

type
  TReceiptForm = class(TForm)
    rgRcp: TRadioGroup;
    Panel: TPanel;
    OkButton: TBitBtn;
    CancelButton: TBitBtn;
    Grid: TStringGrid;
    Timer: TTimer;
    procedure CancelButtonClick(Sender: TObject);
    procedure GridDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure TimerTimer(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure OkButtonClick(Sender: TObject);
  private
    { Private declarations }
    ZdvList: array of RcpZdvRec;
    DynList: array of RcpDynRec;
    CurRcp, RcpNum, ZdvNum, DynNum: integer;
    SostList: TStringList;
    _RcpName: string;
  public
    procedure ShowReceipt(RcpName: string; var CurrentReceipt: integer);
    procedure LoadCurReceipt(RcpName: string; var CurrentReceipt: integer);
    procedure SaveCurReceipt(RcpName: string; CurrentReceipt: integer);
  end;

var
  ReceiptForm: TReceiptForm;

implementation
uses
  RpVisualGlobal,
  TagStorage,
  IniFiles,
  hyperstr;

{$R *.DFM}

procedure TReceiptForm.CancelButtonClick(Sender: TObject);
begin
  Close;
end;

//============================================================================
// Загрузка рецепта и вывод окна
//============================================================================
procedure TReceiptForm.ShowReceipt(RcpName: string; var CurrentReceipt: integer);

      function GetStr(var F: TextFile; mask: string; var s: string): boolean;
      begin
        result := false;
        while not(eof(F)) do begin
          Readln(F, s);
          if length(s) > length(mask) then
            if (s[length(mask)+1] in ['0'..'9']) and
                  (copy(trim(uppercase(s)),1,length(mask))=mask) then begin
              delete(s, 1, pos('=',s));
              s := trim(s);
              result := true;
              break;
            end;
        end;
      end;

var
  fname, s,ss: string;
  i,j,k,q, max_name_width: integer;
  F: TextFile;
begin
  _RcpName:=RcpName;
  
  LoadCurReceipt(RcpName, CurrentReceipt);
  fname := CurDir + 'Receipt\' + RcpName + '.rcp';
  if FileExists(fname) then begin

    AssignFile(F, fname);

    RcpNum := 0;
    ZdvNum := 0;
    DynNum := 0;

    // подсчет кол-ва элементов массивов
    reset(F);
    while GetStr(F,'RCP',s) do inc(RcpNum);
    reset(F);
    while GetStr(F,'ZDV',s) do inc(ZdvNum);
    reset(F);
    while GetStr(F,'DYN',s) do inc(DynNum);

    Grid.RowCount := ZdvNum + 1;
    Grid.ColCount := RcpNum + 2;
    Grid.Cells[0, 0] := 'Задвижки';
    Grid.Cells[1, 0] := 'Тек.сост';

    // чтение названий состояний
    reset(F);
    while (GetStr(F,'SOST',s)) do begin
      k := 1;
      ss := trim(Parse(s,';',k));
      s := trim(Parse(s,';',k));
      if not SostList.Find(ss, k) then SostList.Add(ss);
      SostList.Values[ss] := s;
    end;

    rgRcp.Items.Clear;
    reset(F);
    i:=0;
    while (GetStr(F,'RCP',s)) do begin
      rgRcp.Items.Add( IntToStr(i+1) + '. ' + s);
      Grid.Cells[i+2, 0] := 'Марш. ' + IntToStr(i+1);
      inc(i);
    end;

    SetLength(ZdvList, ZdvNum);
    reset(F);
    i:=0;
    max_name_width := 0;
    while (GetStr(F,'ZDV',s)) do begin

      k := 1;
      Grid.Cells[0, i+1] := trim(parse(s,';',k));
      Grid.Cells[1, i+1] := '-';

      Grid.Canvas.Font.Style := [fsBold];
      if Grid.Canvas.TextWidth( Grid.Cells[0, i+1] ) > max_name_width then
        max_name_width := Grid.Canvas.TextWidth( Grid.Cells[0, i+1] );

      ZdvList[i].TagName := trim(parse(s,';',k));
      ZdvList[i].TagSostIdx := GetTagIndex( ZdvList[i].TagName );

      SetLength(ZdvList[i].Rcp, RcpNum);
      for j:=0 to RcpNum-1 do begin
        val(parse(s,',',k), ZdvList[i].Rcp[j], q);
        Grid.Cells[j+2, i+1] := SostList.Values[inttostr(ZdvList[i].Rcp[j])];
      end;

      ZdvList[i].BadFlag := false;
      inc(i);
    end;

    // считывание динамических свойств
    SetLength(DynList, DynNum);
    reset(F);
    i:=0;
    while (GetStr(F,'DYN',s)) do begin
      k := 1;
      DynList[i].TagName := trim(parse(s,';',k));
      DynList[i].TagSostIdx := GetTagIndex( DynList[i].TagName );
      val( parse(s,';',k), DynList[i].ZdvNum, q);
      val( parse(s,';',k), DynList[i].RcpNum, q);
      val( parse(s,';',k), DynList[i].Value, q);
      val( parse(s,';',k), DynList[i].Sost, q);
      DynList[i].BadFlag := false;
      inc(i);
    end;


    if CurrentReceipt < rgRcp.Items.Count then
      rgRcp.ItemIndex := CurrentReceipt
    else
      rgRcp.ItemIndex := 0;

    // Уст ширину колонки названия
    max_name_width := max_name_width + 20;
    Grid.ColWidths[0] := max_name_width;

    rgRcp.Height := RcpNum * 28 + 5;
    Height := rgRcp.Height + Panel.Height + 30 + (ZdvNum+1) * 21;
    Width := (RcpNum + 1)*65 + max_name_width + 30;
    if Height + Top > Screen.Height then Height := Screen.Height - Top;

    Timer.Enabled := true;

    Show;
//    if ShowModal = mrOk then begin
//      CurrentReceipt := rgRcp.ItemIndex;
//      SaveCurReceipt(RcpName, CurrentReceipt);
//    end;
//    Timer.Enabled := false;

    CloseFile(F);
  end else
    MessageDlg('Не найден файл описания положений задвижек маршрута!', mtError, [mbOk], 0);
end;


//============================================================================
// Раскраска
//============================================================================
procedure TReceiptForm.GridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  x,y: integer;
  s: string;
begin
  Grid.Canvas.Brush.Color := Grid.FixedColor;
  if (ARow=0) then begin
    Grid.Canvas.Font.Style := [fsBold];
    if ACol = rgRcp.ItemIndex+2 then Grid.Canvas.Brush.Color := clLime;
  end else
  if (ACol=0) then begin
    Grid.Canvas.Font.Style := [fsBold];
  end else
  if (ACol=1) then begin
//    Grid.Canvas.Font.Style := [fsItalic];
  end else
  if ACol = rgRcp.ItemIndex+2 then begin
    if ZdvList[ARow-1].BadFlag then begin
      Grid.Canvas.Brush.Color := clRed;
//      Grid.Canvas.Font.Color := clWhite;
    end;
  end else begin
    Grid.Canvas.Font.Color := clDkGray;
  end;

  Grid.Canvas.FillRect(Rect);

  if not((ARow>0) and (ACol=0)) then begin
    x := (Rect.Right - Rect.Left - Grid.Canvas.TextWidth(Grid.Cells[ACol,ARow])) div 2;
    y := (Rect.Bottom - Rect.Top - Grid.Canvas.TextHeight(Grid.Cells[ACol,ARow])) div 2;
  end else begin
    x := 5;
    y := 0;
  end;
  Grid.Canvas.TextOut(Rect.Left+x, Rect.Top+y, Grid.Cells[ACol,ARow]);

  Grid.Canvas.Font.Color := clBlack;
  Grid.Canvas.Font.Style := [];
end;






//============================================================================
// Обновление
//============================================================================
procedure TReceiptForm.TimerTimer(Sender: TObject);
var
  i,j,v: integer;
  HasChanges, flag: boolean;
  s: string;
begin
  HasChanges := false;

  for i:=0 to DynNum-1 do if DynList[i].TagSostIdx >= 0 then
    if DynList[i].Value = GetTagValue( DynList[i].TagSostIdx ) then
      if DynList[i].ZdvNum < ZdvNum then
        if DynList[i].RcpNum < length(ZdvList[DynList[i].ZdvNum].Rcp) then
          if ZdvList[DynList[i].ZdvNum].Rcp[DynList[i].RcpNum] <> DynList[i].Sost then begin
            ZdvList[DynList[i].ZdvNum].Rcp[DynList[i].RcpNum] := DynList[i].Sost;
            HasChanges := true;
            s := SostList.Values[inttostr(DynList[i].Sost)];
            Grid.Cells[DynList[i].RcpNum+2, 1+DynList[i].ZdvNum] := s;
          end;


  for i:=0 to ZdvNum-1 do if ZdvList[i].TagSostIdx >= 0 then begin
    ZdvList[i].Sost := GetTagValue( ZdvList[i].TagSostIdx );

    flag := ZdvList[i].BadFlag;

    if ZdvList[i].Rcp[rgRcp.ItemIndex] = 3 then
      ZdvList[i].BadFlag := false
    else
      ZdvList[i].BadFlag := not (ZdvList[i].Sost = ZdvList[i].Rcp[rgRcp.ItemIndex]);

    HasChanges := HasChanges or (flag xor ZdvList[i].BadFlag);

    s := SostList.Values[inttostr(ZdvList[i].Sost)];

    if not( Grid.Cells[1, i+1] = s ) then Grid.Cells[1, i+1] := s;
  end;

  if HasChanges then Grid.Repaint;

end;

procedure TReceiptForm.FormActivate(Sender: TObject);
begin
  TimerTimer(nil);
  Grid.Repaint;
end;


//============================================================================
// Чтение номера текущего рецепта
//============================================================================
procedure TReceiptForm.LoadCurReceipt(RcpName: string;
  var CurrentReceipt: integer);
begin
  with TIniFile.Create(CurDir + RpVisualIniFile) do begin
    CurrentReceipt := ReadInteger('Receipt', 'Rcp_' + RcpName, 0);
    Free;
  end;
end;


//============================================================================
// Запись номера текущего рецепта
//============================================================================
procedure TReceiptForm.SaveCurReceipt(RcpName: string;
  CurrentReceipt: integer);
begin

  if not noIniSave then begin
  with TIniFile.Create(CurDir + RpVisualIniFile) do begin
    WriteInteger('Receipt', 'Rcp_' + RcpName, CurrentReceipt);
    Free;
  end;
  end;

end;


procedure TReceiptForm.FormCreate(Sender: TObject);
begin
  SostList := TStringList.Create;

  SostList.Add('0');
  SostList.Values['0'] := 'СРЕД';

  SostList.Add('1');
  SostList.Values['1'] := 'ЗАКР';

  SostList.Add('2');
  SostList.Values['2'] := 'ОТКР';

  SostList.Add('3');
  SostList.Values['3'] := 'X';
end;

procedure TReceiptForm.FormDestroy(Sender: TObject);
begin
  SostList.Free;
end;

procedure TReceiptForm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Release;
  ReceiptForm := nil;
end;

procedure TReceiptForm.OkButtonClick(Sender: TObject);
begin
  SaveCurReceipt(_RcpName, rgRcp.ItemIndex);
  Timer.Enabled := false;
  close;
end;

end.
