unit VisSeqcConfig;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, FIBDataSet, pFIBDataSet, FIBDatabase, pFIBDatabase, Grids,
  DBGridEh, Buttons, ExtCtrls, ToolWin, ActnMan, ActnCtrls, ActnList,
  XPStyleActnCtrls, StdCtrls, VisSeqc, GridsEh, ComCtrls, FIBQuery,
  pFIBQuery, DBCtrls, ImgList, DBCtrlsEh, Mask ;

{ TODO : Запрет установки, редактирования, удаления уже установленного в другой ячейке маршрура }
{ TODO : Получение списка установленных машин }
{ TODO : Проверка и предупреждение перед запуском на используемые машины в других запущенных маршрутов }
{ TODO : Логирование действий оператора }

type
  TVisSeqcConfigForm = class(TForm)
    db1: TpFIBDatabase;
    trn1: TpFIBTransaction;
    trn2: TpFIBTransaction;
    trn3: TpFIBTransaction;
    dsM: TpFIBDataSet;
    trn4: TpFIBTransaction;
    pFIBTransaction1: TpFIBTransaction;
    ds2: TpFIBDataSet;
    pFIBTransaction2: TpFIBTransaction;
    Panel1: TPanel;
    Panel2: TPanel;
    Splitter1: TSplitter;
    dsrcM: TDataSource;
    dsrcD: TDataSource;
    dsD: TpFIBDataSet;
    pFIBTransaction3: TpFIBTransaction;
    pFIBTransaction4: TpFIBTransaction;
    dsMID: TFIBIntegerField;
    dsMNAME: TFIBstringField;
    dsMDESCR: TFIBstringField;
    dsDROOT_ID: TFIBIntegerField;
    dsDDEVICE_ID: TFIBIntegerField;
    dsDTIMESTART: TFIBIntegerField;
    dsDTIMESTOP: TFIBIntegerField;
    dsDORDERNUM: TFIBIntegerField;
    dsDDNAME: TStringField;
    Panel3: TPanel;
    grid2: TDBGridEh;
    Panel4: TPanel;
    grid1: TDBGridEh;
    ActionManager1: TActionManager;
    acAdd1: TAction;
    acDel1: TAction;
    acPost1: TAction;
    acRefresh1: TAction;
    ActionToolBar1: TActionToolBar;
    ActionToolBar2: TActionToolBar;
    acAdd2: TAction;
    acDel2: TAction;
    acPost2: TAction;
    Button2: TButton;
    acUp: TAction;
    acDown: TAction;
    dsDID: TFIBIntegerField;
    dsMCODE: TFIBIntegerField;
    ds2ID: TFIBIntegerField;
    ds2ADDR: TFIBIntegerField;
    ds2DEVTYPE: TFIBstringField;
    ds2NAME: TFIBstringField;
    ds2TAGNAME: TFIBstringField;
    ds2DATA: TMemoField;
    dsDADDR: TStringField;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    Splitter2: TSplitter;
    Panel5: TPanel;
    gridCurM: TDBGridEh;
    ActionToolBar3: TActionToolBar;
    Panel6: TPanel;
    gridCurD: TDBGridEh;
    ActionToolBar4: TActionToolBar;
    pFIBQuery1: TpFIBQuery;
    pFIBTransaction5: TpFIBTransaction;
    pFIBTransaction6: TpFIBTransaction;
    dsCurM: TpFIBDataSet;
    dsrcCurM: TDataSource;
    pFIBTransaction7: TpFIBTransaction;
    pFIBTransaction8: TpFIBTransaction;
    dsCurD: TpFIBDataSet;
    dsrcCurD: TDataSource;
    Panel7: TPanel;
    Splitter3: TSplitter;
    acCurAdd: TAction;
    acCurDel: TAction;
    acCurSet: TAction;
    acCurRefresh: TAction;
    dsMROOTBEGIN: TFIBIntegerField;
    dsMROOTEND: TFIBIntegerField;
    acCurEdit: TAction;
    dsCurMID: TFIBIntegerField;
    dsCurMNAME: TFIBstringField;
    dsCurMDESCR: TFIBstringField;
    dsCurMCODE: TFIBIntegerField;
    dsCurDNAME: TFIBstringField;
    dsCurDORDERNUM: TFIBIntegerField;
    dsCurMSUBROOT: TFIBIntegerField;
    pFIBTransaction9: TpFIBTransaction;
    pFIBTransaction10: TpFIBTransaction;
    dsSubrootsM: TpFIBDataSet;
    dsSubrootsMID: TFIBIntegerField;
    dsSubrootsMROOT_ID: TFIBIntegerField;
    dsSubrootsMSUBROOT_ID: TFIBIntegerField;
    dsSubrootsMNAME: TFIBstringField;
    gridSubrootsM: TDBGridEh;
    dsrcSubrootsM: TDataSource;
    dsCurDADDR: TFIBIntegerField;
    dsCurDTIMESTART: TFIBIntegerField;
    dsCurDTIMESTOP: TFIBIntegerField;
    ImageList1: TImageList;
    acCheck: TAction;
    acReset: TAction;
    btHandEdit: TSpeedButton;
    pnlHand: TPanel;
    gridHand: TDBGridEh;
    ActionToolBar5: TActionToolBar;
    acHandAdd: TAction;
    acHandDel: TAction;
    acHandUp: TAction;
    acHandDown: TAction;
    acHandPost: TAction;
    pFIBTransaction11: TpFIBTransaction;
    pFIBTransaction12: TpFIBTransaction;
    dsHand: TpFIBDataSet;
    dsrcHand: TDataSource;
    dsHandID: TFIBIntegerField;
    dsHandROOT_ID: TFIBIntegerField;
    dsHandDEVICE_ID: TFIBIntegerField;
    dsHandTIMESTART: TFIBIntegerField;
    dsHandTIMESTOP: TFIBIntegerField;
    dsHandORDERNUM: TFIBIntegerField;
    dsHandDNAME: TStringField;
    Panel8: TPanel;
    dsHandMODEFLAGS: TStringField;
    dsHandFL_ARMO: TFIBSmallIntField;
    dsHandFL_TRANSPARENT: TFIBSmallIntField;
    dsHandFL_CTRLPROD: TFIBSmallIntField;
    dsHandFL_PROD: TFIBSmallIntField;
    dsHandDLY_PRODSTOP: TFIBSmallIntField;
    dsDFL_ARMO: TFIBSmallIntField;
    dsDFL_TRANSPARENT: TFIBSmallIntField;
    dsDFL_CTRLPROD: TFIBSmallIntField;
    dsDFL_PROD: TFIBSmallIntField;
    dsDDLY_PRODSTOP: TFIBSmallIntField;
    dsDMODEFLAGS: TStringField;
    DBCheckBoxEh1: TDBCheckBoxEh;
    Label1: TLabel;
    DBCheckBoxEh3: TDBCheckBoxEh;
    Label3: TLabel;
    DBCheckBoxEh4: TDBCheckBoxEh;
    Label4: TLabel;
    DBComboBoxEh1: TDBComboBoxEh;
    Label5: TLabel;
    DBNumberEditEh1: TDBNumberEditEh;
    Label2: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    cbHandARMO: TDBCheckBoxEh;
    cbHandCTRLPROD: TDBCheckBoxEh;
    cbHandPROD: TDBCheckBoxEh;
    cmbHandTRANSPARENT: TDBComboBoxEh;
    edHandDLY_PRODSTOP: TDBNumberEditEh;
    dsCurDFL_ARMO: TFIBSmallIntField;
    dsCurDFL_TRANSPARENT: TFIBSmallIntField;
    dsCurDFL_CTRLPROD: TFIBSmallIntField;
    dsCurDFL_PROD: TFIBSmallIntField;
    dsCurDDLY_PRODSTOP: TFIBSmallIntField;
    cbHandCTRLONLY: TDBCheckBoxEh;
    Label9: TLabel;
    dsHandFL_CTRLONLY: TFIBSmallIntField;
    dsCurDFL_CTRLONLY: TFIBSmallIntField;
    DBCheckBoxEh2: TDBCheckBoxEh;
    Label10: TLabel;
    dsDFL_CTRLONLY: TFIBSmallIntField;
    dsCurDDEVTYPE: TFIBstringField;
    dsCurDTAGNAME: TFIBstringField;
    cbHandSOLEOWNER: TDBCheckBoxEh;
    Label11: TLabel;
    dsHandFL_SOLEOWNER: TFIBSmallIntField;
    dsCurDFL_SOLEOWNER: TFIBSmallIntField;
    dsDFL_SOLEOWNER: TFIBSmallIntField;
    Label12: TLabel;
    DBCheckBoxEh5: TDBCheckBoxEh;
    dsCurDMODEFLAGS: TStringField;
    Label13: TLabel;
    Label14: TLabel;
    Label15: TLabel;
    Label16: TLabel;
    Label17: TLabel;
    Label18: TLabel;
    DBCheckBoxEh6: TDBCheckBoxEh;
    DBCheckBoxEh7: TDBCheckBoxEh;
    DBCheckBoxEh8: TDBCheckBoxEh;
    DBComboBoxEh2: TDBComboBoxEh;
    DBNumberEditEh2: TDBNumberEditEh;
    DBCheckBoxEh9: TDBCheckBoxEh;
    DBCheckBoxEh10: TDBCheckBoxEh;
    DBEditEh1: TDBEditEh;
    cbAutoMinimize: TCheckBox;
    procedure ds2FilterRecord(DataSet: TDataSet; var Accept: Boolean);
    procedure Button1Click(Sender: TObject);
    procedure acAdd1Execute(Sender: TObject);
    procedure acDel1Execute(Sender: TObject);
    procedure acPost1Execute(Sender: TObject);
    procedure acRefresh1Execute(Sender: TObject);
    procedure acAdd2Execute(Sender: TObject);
    procedure acDel2Execute(Sender: TObject);
    procedure acPost2Execute(Sender: TObject);
    procedure acUpDownExecute(Sender: TObject);
    procedure dsrcMStateChange(Sender: TObject);
    procedure dsrcDStateChange(Sender: TObject);
    procedure dsDBeforePost(DataSet: TDataSet);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button2Click(Sender: TObject);
    procedure acCurRefreshExecute(Sender: TObject);
    procedure acCurSetExecute(Sender: TObject);
    procedure acCurAddExecute(Sender: TObject);
    procedure acCheckExecute(Sender: TObject);
    procedure acCurDelExecute(Sender: TObject);
    procedure acResetExecute(Sender: TObject);
    function SetAndCheck(OnlyCheck: boolean): boolean;
    procedure btHandEditClick(Sender: TObject);
    procedure dsrcHandStateChange(Sender: TObject);
    procedure acHandAddExecute(Sender: TObject);
    procedure acHandDelExecute(Sender: TObject);
    procedure acHandPostExecute(Sender: TObject);
    procedure dsrcCurMDataChange(Sender: TObject; Field: TField);
    procedure FormCreate(Sender: TObject);
    procedure dsHandCalcFields(DataSet: TDataSet);
    procedure grid1SortMarkingChanged(Sender: TObject);
    procedure gridApplyFilter(Sender: TObject);
    procedure FormDeactivate(Sender: TObject);
    procedure dsrcMDataChange(Sender: TObject; Field: TField);
    procedure dsMAfterDelete(DataSet: TDataSet);
    procedure dsMAfterInsert(DataSet: TDataSet);
    procedure dsMAfterPost(DataSet: TDataSet);
    procedure updateButtonsD(DataSet: TDataSet);
    procedure FormShow(Sender: TObject);
  private
    BlokEditDisabled: boolean;
    function Is_CurM_Hand: boolean;
    procedure UpdateList(Sender: TObject);
    { Private declarations }
  public
    FilterAdd, FilterDel: string;
    M: TVisSeqc;
  end;

  function VisSeqcConfigFormCreate(M: TVisSeqc; dbname: string): boolean;
  procedure VisSeqcConfigFormFree;
  procedure VisSeqcOpenDatasets;
  procedure VisSeqcOpenDevices(AFilterAdd, AFilterDel: string);
  procedure VisSeqcLoadRootName(M: TVisSeqc; ACode: integer);


  procedure update_dataset(dsrc: array of TDataSource);

