unit VisVespA;

interface

uses
{$ifdef VER150}
  DesignIntf, DesignEditors, DesignWindows, DsnConst,
{$else}
  DsgnIntf,
{$endif}
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, stdctrls, ScadaBase, VisMachine;


type
  TVisVespA = class(TCustomScadaObject)
  private
    FData: TStringList;

    FImagePic1: TPicName;
    FImagePic2: TPicName;
    FImagePic3: TPicName;
    FImagePic4: TPicName;

    procedure SetupData(Value: TStringList);
    procedure LoadSetupData;
    procedure SaveSetupData;
  protected
    FTagVspaEnable: integer;
    FTagVspaReg20: integer;
    FTagVspaReg21: integer;
    FTagVspaReg22: integer;
    FTagVspaReg23: integer;
    FTagVspaReg24: integer;
    FTagVspaAnswer: integer;
    FTagVspaErrorFlag: integer;

    FCurSost: integer;
    FCurMode: integer;
    FCurBlok: integer;

    procedure SetImageSost(Value: integer);
    procedure SetFrameMode(Value: integer);
    procedure SetFrameBlok(Value: integer);
    procedure SetDatColor(idx, value: integer);

    procedure Loaded; override;
  public
    TagName: TTagName;
    DeviceName: TDeviceName;
    ImagePic: TPicName;

    ImageObj: TImage;
    LabelObj: TLabel;
    FrameModeObj: TShape;
    FrameBlokObj: TShape;

    DatCount: integer;
    Datchik: array of PVisMachineDat;

    OpFreqMax: integer;

    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure Init; override;
    procedure Process; override;

    procedure FrameUpdate;
    procedure FreeDatchiks;

  published
    property Data: TStringList read FData write SetupData;
  end;

  TVisVespAEditor = class(TComponentEditor)
  private
  public
    procedure Edit; override;
  end;



procedure Register;

implementation
uses
  TagStorage,
  numbers,
  ExtDlgs,
  VisVespASetup,
  RpVisualGlobal,
  RpVisualLegacyPanels,
  RpVisualUtils,
  RpVisualMain;

procedure Register;
begin
  RegisterComponents('Scada', [TVisVespA]);
  RegisterComponentEditor(TVisVespA, TVisVespAEditor);
end;

{ TVisVespA }

constructor TVisVespA.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FEraseBackground := true;
  Width := 100;
  Height := 100;
  ShowHint := true;

  FData := TStringList.Create;

  Datchik := nil;
  DatCount := 0;

  // Создание изображения
  ImageObj := TImage.Create(Self);
  ImageObj.Parent := self;
  ImageObj.Stretch := true;
  ImageObj.Visible := true;

  // Создание рамки Mode
  FrameModeObj := TShape.Create(self);
  FrameModeObj.Parent := self;
  FrameModeObj.Visible := true;
  FrameModeObj.Brush.Style := bsClear;
  FrameModeObj.Pen.Color := clAqua;

  // Создание рамки Blok
  FrameBlokObj := TShape.Create(self);
  FrameBlokObj.Parent := self;
  FrameBlokObj.Visible := true;
  FrameBlokObj.Brush.Style := bsClear;
  FrameBlokObj.Pen.Color := clYellow;

  // Создание метки
  LabelObj := TLabel.Create(Self);
  LabelObj.Parent := self;
  LabelObj.Visible := true;
  LabelObj.Transparent := true;
  LabelObj.Font.Color := clWhite;
  LabelObj.Font.Size := 10;
  LabelObj.Font.Style := [fsBold];
  LabelObj.Font.Name := 'Tahoma';

  ImageObj.OnClick := OnDeviceClick;
  LabelObj.OnClick := OnDeviceClick;

  FTagVspaEnable := -1;
  FTagVspaReg20 := -1;
  FTagVspaReg21 := -1;
  FTagVspaReg22 := -1;
  FTagVspaReg23 := -1;
  FTagVspaReg24 := -1;
  FTagVspaAnswer := -1;
  FTagVspaErrorFlag := -1;

  FCurSost := -1;
  FCurMode := -1;
  FCurBlok := -1;
end;

destructor TVisVespA.Destroy;
begin
  FreeDatchiks;
  inherited;
end;