var
  VisSeqcConfigForm: TVisSeqcConfigForm;

implementation
uses
  infodlg,
  InputDialog,
  UserControlEx,
  rpVisualParams,
  users,
  VisSeqcConfigAdd,
  VisSeqcHandConfig,
  VisSeqcDBCheck,
  Status,
  rpSysUtils,
  RpVisualGlobal,
  RpVisualUtils,
  tagstorage,
  numbers;

{$R *.dfm}


function VisSeqcConfigFormCreate(M: TVisSeqc; dbname: string): boolean;
var
  edit_access: boolean;
//  s: string;
begin
  if VisSeqcConfigForm=nil then
    VisSeqcConfigForm := TVisSeqcConfigForm.Create(nil)
  else
    VisSeqcConfigForm.WindowState := wsNormal;

  VisSeqcConfigForm.BlokEditDisabled := rpVisualParams_Read(
        'VisSEQC_edit',
        'Сост.марш: Запрет редактир.блоков (0-нет, 1-да)',
        '0') = '1';

  if isModeUserEx then
     edit_access := isPermittedSilent('VisSEQC')
  else
     edit_access := CheckAccess(PREVILEG_SEQC_EDIT1, false);

  VisSeqcConfigForm.TabSheet2.TabVisible := (edit_access) and (not VisSeqcConfigForm.BlokEditDisabled);
  VisSeqcConfigForm.acHandAdd.Enabled := edit_access;
  VisSeqcConfigForm.acHandDel.Enabled := edit_access;
  VisSeqcConfigForm.acHandUp.Enabled := edit_access;
  VisSeqcConfigForm.acHandDown.Enabled := edit_access;
  VisSeqcConfigForm.acHandPost.Enabled := edit_access;
  VisSeqcConfigForm.acHandAdd.Enabled := edit_access;
  VisSeqcConfigForm.gridHand.ReadOnly := not edit_access;
  VisSeqcConfigForm.cbHandARMO.ReadOnly := not edit_access;
  VisSeqcConfigForm.cbHandCTRLPROD.ReadOnly := not edit_access;
  VisSeqcConfigForm.cbHandPROD.ReadOnly := not edit_access;
  VisSeqcConfigForm.cbHandCTRLONLY.ReadOnly := not edit_access;
  VisSeqcConfigForm.cbHandSOLEOWNER.ReadOnly := not edit_access;
  VisSeqcConfigForm.cmbHandTRANSPARENT.ReadOnly := not edit_access;
  VisSeqcConfigForm.edHandDLY_PRODSTOP.ReadOnly := not edit_access;

  edit_access := CheckAccess(PREVILEG_SEQC_EDIT2, false);
  VisSeqcConfigForm.acCurAdd.Enabled := edit_access;
  VisSeqcConfigForm.acCurDel.Enabled := edit_access;
  VisSeqcConfigForm.acCurEdit.Enabled := edit_access;
  
  VisSeqcConfigForm.Panel7.Visible := not VisSeqcConfigForm.BlokEditDisabled;

  try
    VisSeqcConfigForm.M := M;
    with VisSeqcConfigForm do begin

      if ((db1.Connected) and (DBName <> dbname)) or (dbname='') then
        db1.Connected := false;

      if not db1.Connected then begin
        db1.DBName := dbname;
        db1.Connected := true;
        CheckDatabase(pFIBQuery1);
      end;
    end;
    result := true;
  except
    result := false;
  end;
end;

procedure VisSeqcConfigFormFree;
begin
  if VisSeqcConfigForm<>nil then begin

    if VisSeqcConfigForm.db1.Connected then
        VisSeqcConfigForm.db1.Connected := false;

    VisSeqcConfigForm.Free;
  end;

  VisSeqcConfigForm := nil;
end;


procedure VisSeqcOpenDatasets;
begin
  VisSeqcConfigForm.dsM.Open;
  VisSeqcConfigForm.dsD.Open;
  VisSeqcConfigForm.dsCurM.Open;
  VisSeqcConfigForm.dsCurD.Open;
  VisSeqcConfigForm.dsSubrootsM.Open;
end;


procedure TVisSeqcConfigForm.ds2FilterRecord(DataSet: TDataSet;
  var Accept: Boolean);
var
  s: string;
begin
  s := DataSet.FieldByName('NAME').AsString;
  Accept:=false;
  if (CheckFilter(s, FilterAdd))  or (FilterAdd='') then
    if (not CheckFilter(s, FilterDel)) or (FilterDel='') then 
      Accept:=true;
end;

procedure VisSeqcOpenDevices(AFilterAdd, AFilterDel: string);
begin
  VisSeqcConfigForm.FilterAdd := AFilterAdd;
  VisSeqcConfigForm.FilterDel := AFilterDel;
  VisSeqcConfigForm.ds2.Open;