procedure TVisVespA.SetupData(Value: TStringList);
begin
  FData.Assign(Value);
  LoadSetupData;
end;


procedure TVisVespA.SetImageSost(Value: integer);
begin
  if (Value <> FCurSost) and (Value>=0) then try
    case value of
      0:   ImageObj.Picture.LoadFromFile(VisImagesPath + FImagePic1);
      1:   ImageObj.Picture.LoadFromFile(VisImagesPath + FImagePic2);
      2:   ImageObj.Picture.LoadFromFile(VisImagesPath + FImagePic3);
    else
      ImageObj.Picture.LoadFromFile(VisImagesPath + FImagePic4);
    end;
    FCurSost := Value;
  except
    LabelObj.Caption := 'PIC';
  end;
end;

procedure TVisVespA.SetFrameMode(Value: integer);
begin
  if (Value <> FCurMode) then begin
    if (value) > 0 then
      FrameModeObj.Pen.Color := clAqua
    else
      FrameModeObj.Pen.Color := Color;
    FCurMode := Value;
  end;
end;

procedure TVisVespA.SetFrameBlok(Value: integer);
begin
  if (Value <> FCurBlok) then begin
    if (value) > 0 then
      FrameBlokObj.Pen.Color := clYellow
    else
      FrameBlokObj.Pen.Color := Color;
    FCurBlok := Value;
  end;
end;

procedure TVisVespA.SetDatColor(idx, value: integer);
begin
  if (value <> Datchik[idx].valSost) or (value>0) then begin

    if Datchik[idx].ColorScheme = 0 then begin
      case value of
      0: Datchik[idx].Shape.Brush.Color := clAqua;

      1: Datchik[idx].Shape.Brush.Color := clYellow;

      2: Datchik[idx].Shape.Brush.Color := clRed;

      3: if Datchik[idx].Shape.Brush.Color = clRed then
           Datchik[idx].Shape.Brush.Color := clYellow
         else
           Datchik[idx].Shape.Brush.Color := clRed;
      end;
    end;

    if Datchik[idx].ColorScheme = 1 then begin
      if value = 0 then
        Datchik[idx].Shape.Brush.Color := clAqua
      else
        Datchik[idx].Shape.Brush.Color := clYellow;
    end;

    Datchik[idx].valSost := value;
  end;

end;


// INIT
procedure TVisVespA.Init;
var
  i: integer;
  _tagname: string;
begin
  inherited;
  _tagname := repl(TagName, TagIdRoot, TagRoot);

  FTagVspaEnable := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_Enable');
  FTagVspaReg20 := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_Reg20');
  FTagVspaReg21 := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_Reg21');
  FTagVspaReg22 := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_Reg22');
  FTagVspaReg23 := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_Reg23');
  FTagVspaReg24 := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_Reg24');
  FTagVspaAnswer := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_Answer');
  FTagVspaErrorFlag := GetTagIndex(TagPath + '.VSPA_' + _TagName + '_ErrorFlag');

  IsConnectionBad := (FTagVspaEnable<0) or (FTagVspaReg20<0) or
      (FTagVspaReg21<0) or (FTagVspaReg22<0) or
      (FTagVspaReg23<0) or (FTagVspaReg24<0) or
      (FTagVspaAnswer<0) or (FTagVspaErrorFlag<0);

  for i:=0 to DatCount-1 do with Datchik[i]^ do begin
    TagIdxOutput := GetTagIndex(format('%s.RKSV_%s%s_Output',
        [TagPath, _TagName, TagPostfix]));

    TagIdxAlarm := GetTagIndex(format('%s.RKSV_%s%s_Alarm',
        [TagPath, _TagName, TagPostfix]));

    TagIdxBlok := GetTagIndex(format('%s.RKSV_%s%s_Blok',
        [TagPath, _TagName, TagPostfix]));

    IsConnectionBad := (IsConnectionBad) or (TagIdxOutput<0) or
        (TagIdxAlarm<0) or (TagIdxBlok<0);
  end;

end;

// PROCESS HANDLER
procedure TVisVespA.Process;
var
  value, venab, vreg20, vreg21, vreg22, vreg23, vreg24, verr, vansw, valOutput,
  valAalarm, blokval, i: integer;