end;


procedure TVisSeqcConfigForm.Button1Click(Sender: TObject);
begin
  close;
end;

procedure TVisSeqcConfigForm.acAdd1Execute(Sender: TObject);
begin
  if dsM.CanInsert then dsM.Append;
  grid1.SetFocus;
end;

procedure TVisSeqcConfigForm.acDel1Execute(Sender: TObject);
begin
  if showInfoDlg('Удалить группу?', mtConfirmation, mbOKCancel, 0) <> mrOk then exit;
  try
    if dsM.CanDelete then dsM.Delete;
  except
  end;
end;

procedure TVisSeqcConfigForm.acPost1Execute(Sender: TObject);
begin
  if dsM.CanEdit then dsM.Post;
end;

procedure TVisSeqcConfigForm.acRefresh1Execute(Sender: TObject);
begin
  update_dataset([dsrcM]);
  update_dataset([dsrcD]);
end;




procedure TVisSeqcConfigForm.acAdd2Execute(Sender: TObject);
begin
  if dsD.CanInsert then dsD.Append;
  grid2.SetFocus;
end;

procedure TVisSeqcConfigForm.acDel2Execute(Sender: TObject);
begin
  if showInfoDlg('Удалить устройство?', mtConfirmation, mbOKCancel, 0) <> mrOk then exit;
  try
    if dsD.CanDelete then dsD.Delete;
  except
  end;
end;

procedure TVisSeqcConfigForm.acPost2Execute(Sender: TObject);
begin
  if dsD.CanEdit then dsD.Post;
end;

procedure update_dataset(dsrc: array of TDataSource);
var
  n,i: integer;
  id: array of integer;
begin
  try
    n := length(dsrc);
    if n=0 then exit;

    SetLength(id, n);

    for i:=0 to n-1 do
      id[i] := dsrc[i].DataSet.fieldbyname('ID').AsInteger;

    for i:=0 to n-1 do
      dsrc[i].Enabled := false;

    dsrc[0].DataSet.Close;
    dsrc[0].DataSet.Open;

    for i:=0 to n-1 do
      dsrc[i].DataSet.Locate('ID', id[i], []);

    for i:=0 to n-1 do
      dsrc[i].Enabled := true;
  except
  end;
end;


procedure TVisSeqcConfigForm.acUpDownExecute(Sender: TObject);
var
  id1, id2, ordernum1, ordernum2: integer;
  ds: TpFIBDataSet;
  dsrc: TDataSource;