begin

  IsValueBad := false;

  venab := GetTagValue(FTagVspaEnable);
  vreg20 := GetTagValue(FTagVspaReg20);
  vreg21 := GetTagValue(FTagVspaReg21);
  vreg22 := GetTagValue(FTagVspaReg22);
  vreg23 := GetTagValue(FTagVspaReg23);
  vreg24 := GetTagValue(FTagVspaReg24);
  vansw := GetTagValue(FTagVspaAnswer);
  verr := GetTagValue(FTagVspaErrorFlag);


  IsValueBad := IsValueBad or (venab < 0) or (vreg20 < 0) or (vreg21 < 0)
      or (vreg22 < 0) or (vreg23 < 0) or (vreg24 < 0) or (vansw < 0)
      or (verr < 0);

  value := 0;
  if (vreg20 and 1) > 0 then value := 1;
  if (value=1) and (vreg23 <> vreg24) then value:=3;
  if ((vreg20 and $FF08)>0) or (vreg21>0) or (vreg22>0) or (verr>0)
      or (vansw>0) then value:=2;
  SetImageSost(value);

  SetFrameMode( (venab and 2) );

  blokval := 0;
  for i:=0 to DatCount-1 do begin
    valOutput := GetTagValue(Datchik[i].TagIdxOutput);
    valAalarm := GetTagValue(Datchik[i].TagIdxAlarm);
    value := GetTagValue(Datchik[i].TagIdxBlok);
    IsValueBad := IsValueBad or (valOutput < 0) or (valAalarm < 0) or (value < 0);
    blokval := blokval or value;

    SetDatColor(i, valOutput * 2 + valAalarm);
  end;
  SetFrameBlok(blokval);

  inherited;

end;



procedure TVisVespA.LoadSetupData;
var
  s, s1, s2: string;
  k, i, j, v: integer;
begin

  // TagPath
  if FData.Count>0 then s := FData.Strings[0] else s := '';
  k := pos('.', s);
  TagPath := copy(s, 1, k-1);

  // TagName
  delete(s, 1, k); k := pos(';', s);
  TagName := copy(s, 1, k-1);

  // DeviceName
  delete(s, 1, k);
  DeviceName := trim(s);
  Hint := DeviceName;


  // Image
  if FData.Count>1 then s := FData.Strings[1] else s := '';
  k := pos(',', s);
  val(copy(s, 1, k-1), v, j);
  ImageObj.Left := v;

  delete(s, 1, k); k := pos(',', s);
  val(copy(s, 1, k-1), v, j);
  ImageObj.Top := v;

  delete(s, 1, k); k := pos(',', s);
  val(copy(s, 1, k-1), v, j);
  ImageObj.Width := v;

  delete(s, 1, k); k := pos(',', s);
  val(copy(s, 1, k-1), v, j);
  ImageObj.Height := v;

  delete(s, 1, k);
  ImagePic := trim(s);

  s := VisImagesPath + ImagePic;
  try
    if FileExists(s) then ImageObj.Picture.LoadFromFile(s);
  except
  end;


  // Label
  if FData.Count>2 then s := FData.Strings[2] else s := '';
  k := pos(',', s);
  val(copy(s, 1, k-1), v, j);
  LabelObj.Left := v;

  delete(s, 1, k); k := pos(',', s);
  val(copy(s, 1, k-1), v, j);
  LabelObj.Top := v;

  delete(s, 1, k);
  LabelObj.Caption := trim(s);

  // Обновление рамок
  FrameUpdate;

  // Загрузка датчиков
  FreeDatchiks;
  if FData.Count>3 then s := FData.Strings[3] else s := '';
  k := pos(',', s);
  val(copy(s, 1, k-1), v, j);
  DatCount := v;
  SetLength(Datchik, DatCount);

  delete(s, 1, k);
  val(s, v, j);
  OpFreqMax := v;

  for i:=0 to DatCount-1 do begin
    new( Datchik[i] );
    Datchik[i].Shape := TShape.Create(Self);
    Datchik[i].Shape.Parent := self;
    Datchik[i].Shape.Visible := true;
    Datchik[i].Shape.Brush.Color := clAqua;
    Datchik[i].Shape.OnMouseUp := OnDeviceMouseUp;

    if FData.Count>4+i then s := FData.Strings[4+i] else s := '';
    k := pos(',', s);
    val(copy(s, 1, k-1), v, j);
    Datchik[i].Shape.Left := v;

    delete(s, 1, k); k := pos(',', s);
    val(copy(s, 1, k-1), v, j);
    Datchik[i].Shape.Top := v;

    delete(s, 1, k); k := pos(',', s);
    val(copy(s, 1, k-1), v, j);
    Datchik[i].Shape.Width := v;

    delete(s, 1, k); k := pos(',', s);
    val(copy(s, 1, k-1), v, j);
    Datchik[i].Shape.Height := v;

    delete(s, 1, k); k := pos(',', s);
    val(copy(s, 1, k-1), v, j);
    Datchik[i].Shape.Shape := TShapeType(v);

    delete(s, 1, k); k := pos(',', s);
    val(copy(s, 1, k-1), v, j);
    Datchik[i].ColorScheme := v;

    delete(s, 1, k); k := pos(',', s);
    Datchik[i].TagPostfix := copy(s, 1, k-1);

    delete(s, 1, k);
    Datchik[i].Name := trim(s);

    Datchik[i].TagIdxOutput := -1;
    Datchik[i].TagIdxAlarm := -1;
    Datchik[i].TagIdxBlok := -1;

    Datchik[i].valSost := -1;

  end;

  // имена картинок
  s2 := ImagePic;
  i := pos('_',s2);
  s1 := copy(s2, 1, i);
  delete(s2, 1, i+1);

  FImagePic1 := s1 + '1' + s2;
  FImagePic2 := s1 + '2' + s2;
  FImagePic3 := s1 + '3' + s2;
  FImagePic4 := s1 + '4' + s2;