begin
  if (Sender = acUp) or (Sender = acDown) then begin
    ds := dsD;
    dsrc := dsrcD;
  end else begin
    ds := dsHand;
    dsrc := dsrcHand;
  end;

  try
    dsrc.Enabled := False;

    id1 := ds.fieldByName('ID').AsInteger;
    ordernum1 := ds.fieldByName('ORDERNUM').AsInteger;

    if (Sender = acUp) or (Sender = acHandUp) then
      ds.Prior
    else
      ds.Next;

    id2 := ds.fieldByName('ID').AsInteger;
    ordernum2 := ds.fieldByName('ORDERNUM').AsInteger;

    if (id1>0) and (id2>0) and (id1<>id2) and (ordernum1>0) and (ordernum2>0) then begin
      ds.Edit;
      ds.fieldByName('ORDERNUM').AsInteger := ordernum1;
      ds.Post;

      if (Sender = acUp) or (Sender = acHandUp) then
        ds.Next
      else
        ds.Prior;

      ds.Edit;
      ds.fieldByName('ORDERNUM').AsInteger := ordernum2;
      ds.Post;

    end;

    dsrc.Enabled := true;

    update_dataset([dsrc]);
  except
  end;
end;

procedure TVisSeqcConfigForm.dsrcMStateChange(Sender: TObject);
begin
  acPost1.Enabled := dsM.State in [dsEdit, dsInsert];
  ActionToolBar2.Enabled := not acPost1.Enabled;
  grid2.Enabled := not acPost1.Enabled;
end;

procedure TVisSeqcConfigForm.dsrcDStateChange(Sender: TObject);
begin
  acPost2.Enabled := (dsD.State in [dsEdit, dsInsert]);
end;

procedure TVisSeqcConfigForm.dsDBeforePost(DataSet: TDataSet);
begin
  if( dsM.Eof ) then begin
    dsD.Cancel;
    exit;
  end;


  if DataSet.FieldByName('TIMESTART').IsNull then
    DataSet.FieldByName('TIMESTART').AsInteger := 5;

  if DataSet.FieldByName('TIMESTOP').IsNull then
    DataSet.FieldByName('TIMESTOP').AsInteger := 5;
end;



////////////////////////////////////////////////////////////////////////////////
procedure TVisSeqcConfigForm.acCurSetExecute(Sender: TObject);
begin
  OnDeactivate := nil;
  if not SetAndCheck(false) then
    ShowMessage('Установка данных не выполнена')
  else
    close;
  OnDeactivate := FormDeactivate;
end;

procedure TVisSeqcConfigForm.acCheckExecute(Sender: TObject);
begin
  if SetAndCheck(true) then begin
    if Sender<>nil then
      ShowMessage('Проверка выполнена успешно')
  end else
    showInfoDlg('Данные в ПЛК не соответствуют выбранному маршруту. '+
          'Выполните установку маршрута в ПЛК!', mtWarning, [mbOK], 0);

end;

function TVisSeqcConfigForm.SetAndCheck(OnlyCheck: boolean): boolean;
type
  _rec = record
    tag_addr: integer;
    tag_delays: integer;
    tag_modeflags: integer;
    val_addr: integer;
    val_delays: integer;
    val_modeflags: integer;
  end;
var
  _tagname, _address, _delays, _modeflags: string;
  FTagCode, Code: integer;
  i,n,j: integer;
  arr: array of _rec;
  flag: boolean;
  s, bad_tags: string;
  DATA_SETUP_TIMEOUT: integer;