end;

procedure TVisVespA.SaveSetupData;
var
  i: integer;
//  s: string;
begin
  FData.Clear;
  FData.Add( TagPath + '.' + TagName + ';' + DeviceName );
  FData.Add( format('%d,%d,%d,%d,%s', [
      ImageObj.Left, ImageObj.Top, ImageObj.Width, ImageObj.Height, ImagePic]) );
  FData.Add( format('%d,%d,%s', [LabelObj.Left, LabelObj.Top, LabelObj.Caption]) );

  FData.Add(IntToStr(DatCount) + ',' + IntToStr(OpFreqMax));
  for i:=0 to DatCount-1 do
    FData.Add( format('%d,%d,%d,%d,%d,%d,%s,%s', [
        Datchik[i].Shape.Left, Datchik[i].Shape.Top,
        Datchik[i].Shape.Width, Datchik[i].Shape.Height,
        ord(Datchik[i].Shape.Shape), Datchik[i].ColorScheme,
        Datchik[i].TagPostfix, Datchik[i].Name
        ]));

end;


procedure TVisVespA.Loaded;
begin
  inherited;
  LoadSetupData;
end;


procedure TVisVespA.FrameUpdate;
begin
  FrameModeObj.Left   := LabelObj.Left   - ModeMarginX;
  FrameModeObj.Top    := LabelObj.Top    - ModeMarginY;
  FrameModeObj.Width  := LabelObj.Width  + 2*ModeMarginX;
  FrameModeObj.Height := LabelObj.Height + 2*ModeMarginY;

  FrameBlokObj.Left   := LabelObj.Left   - BlokMarginX;
  FrameBlokObj.Top    := LabelObj.Top    - BlokMarginY;
  FrameBlokObj.Width  := LabelObj.Width  + 2*BlokMarginX;
  FrameBlokObj.Height := LabelObj.Height + 2*BlokMarginY;
end;

procedure TVisVespA.FreeDatchiks;
var
  i: integer;
begin
  for i:=0 to DatCount-1 do begin
    Datchik[i].Shape.Free;
    Dispose(Datchik[i]);
  end;
  Datchik := nil;
end;



{ TVisVespAEditor }

procedure TVisVespAEditor.Edit;
begin
  inherited;

  VisVespASetupForm := TVisVespASetupForm.Create(nil);

  VisVespASetupForm.M := Component as TVisVespA;
  VisVespASetupForm.D := Self;
  if VisVespASetupForm.ShowModal = mrOk then
    VisVespASetupForm.M.SaveSetupData
  else
    VisVespASetupForm.M.LoadSetupData;

  VisVespASetupForm.Free;

end;


end.