begin
  result := false;
  flag := false;

  DATA_SETUP_TIMEOUT := 60;

  acCurRefreshExecute(nil);

  _tagname := repl(M.Tagname_Seqc, M.TagIdRoot, M.TagRoot);
  _address := M.TagPath + '.SEQC_' + _TagName + '_Address';
  _delays := M.TagPath + '.SEQC_' + _TagName + '_Delays';
  _modeflags := M.TagPath + '.SEQC_' + _TagName + '_ModeFlags';


  i := GetTagValueByName(M.TagPath + '.SEQC_' + _TagName + '_Sost');
  if not OnlyCheck then
    if i <> 0 then begin
      close;
      exit;
    end;

  bad_tags := '';

  s := M.TagPath + '.SEQC_' + _TagName + '_Code';
  FTagCode := GetTagIndex(s);
  if FTagCode=-1 then
    bad_tags := bad_tags + s + #13;

  Code := dsCurM.fieldByName('CODE').AsInteger;

  if Code<=0 then
    exit;


  // формирование массива
  n := dsCurD.RecordCountFromSrv+1;
  SetLength(arr, n);

  dsCurD.First;
  for i:=0 to n-2 do begin
    s := _address + inttostr(i);
    arr[i].tag_addr := GetTagIndex(s);
    if arr[i].tag_addr=-1 then bad_tags := bad_tags + s + #13;

    s := _delays + inttostr(i);
    arr[i].tag_delays := GetTagIndex(s);
    if arr[i].tag_delays=-1 then bad_tags := bad_tags + s + #13;

    s := _modeflags + inttostr(i);
    arr[i].tag_modeflags := GetTagIndex(s);
    if arr[i].tag_modeflags=-1 then bad_tags := bad_tags + s + #13;


    arr[i].val_addr := dsCurD.FieldByName('ADDR').AsInteger;
    arr[i].val_delays := dsCurD.FieldByName('TIMESTART').AsInteger * $100 +
          dsCurD.FieldByName('TIMESTOP').AsInteger;

    arr[i].val_modeflags :=
          ((dsCurD.FieldByName('FL_ARMO').AsInteger) and 1);

    arr[i].val_modeflags := arr[i].val_modeflags +
          ((dsCurD.FieldByName('FL_TRANSPARENT').AsInteger) and 3) shl 1;

    arr[i].val_modeflags := arr[i].val_modeflags +
          ((dsCurD.FieldByName('FL_CTRLPROD').AsInteger) and 1) shl 3;

    arr[i].val_modeflags := arr[i].val_modeflags +
          ((dsCurD.FieldByName('FL_PROD').AsInteger) and 1) shl 4;

    arr[i].val_modeflags := arr[i].val_modeflags +
          ((dsCurD.FieldByName('FL_CTRLONLY').AsInteger) and 1) shl 5;

    arr[i].val_modeflags := arr[i].val_modeflags +
          ((dsCurD.FieldByName('FL_SOLEOWNER').AsInteger) and 1) shl 6;

    arr[i].val_modeflags := arr[i].val_modeflags +
          ((dsCurD.FieldByName('DLY_PRODSTOP').AsInteger) and 255) shl 8;

    dsCurD.Next;
  end;

  // конец массива
  i:=n-1;
  s := _address + inttostr(i);
  arr[i].tag_addr := GetTagIndex(s);
  if arr[i].tag_addr=-1 then bad_tags := bad_tags + s + #13;

  arr[i].tag_delays := -1;
  arr[i].tag_modeflags := -1;
  arr[i].val_addr := $FFFF;
  arr[i].val_delays := 0;
  arr[i].val_modeflags := 0;


  // проверка что все теги нашлись
  if bad_tags<>'' then begin
    ShowMessage('Не найдены теги: '#13 + bad_tags);
    exit;
  end;


  // запись / контроль
  if not OnlyCheck then
    ShowStatusMessageA('Установка данных','подождите...', clLime);

  for j:=1 to DATA_SETUP_TIMEOUT do begin
    flag := true;
    for i:=0 to n-1 do begin

      if arr[i].tag_addr <> -1 then
        if arr[i].val_addr <> GetTagValue(arr[i].tag_addr) then begin
          if not OnlyCheck then
            SetTagValue(arr[i].tag_addr, arr[i].val_addr);
          flag := false;
        end;

      if arr[i].tag_delays <> -1 then
        if arr[i].val_delays <> GetTagValue(arr[i].tag_delays) then begin
          if not OnlyCheck then
            SetTagValue(arr[i].tag_delays, arr[i].val_delays);
          flag := false;
        end;

      if arr[i].tag_modeflags <> -1 then
        if arr[i].val_modeflags <> GetTagValue(arr[i].tag_modeflags) then begin
          if not OnlyCheck then
            SetTagValue(arr[i].tag_modeflags, arr[i].val_modeflags);
          flag := false;
        end;

    end;

    if FTagCode <> -1 then
      if Code <> GetTagValue(FTagCode) then begin
        if not OnlyCheck then
          SetTagValue(FTagCode, Code);
        flag := false;
      end;

    if flag then break;

    if OnlyCheck then break;

//    rpDelay(1000);
    DelayMs(1000, true);
  end;
  
  dsCurD.First;

  if not OnlyCheck then begin
    CloseStatusMessage;
    VisSeqcLoadRootName(M, M.Code);
  end;

  result := flag;

end;

procedure VisSeqcLoadRootName(M: TVisSeqc; ACode: integer);
var
  form_exists: boolean;
//  s: string;
begin

  if ACode=0 then begin
//    M.objLabel.Caption := 'Маршрут не выбран';
    M.objLabel.Caption := '';
    M.objLabel.Hint := '';
    exit;
  end;

  form_exists := VisSeqcConfigForm <> nil;

  if not form_exists then begin
    if VisSeqcConfigFormCreate(M, M.DBName) then begin
      VisSeqcOpenDevices(M.FilterAdd, M.FilterDel);
      VisSeqcOpenDatasets;
    end;
  end;

  if not VisSeqcConfigForm.db1.Connected then begin
    M.objLabel.Caption := 'Ошибка подключения к БД';
    exit;
  end;

  VisSeqcConfigForm.dsCurM.Locate('CODE', ACode, []);

  if VisSeqcConfigForm.dsCurM.FieldByName('CODE').AsInteger = ACode then begin
    M.objLabel.Caption := VisSeqcConfigForm.dsCurM.FieldByName('NAME').AsString;
    M.objLabel.Hint := VisSeqcConfigForm.dsCurM.FieldByName('DESCR').AsString;

    M.KillRootDevices;
    VisSeqcConfigForm.dsCurD.First;
    while not VisSeqcConfigForm.dsCurD.Eof do
      with M.AddRootDevices do begin
        Addr := VisSeqcConfigForm.dsCurD.fieldbyname('addr').AsInteger;
        Name := VisSeqcConfigForm.dsCurD.fieldbyname('name').AsString;
        devtype := VisSeqcConfigForm.dsCurD.fieldbyname('devtype').AsString;
        tagname := VisSeqcConfigForm.dsCurD.fieldbyname('tagname').AsString;
//        soleOwner := VisSeqcConfigForm.dsCurD.fieldbyname('fl_soleowner').AsBoolean;

        VisSeqcConfigForm.dsCurD.Next;
      end;
    VisSeqcConfigForm.dsCurD.First;



  end else begin
    // root не найден
    M.objLabel.Caption := 'Маршрут Code=' + inttostr(ACode) + ' не найден';
    M.objLabel.Hint := '';
  end;
//  M.objLabel.Hint := M.objLabel.Caption;


  if not form_exists then
    VisSeqcConfigFormFree;
end;

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

procedure TVisSeqcConfigForm.Button2Click(Sender: TObject);
begin
  close;
end;

procedure TVisSeqcConfigForm.acCurRefreshExecute(Sender: TObject);
begin
  update_dataset([dsrcCurM]);
end;


procedure TVisSeqcConfigForm.acCurAddExecute(Sender: TObject);
var
  edit_mode: boolean;
  s: string;
begin
  edit_mode := (Sender = acCurEdit) or (sender = gridCurM);

  if edit_mode then begin
    if dsCurM.Eof then exit;

    if Is_CurM_Hand then begin
      s := dsCurMNAME.AsString;
      delete(s,1,2);
      if not ShowInputDialog('Название маршрута', 'Введите название маршрута', s) then exit;
      dsCurM.Edit;
      dsCurMNAME.AsString := '* ' + s;
      dsCurM.Post;
      exit;
    end;
  end else begin
    if BlokEditDisabled then begin
      s := 'Новый маршрут';
      if not ShowInputDialog('Название маршрута', 'Введите название маршрута', s) then exit;
      dsCurM.Append;
      dsCurMNAME.AsString := '* ' + s;
      dsCurM.Post;
      exit;
    end;
  end;

  VisSeqcConfigAddForm := TVisSeqcConfigAddForm.Create(self);
  try
    VisSeqcConfigAddForm.db := db1;
    VisSeqcConfigAddForm.edit_mode := edit_mode;

    VisSeqcConfigAddForm.Init;
    VisSeqcConfigAddForm.ShowModal;

    VisSeqcConfigForm.dsCurD.Close;
    VisSeqcConfigForm.dsHand.Close;
    VisSeqcConfigForm.dsSubrootsM.Close;
    VisSeqcConfigForm.dsCurD.Open;
    VisSeqcConfigForm.dsHand.Open;
    VisSeqcConfigForm.dsSubrootsM.Open;

  finally
    VisSeqcConfigAddForm.Free;
  end;

end;


procedure TVisSeqcConfigForm.acCurDelExecute(Sender: TObject);
begin
  if showInfoDlg('Удалить маршрут?', mtConfirmation, mbOKCancel, 0) <> mrOk then exit;
  try
    if dsCurM.CanDelete then dsCurM.Delete;
  except
  end;
end;

procedure TVisSeqcConfigForm.acResetExecute(Sender: TObject);
var
  _tagname: string;
begin
  if showInfoDlg('Сбросить установку маршрута в ПЛК?', mtConfirmation, mbOKCancel, 0) <> mrOk then exit;
  try
    _tagname := repl(M.Tagname_Seqc, M.TagIdRoot, M.TagRoot);
    SetTagValue(GetTagIndex(M.TagPath + '.SEQC_' + _TagName + '_Code'), 0);
    close;
  except
  end;
end;

procedure TVisSeqcConfigForm.btHandEditClick(Sender: TObject);
begin
  if not CheckAccess(PREVILEG_SEQC_EDIT1, true) then exit;

  if dsCurM.Eof then exit;
  if showInfoDlg('ПЕРЕВОД НА РУЧНОЕ РЕДАКТИРОВАНИЕ'#13+
        'После выполнения этой операции система не сможет следить за '+
        'правильностью составления маршрута. Обратный перевод будет невозможен. '+
        'Перевести маршрут на ручное редактирование?',
        mtConfirmation, mbOKCancel, 0) <> mrOk
  then exit;

  dsCurM.Edit;
  dsCurMNAME.AsString := '* ' + dsCurMNAME.AsString;
  dsCurM.Post;

  dsSubrootsM.First;
  while not dsSubrootsM.Eof do dsSubrootsM.Delete;
end;

procedure TVisSeqcConfigForm.dsrcHandStateChange(Sender: TObject);
begin
  acHandPost.Enabled := dsHand.State in [dsEdit, dsInsert];
end;

procedure TVisSeqcConfigForm.acHandAddExecute(Sender: TObject);
begin
  if dsHand.CanInsert then dsHand.Append;
  gridHand.SetFocus;
end;

procedure TVisSeqcConfigForm.acHandDelExecute(Sender: TObject);
begin
  if showInfoDlg('Удалить устройство?', mtConfirmation, mbOKCancel, 0) <> mrOk then exit;
  try
    if dsHand.CanDelete then dsHand.Delete;
  except
  end;
end;

procedure TVisSeqcConfigForm.acHandPostExecute(Sender: TObject);
begin
  if dsHand.CanEdit then dsHand.Post;
end;

procedure TVisSeqcConfigForm.dsrcCurMDataChange(Sender: TObject;
  Field: TField);
begin
  pnlHand.Visible := Is_CurM_Hand;
end;

function TVisSeqcConfigForm.Is_CurM_Hand: boolean;
begin
  result := false;
  if not dsCurM.Eof then
    result := copy(dsCurMNAME.AsString,1,1)='*';
end;

procedure TVisSeqcConfigForm.FormCreate(Sender: TObject);
begin
  pnlHand.Align := alClient;
end;

procedure TVisSeqcConfigForm.dsHandCalcFields(DataSet: TDataSet);
var
  s: string;
begin
  s := '';
  if DataSet.FieldByName('FL_CTRLONLY').AsInteger>0 then s := s + 'К ';

  if DataSet.FieldByName('FL_ARMO').AsInteger>0 then s := s + 'Н ';

  if DataSet.FieldByName('FL_TRANSPARENT').AsInteger=1 then s := s + 'ПрЗ ';
  if DataSet.FieldByName('FL_TRANSPARENT').AsInteger=2 then s := s + 'ПрР ';
  if DataSet.FieldByName('FL_TRANSPARENT').AsInteger=3 then s := s + 'Пр ';

  if DataSet.FieldByName('FL_CTRLPROD').AsInteger>0 then s := s + 'Кп ';

  if DataSet.FieldByName('FL_PROD').AsInteger>0 then s := s + 'Пд' +
        iif( DataSet.FieldByName('DLY_PRODSTOP').AsInteger>0, DataSet.FieldByName('DLY_PRODSTOP').AsString, '') + ' ';

  if DataSet.FieldByName('FL_SOLEOWNER').AsInteger>0 then s := s + 'И';

  DataSet.FieldByName('MODEFLAGS').AsString := s;
end;

procedure TVisSeqcConfigForm.grid1SortMarkingChanged(Sender: TObject);
begin
  SortMarkingChanged(sender);
end;

procedure TVisSeqcConfigForm.UpdateList(Sender: TObject);
const
  _filter_beg = '/*FILTER_BEG*/';
  _filter_end = '/*FILTER_END*/';
var
  s: string;
  i,k1,k2: integer;
  FiltStr: string;
begin

  FiltStr := '';
  with sender as TDBGridEh do
    for i:=0 to Columns.Count-1 do
      if trim(Columns[i].STFilter.ExpressionStr) <> '' then

        FiltStr :=
            FiltStr + ' AND ' +
            Columns[i].FieldName +
            ' CONTAINING '''+trim(Columns[i].STFilter.ExpressionStr)+''' ';


            

  with ((sender as TDBGridEh).DataSource.DataSet as TpFIBDataSet) do
  try



    Close;
    s := SelectSQL.Text;

    k1 := pos(_filter_beg, s) + length(_filter_beg);
    k2 := pos(_filter_end, s);

    system.delete(s, k1, k2-k1);
    system.insert(FiltStr, s, k1);

    SelectSQL.Text := s;
    Open;
  except
    Transaction.Active := false;
  end;

end;




procedure TVisSeqcConfigForm.gridApplyFilter(Sender: TObject);
begin
  UpdateList(sender);
end;

procedure TVisSeqcConfigForm.FormDeactivate(Sender: TObject);
begin
  if cbAutoMinimize.Checked then
    WindowState := wsMinimized;
end;

procedure TVisSeqcConfigForm.dsrcMDataChange(Sender: TObject;
  Field: TField);
begin
  acAdd2.Enabled := not dsM.Eof;
  acDel2.Enabled := not dsM.Eof;
end;

procedure TVisSeqcConfigForm.dsMAfterDelete(DataSet: TDataSet);
begin
  acAdd2.Enabled := not dsM.Eof;
  acDel2.Enabled := not dsM.Eof;
end;

procedure TVisSeqcConfigForm.dsMAfterInsert(DataSet: TDataSet);
begin
  acAdd2.Enabled := not dsM.Eof;
  acDel2.Enabled := not dsM.Eof;
end;

procedure TVisSeqcConfigForm.dsMAfterPost(DataSet: TDataSet);
begin
  acAdd2.Enabled := not dsM.Eof;
  acDel2.Enabled := not dsM.Eof;
end;

procedure TVisSeqcConfigForm.updateButtonsD(DataSet: TDataSet);
begin
  acAdd2.Enabled := not dsM.Eof;
  acDel2.Enabled := not dsM.Eof;
end;

procedure TVisSeqcConfigForm.FormShow(Sender: TObject);
//var
//  edit_access:Boolean;
begin
//  if isModeUserEx then
//     edit_access := isPermittedSilent('VisSEQC');
//  else
//
end;

end.
