unit DozatorNKomp;

interface
uses
  Types,
  Graphics,
  StdCtrls,
  SysUtils,
  Classes,
  Dialogs,
  ExtCtrls,
  Controls,
  ScadaBase,
  Forms,
  FIBQuery, pFIBQuery, FIBDatabase, pFIBDatabase, DB, FIBDataSet, pFIBDataSet
  ;

const
  dt_format = 'yyyy.mm.dd hh:nn:ss';
  dataformat = 'yyyymmdd';
  debug_mode = false;

type
  PDozatorNKompKomponent =^ TDozatorNKompKomponent;
  TDozatorNKompKomponent = record
    name: string;
    MainCounterTagNameLow : string;
    MainCounterTagIdxLow  : integer;

    MainCounterTagNameHight : string;
    MainCounterTagIdxHight  : integer;

    ReceiptTagHight       : string;
    ReceiptTagIdxHight    : integer;

    ReceiptTagLow         : string;
    ReceiptTagIdxLow      : integer;


    TimeDosBeginComp      : TDateTime;
    TimeDosEndComp        : TDateTime;

    Razmernost            : string;
    mul                   : real;
    isInit                : boolean;
    ValueDo               : int64;
    ValuePosle            : int64;
    ValueNeed             : int64;

    FakeReceipt1, FakeReceipt2 :integer;
    NeedUseFake           : boolean;

    Bunk                  : integer;

  end;

  TBunker = record
    id       : integer;
    num      : integer;
    name     : string;
    prodID   : integer;
    idm      : integer;
    isInit   : boolean;
  end;


  TModul = record
    idm      : integer;
    name     : string;
    desc     : string;
    mul      : real;
    idp      : integer;
    smena    : integer;
    enable   : boolean;
    isInit   : boolean;
  end;

  TSmena = record
    id       : integer;
    smenanum : integer;
    name     : string;
    timebeg  : integer;
    idsl     : integer;
    timeend  : integer;
    isInit   : boolean;
  end;

  TProd = record
    id       : integer;
    code     : integer;
    name     : string;
    desc     : string;
    isInit   : boolean;
  end;



  TDozatorNKomp = class( TCustomScadaObject )
  public
    Komponent: array of TDozatorNKompKomponent;
    cKomponent : integer;
    Sost       : integer;
    SostK      : integer;
    Connected  : boolean;
    maintablename: string;
    modulID    : integer;

    StartTag   : string;
    StartValue : integer;

    SostTag   : string;
    SostTagIdx : integer;

    SostTag2   : string;
    SostTagIdx2 : integer;

    SostTag3   : string;
    SostTagIdx3 : integer;

    old_Sost1   : integer;
    old_Sost2   : integer;
    old_Sost3   : integer;

    id_rec     :int64;


    cnt        : integer;


    ValueDo               : int64;
    ValuePosle            : int64;
    ValueNeed             : int64;
    Bunk                  : integer;

    time_start : TDateTime;
    time_stop  : TDateTime;

    isSavedBeginToDB, isSavedEndToDB : boolean;

    MainCounterTagNameLow : string;
    MainCounterTagIdxLow  : integer;
    MainCounterTagNameHight : string;
    MainCounterTagIdxHight  : integer;

    MixTag                 : string;
    MixTagIdx              : integer;

    NValueDo               : int64;
    NValuePosle            : int64;

    ErrorFlag  : string;
    ErrorFlagIdx  : integer;

    NMainCounterTagNameLow : string;
    NMainCounterTagIdxLow  : integer;
    NMainCounterTagNameHight : string;
    NMainCounterTagIdxHight  : integer;

    WES        : TpFIBDatabase;
    Trans      : TpFIBTransaction;
    qry        : TpFIBQuery;

    url        : string;
    user, pass : string;
    BunkList   : array of TBunker;
    ModulList  : array of TModul;
    ProdList   : array of TProd;
    SmenaList  : array of TSmena;

    dozatorMdlidx : integer;
    MesShow       : boolean;

    cBunker, cModul, cSmena, cProd : integer;

    MixTime    : integer;

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

    function Int2int64 (H,L:integer) : int64;
    function Int642Int (I:int64; w: boolean):integer;
    function GetCurrentWeight (id:integer) : int64;


    procedure createKomponent(            i:integer;
                                          nm  :string;
                                          mx  :real;
                                          rz  :string;
                                          TagA, TagB,
                                          TagRecA, TagRecB : string
                                           );


    procedure Init; override;
    procedure Process; override;
    procedure Start   (
                         wesS : string;
                         bunkS : string;
                         prod : integer;
                         brig : integer;
                         dstBunk : integer;
                         MixT : integer
                      );
    procedure Connect;
    procedure Disconnect;
    function  IsConnected : boolean;
    function  SaveEndToDB (mode:integer) : boolean;

    procedure GetBunkersList;
    procedure GetModulesList;

    procedure GetSmenaList;
    procedure GetProdList;

    function  CheckCanStart : boolean;

    function  ChekTag (name:string; var idx:integer):boolean;
    function  GetSmenaNumFromList (idsl:integer; t:TDateTime):integer;

    procedure ExceptionClose;
  end;

function createDozatorNKomp(var parent: TPanel; cKomponent:integer; DBLink, DBuser, DBpass : string; MID:integer; STTag:string; STVal:integer;
                            prodcH:string; prodcL:string; TagSost, TagSost2, TagSost3:String; NcountH, NcountL, EF, Mix:string; MShow : boolean ): TDozatorNKomp;


implementation
uses
  RpVisualGlobal,
  TagStorage,
  Variants,
  HyperStr;



procedure Log(s: string);
var
  F: TextFile;
begin
  try
    AssignFile(F, CurDir + 'error.log');
    if not FileExists(CurDir + 'error.log') then
      rewrite(F)
    else begin
      append(F);
    end;

    Writeln(F, DateTimeToStr(now) + ': ' + s);
  finally
    try
      CloseFile(F);
    except
    end;
  end;
end;


function createDozatorNKomp(var parent: TPanel; cKomponent:integer; DBLink, DBuser, DBpass : string; MID:integer; STTag:string; STVal:integer;
                            prodcH:string; prodcL:string; TagSost, TagSost2, TagSost3:String; NcountH, NcountL, EF, Mix:string; MShow : boolean ): TDozatorNKomp;
var
  dz: TDozatorNKomp;
  i:integer;
begin

  dz := TDozatorNKomp.Create(parent);
  dz.parent := parent;
  dz.cKomponent := cKomponent;

  SetLength(dz.Komponent, cKomponent);

  dz.url  := DBLink;
  dz.user := DBUser;
  dz.pass := DBPass;
  dz.maintablename := 'DOZATOR' + inttostr(dz.cKomponent)+'KOMP';
  dz.modulID := MID;
  dz.StartTag := STTag;
  dz.StartValue := STVal;

  dz.SostTag := TagSost;
  dz.SostTag2 := TagSost2;
  dz.SostTag3 := TagSost3;

  dz.MainCounterTagNameLow := prodcL;
  dz.MainCounterTagNameHight := prodcH;

  dz.NMainCounterTagNameLow := NcountL;
  dz.NMainCounterTagNameHight := NcountH;

  dz.MixTag := Mix;

  dz.ErrorFlag := EF;

  dz.dozatorMdlidx := -1;
  dz.id_rec := 0;

  dz.MesShow := MShow;

  for i:=0 to cKomponent-1 do
    dz.Komponent[i].isInit := false;

  result := dz;
end;

function  TDozatorNKomp.IsConnected : boolean;
begin
 result := Connected;
end;


constructor TDozatorNKomp.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  Sost := 0;

  SostK := -1;
  Connected := false;

  BunkList   := nil;
  cBunker    := 0;
  cKomponent := 0;
  WES        := TpFIBDatabase.Create(AOwner);
  Trans      := TpFIBTransaction.Create(AOwner);
  qry        := TpFIBQuery.Create(AOwner);


end;

destructor TDozatorNKomp.Destroy;
begin
  WES.Destroy;
  Trans.Destroy;
  qry.Destroy;
  Komponent  := nil;
  BunkList   := nil;
  ModulList  := nil;
  ProdList   := nil;
  SmenaList  := nil;
  
  cBunker    :=0;
  cKomponent :=0;

  inherited Destroy;

end;



procedure TDozatorNKomp.createKomponent ( i   :integer;
                                          nm  :string;
                                          mx  :real;
                                          rz  :string;
                                          TagA, TagB,
                                          TagRecA, TagRecB : string
                                        );
begin
  if (i >= cKomponent) OR (i < 0) then
    begin
      ShowMessage('Попытка инициализоровать несуществующий компонент дозатора');
      exit;
    end;

  if (Komponent[i].isInit) then
    begin
      ShowMessage('Попытка инициализоровать уже инициализированный компонент дозатора');
      exit;
    end;

  with Komponent[i] do
    begin
      name:= nm;
      MainCounterTagNameHight := TagA;
      MainCounterTagNameLow   := TagB;
      ReceiptTagHight       := TagRecA;
      ReceiptTagLow         := TagRecB;
      Razmernost            := rz;
      mul                   := 1 / mx;
      isInit                := true;
    end;
end;

procedure TDozatorNKomp.Init;
begin
  inherited;
end;

procedure TDozatorNKomp.ExceptionClose;
begin
 if Qry.Transaction.Active then
   begin
     Qry.Transaction.Rollback;
     qry.Close;
     qry.FreeHandle;
   end;
end;


procedure TDozatorNKomp.GetProdList;
var    sql : string;
begin
 if NOT WES.Connected then begin cProd:=0; exit; end;
         // ------------------------------------------------------------
         // Прочитать списки продуктов
         // ------------------------------------------------------------

         try
           sql := 'SELECT IDPROD, NAME, DESCR, CODE FROM PRODUCT ORDER BY NAME';
           qry.SQL.text := sql;
           qry.Transaction.StartTransaction;
           qry.ExecQuery;

           if qry.Eof then begin
             cProd := 0;
           end else begin
             cProd := 1;

             while not qry.Eof do
               begin
                 SetLength (ProdList, cProd);

                 ProdList[cProd-1].id   := qry.Fields[0].AsInteger;
                 ProdList[cProd-1].name := qry.Fields[1].AsString;
                 ProdList[cProd-1].desc := qry.Fields[2].AsString;
                 ProdList[cProd-1].code := qry.Fields[3].AsInteger;

                 ProdList[cProd-1].isInit := true;

                 cProd := cProd + 1;
                 qry.Next;
               end;

             cProd := cProd - 1;
           end;

           Qry.Transaction.Commit;
           qry.Close;
           qry.FreeHandle;

        except
          log (DateTimeToStr(now) + 'Провал запроса: '+sql);
          ExceptionClose;
        end;

end;

function TDozatorNKomp.GetSmenaNumFromList (idsl:integer; t:TDateTime):integer;
var i, rez, hm : integer;
begin
  rez := -1;
  for i:=0 to cSmena-1 do
    begin
      if (SmenaList[i].idsl = idsl) then
        begin
           hm := strtoint(FormatDateTime('hhnn', t));

           if (SmenaList[i].timebeg <= hm) and (hm <= SmenaList[i].timeend)
              then
                begin
                  rez := SmenaList[i].smenanum;
                  break;
                end;

        end;
    end;
  GetSmenaNumFromList := rez;
end;


procedure TDozatorNKomp.GetSmenaList;
var    sql : string;
begin
 if NOT WES.Connected then begin cSmena:=0; exit; end;
         // ------------------------------------------------------------
         // Прочитать списки смен
         // ------------------------------------------------------------

         try
           sql := 'SELECT IDSMENA, SMENANUM, NAME, TIMEBEG, TIMEEND, IDSL FROM SMENAS ORDER BY SMENANUM';
           qry.SQL.text := sql;
           qry.Transaction.StartTransaction;
           qry.ExecQuery;

           if qry.Eof then begin
             cSmena := 0;
           end else begin
             cSmena := 1;

             while not qry.Eof do
               begin
                 SetLength (SmenaList, cSmena);

                 SmenaList[cSmena-1].id       := qry.Fields[0].AsInteger;
                 SmenaList[cSmena-1].smenanum := qry.Fields[1].AsInteger;
                 SmenaList[cSmena-1].name     := qry.Fields[2].AsString;
                 SmenaList[cSmena-1].timebeg  := qry.Fields[3].AsInteger;
                 SmenaList[cSmena-1].timeend  := qry.Fields[4].AsInteger;
                 SmenaList[cSmena-1].idsl     := qry.Fields[5].AsInteger;
                 SmenaList[cSmena-1].isInit := true;

                 cSmena := cSmena + 1;
                 qry.Next;
               end;

             cSmena := cSmena - 1;
           end;

           Qry.Transaction.Commit;
           qry.Close;
           qry.FreeHandle;

         except
          log (DateTimeToStr(now) + 'Провал запроса: '+sql);
          ExceptionClose;
         end;

         // ------------------------------------------------------------
end;

procedure TDozatorNKomp.GetBunkersList;
var    sql : string;
begin
 if NOT WES.Connected then begin cBunker:=0; exit; end;
         // ------------------------------------------------------------
         // Прочитать списки бункеров
         // ------------------------------------------------------------
         try
           sql := 'SELECT ID, NAME, IDM, NUM, IDP FROM BUNKERS ORDER BY NUM';
           qry.SQL.text := sql;
           qry.Transaction.StartTransaction;
           qry.ExecQuery;

           if qry.Eof then begin
             cBunker := 0;
           end else begin
             cBunker := 1;

             while not qry.Eof do
               begin
                 SetLength (BunkList, cBunker);

                 BunkList[cBunker-1].id     := qry.Fields[0].AsInteger;
                 BunkList[cBunker-1].name   := qry.Fields[1].AsString;
                 BunkList[cBunker-1].idm    := qry.Fields[2].AsInteger;
                 BunkList[cBunker-1].num    := qry.Fields[3].AsInteger;
                 BunkList[cBunker-1].prodID := qry.Fields[4].AsInteger;
                 BunkList[cBunker-1].isInit := true;

                 cBunker := cBunker + 1;
                 qry.Next;
               end;

             cBunker := cBunker - 1;
           end;

           Qry.Transaction.Commit;
           qry.Close;
           qry.FreeHandle;

         except
           log (DateTimeToStr(now) + 'Провал запроса: '+sql);
           ExceptionClose;

         end;

         // ------------------------------------------------------------
end;

procedure TDozatorNKomp.GetModulesList;
var    sql : string;
begin
 if NOT WES.Connected then begin cModul:=0; exit; end;

         // ------------------------------------------------------------
         // Прочитать списки модулей
         // ------------------------------------------------------------
         try
           sql := 'SELECT IDM, NAME, DESCR, ENABLED, WMUL, IDPROD, IDSL FROM MODULES ORDER BY NAME';
           qry.SQL.text := sql;
           qry.Transaction.StartTransaction;
           qry.ExecQuery;

           if qry.Eof then begin
             cModul := 0;
           end else begin
             cModul := 1;

             while not qry.Eof do
               begin
                 SetLength (ModulList, cModul);

                 ModulList[cModul-1].idm    :=  qry.Fields[0].AsInteger;
                 ModulList[cModul-1].name   :=  qry.Fields[1].AsString;
                 ModulList[cModul-1].desc   :=  qry.Fields[2].AsString;

                 if qry.Fields[3].AsInteger = 1
                    then ModulList[cModul-1].enable := true
                    else ModulList[cModul-1].enable := false;

                 ModulList[cModul-1].mul    :=  qry.Fields[4].AsDouble;
                 ModulList[cModul-1].idp    :=  qry.Fields[5].AsInteger;
                 ModulList[cModul-1].smena  :=  qry.Fields[6].AsInteger;


                 ModulList[cModul-1].isInit :=  true;

                 if (modulID = ModulList[cModul-1].idm) then dozatorMdlidx := cModul-1;

                 cModul := cModul + 1;
                 qry.Next;
               end;

             cModul := cModul - 1;
           end;

           Qry.Transaction.Commit;
           qry.Close;
           qry.FreeHandle;

         except
          log (DateTimeToStr(now) + 'Провал запроса: '+sql);
          ExceptionClose;
         end;

         // ------------------------------------------------------------
end;


function TDozatorNKomp.ChekTag (name:string; var idx:integer):boolean;
begin
 idx := GetTagIndex(name);

 if idx = -1 then
    begin
      ShowMessage('Нет такого тега: ' + name);
      ChekTag := false;
    end      else
      ChekTag := true;
end;



procedure TDozatorNKomp.Connect;
var i:integer;
    w, w2:boolean;
begin

  if not rvgLogIn then Exit;

  w := true;

  for i:=0 to cKomponent-1 do
   begin
    if NOT Komponent[i].isInit then
      begin
        ShowMessage('Не инициализирован компонент '+inttostr(i+1)+' дозатора');
        w:=false;
      end else
      begin
        w := w and ChekTag (Komponent[i].MainCounterTagNameLow,    Komponent[i].MainCounterTagIdxLow );
        w := w and ChekTag (Komponent[i].MainCounterTagNameHight,  Komponent[i].MainCounterTagIdxHight);
        w := w and ChekTag (Komponent[i].ReceiptTagHight,          Komponent[i].ReceiptTagIdxHight);
        w := w and ChekTag (Komponent[i].ReceiptTagLow,            Komponent[i].ReceiptTagIdxLow);
      end;
   end;


  w := w and ChekTag (MixTag,  MixTagIdx);
  w := w and ChekTag (ErrorFlag,  ErrorFlagIdx);
  w := w and ChekTag (SostTag,    SostTagIdx);
  w := w and ChekTag (SostTag2,   SostTagIdx2);
  w := w and ChekTag (SostTag3,   SostTagIdx3);

  if  GetTagIndex(StartTag) = -1 then
           begin
             w:=false;
             ShowMessage('Нет такого тега: ' + StartTag);
           end;


  w := w and ChekTag (MainCounterTagNameLow,    MainCounterTagIdxLow);
  w := w and ChekTag (MainCounterTagNameHight,  MainCounterTagIdxHight );
  w := w and ChekTag (NMainCounterTagNameLow,   NMainCounterTagIdxLow);
  w := w and ChekTag (NMainCounterTagNameHight, NMainCounterTagIdxHight);


  id_rec := 0;

  WES.DatabaseName := url;

  WES.DBParams.Add('lc_ctype=WIN1251');
  WES.DBParams.Add('user_name=' + user);
  WES.DBParams.Add('password=' + pass);

  WES.SQLDialect := 3;

  WES.DefaultTransaction := Trans;
  qry.Database := WES;
  qry.ParamCheck := true;
  qry.Transaction := Trans;


  if NOT w then
    begin
      Connected := false;
      exit;
    end;

  try
    WES.Connected := true;
    if WES.Connected then
       begin
         //Есть соединение, проверить таблицы и создать отсутствующие.

         //Считать список модулей
         GetModulesList;

         w2 := false;
         // проверить, что выбранный модуль существует
         for i:=0 to cModul-1 do
           begin
             if ModulList[i].idm = modulID then w2 := true;
           end;

         if NOT w2 then
           begin
             ShowMessage('Нет модуля с id' + inttostr(modulID));
             w := false;
           end;

         //Считать списки бункеров
         GetBunkersList;

         GetProdList;

         //Считать списки смен
         GetSmenaList;
       end
    else
       begin
         w := false;
       end;

  except
    WES.Connected := false;
    ShowMessage('FALSE');
  end;

  Connected := w;
end;

procedure TDozatorNKomp.Disconnect;
var i:integer;
begin
  if Sost <> 0 then
    begin
      SaveEndToDB(3);
      
      Sost:=0;
    end;


  Connected := false;
  for i:=0 to cKomponent-1 do
    begin
      if Komponent[i].isInit then
        begin
          Komponent[i].MainCounterTagIdxLow    := -1;
          Komponent[i].MainCounterTagIdxHight  := -1;
        end;
    end;

  if WES.Connected then WES.Connected := false;
end;




function TDozatorNKomp.Int2int64 (H, L:integer) : int64;
begin
  Int2int64 := int64(H) * $10000 + int64(L);
end;

function TDozatorNKomp.Int642Int (I:int64; w: boolean):integer;
VAR R:INTEGER;
begin
  if w then R := i div $10000
       else R := i mod $10000;
 Int642Int := R;
end;


function TDozatorNKomp.GetCurrentWeight (id:integer) : int64;
begin
 if (not rvgLogIn) or (NOT Connected) then
   begin
     GetCurrentWeight := -3;
     Exit;
   end;

 if (id >= 0) and (id < cKomponent) then
   begin
     if Komponent[id].isInit then
                              begin
                                result := Int2int64 (GetTagValue(Komponent[id].MainCounterTagIdxHight), GetTagValue(Komponent[id].MainCounterTagIdxLow));
                              end
                            else
                              begin
                                result := -2;
                              end;
   end
 else
   begin
     result := -1;
   end;

end;


function GetTimeShtamp (t:TDateTime; i:integer):int64;
begin
  GetTimeShtamp := strtoint64(FormatDateTime(dataformat, t))*100 + (i);
end;


function TDozatorNKomp.SaveEndToDB (mode:integer) : boolean;
var sql:string;
    SavedToDB:boolean;
    i:integer;
    tmp:int64;
    s:string;
begin
   // 1 - Sost=1
   // 2 - Sost=2
   // 3 - Sost=3 авария
   // 4 - Sost=3 норм стоп

   if (not rvgLogIn) or (NOT Connected) then
     begin
       SaveEndToDB := false;
       exit;
     end;

   SavedToDB := false;

   for i:=0 to cKomponent-1 do
    begin
      Komponent[i].ValuePosle := GetCurrentWeight(i);
      if Komponent[i].ValuePosle < 0 then Komponent[i].ValuePosle:=0;
    end;

   ValuePosle            := Int2int64 (GetTagValue(MainCounterTagIdxHight), GetTagValue(MainCounterTagIdxLow));
   NValuePosle           := Int2int64 (GetTagValue(NMainCounterTagIdxHight), GetTagValue(NMainCounterTagIdxLow));


   if (NOT isSavedEndToDB) and isSavedBeginToDB then
   BEGIN

 try
   sql := '';
   sql := 'UPDATE '+maintablename + ' SET ';

   if mode = 4 then sql := sql + ' DTEND = ' + '''' + FormatDateTime(dt_format, now()) + ''''+', '
               else sql := sql + ' DTEND = NULL, ';

   if (mode = 1) OR (mode = 2) OR (mode = 3) OR (mode = 4) then
   begin
   for i:=0 to cKomponent-1 do
      sql := sql + ' WC'+inttostr(i+1)+'END = ' + '''' + inttostr(Komponent[i].ValuePosle) + ''''+', ';
   end;

   if (mode = 1) OR (mode = 2) OR (mode = 3) OR (mode = 4) then
   begin
   for i:=0 to cKomponent-1 do
     if Komponent[i].ValuePosle-Komponent[i].ValueDo < 0 then
           sql := sql + ' WC'+inttostr(i+1)+' = ' + '''' + '0' + ''''+', '
     else
       begin
         tmp := Komponent[i].ValuePosle - Komponent[i].ValueDo;
         if tmp >= 0 then
                        sql := sql + ' WC'+inttostr(i+1)+' = ' + '''' + inttostr(Komponent[i].ValuePosle-Komponent[i].ValueDo) + ''''+', '
                     else
                        sql := sql + ' WC'+inttostr(i+1)+' = ' + '''' + inttostr(0) + ''''+', ';  //Тут надо не минусом, а фактическую цифру

       end;

   end;

   if (mode = 3) OR (mode = 4) then
   for i:=0 to cKomponent-1 do
      begin
        if Komponent[i].TimeDosBeginComp <> 0 then sql := sql + ' DTW'+inttostr(i+1)+' = ' + '''' + FormatDateTime(dt_format, Komponent[i].TimeDosBeginComp) + ''''+', '
                                              else sql := sql + ' DTW'+inttostr(i+1)+' = NULL, ';
      end;

   if (mode = 1) OR (mode = 2) OR (mode = 3) OR (mode = 4) then
   begin
     tmp := ValuePosle - ValueDo;
     if tmp >= 0 then
                        sql := sql + ' WP = '    +  inttostr(ValuePosle - ValueDo) + ', '
                 else
                        sql := sql + ' WP = '    +  inttostr(0) + ', ';

   sql := sql + ' WPEND = ' +  inttostr(ValuePosle)  + ', ';
   sql := sql + ' NPEND = ' +  inttostr(NValuePosle) + ' '; // <---!!!!
   end;

   sql := sql + ' WHERE ID =' +inttostr(id_rec)+ '';

   if debug_mode then log('Добавляем запись об окончании дозирования в БД:'+sql);

   qry.SQL.text:=sql;
   qry.Transaction.StartTransaction;
   qry.ExecQuery;
   if debug_mode then log ('Затронуло '+inttostr(qry.rowsaffected)+' ячеек');

   if qry.rowsaffected = 1 then SavedToDB := true;



   Qry.Transaction.Commit;
   qry.Close;
   qry.FreeHandle;

   isSavedEndToDB  := true;
 except
   SavedToDB := false;
   log (DateTimeToStr(now) + 'Провал запроса: '+sql);
   ExceptionClose;

 end;

   Sost := 0;

   s := #10 + #13 + 'Отвесили' + #10 + #13;

   for i:=0 to cKomponent-1 do
     begin
       s := s + Komponent[i].name + ' ' + inttostr(Komponent[i].ValuePosle-Komponent[i].ValueDo) + ' ' + Komponent[i].Razmernost + #10 + #13;
     end;

   s :=  s + 'итого смеси' + ' ' + inttostr(ValuePosle - ValueDo) + ' ' + Komponent[0].Razmernost + #10 + #13;
   if NValuePosle > NValueDo then
      s :=  s + 'номер навески' + ' ' + inttostr(NValuePosle) + ' ' + #10 + #13;

   if SavedToDB then s := s + 'Данные сохранены в БД'
                else s := s + 'Данные не сохранены БД';

   if NOT SavedToDB then
                begin
                  log ('ERROR: Не получается записать отвес:' + sql);
                  SaveEndToDB := false;
                  exit;
                end;


   if MesShow then
     begin
       if mode=4 then ShowMessage('Дозирование закончилось успешно' + s)
                 else ShowMessage('Дозирование закончилось аварийно' + s);
     end;

   result := SavedToDB;

   END else result := true;

end;


function TDozatorNKomp.CheckCanStart : boolean;
var w : boolean;
begin
  w:=true;

  w := w AND rvgLogIn AND Connected
       AND (GetTagValue(ErrorFlagIdx) = 0) AND (GetTagValue(SostTagIdx) = 0) AND (Sost = 0);

  if ((DataClient.port.ConnectBad=1) and (DataClient.Connected)) then  w:=false;

  CheckCanStart := w;
end;


procedure TDozatorNKomp.Start(
                         wesS : string;
                         bunkS : string;
                         prod : integer;
                         brig : integer;
                         dstBunk : integer;
                         MixT : integer
                      );
var i, j, k : integer;
    s, sql:string;
    t : TDateTime;
    np : int64;

    SavedToDB : boolean;

    cval : array of int64;
    pval, nval : int64;

    v: variant;
    w, needremember, needforgot, isclear :boolean;
    smnum:integer;
begin

  if NOT WES.Connected then Disconnect;
  if (not rvgLogIn) or (NOT Connected) then Exit;
  if ((DataClient.port.ConnectBad=1) and (DataClient.Connected)) then  exit;

  if GetTagValue(ErrorFlagIdx) <> 0 then Exit;

  if GetTagValue(SostTagIdx) <> 0 then
    begin
      case GetTagValue(SostTagIdx) of
        5:  ShowMessage('Дозатор в состоянии Авария. Устраните аварию и выполните сброс.');
        else
           ShowMessage('Дозатор работает, дождитесь окончания работы');
      end;
      exit;
    end;


  if Sost <> 0 then
    begin
      ShowMessage('Дозирование уже запущено, дождитесь завершения или сделайте сброс');
      exit;
    end;

  j := 0;
  k := 0;

  isSavedBeginToDB  := false;
  isSavedEndToDB    := false;

  MixTime := MixT;

  // Считать счетчики и задание
  for i:=0 to cKomponent-1 do
    begin
      if debug_mode then  log ('До инициализации ValueDo['+inttostr(i)+']=' + inttostr(Komponent[i].ValueDo));
      Komponent[i].ValueDo    := GetCurrentWeight(i);
      Komponent[i].ValuePosle := Komponent[i].ValueDo;
      if debug_mode then log ('После инициализации ValueDo['+inttostr(i)+']=' + inttostr(Komponent[i].ValueDo));


      Komponent[i].TimeDosBeginComp := 0;
      Komponent[i].TimeDosEndComp := 0;

      Komponent[i].NeedUseFake := false;

      s:= '';
      j := j + 1;
      while (wesS[j]<>';') and (j<=length(wesS)) do
        begin
          s := s + wesS[j];
          j:=j+1;
        end;
      Komponent[i].ValueNeed  := StrToInt64 (s);

      s:= '';
      k := k + 1;
      while (bunkS[k]<>';') and (k<=length(bunkS)) do
        begin
          s := s + bunkS[k];
          k:=k+1;
        end;
      Komponent[i].Bunk  := StrToInt (s);
    end;

  ValueDo               := Int2int64 (GetTagValue(MainCounterTagIdxHight), GetTagValue(MainCounterTagIdxLow));
  ValuePosle            := ValueDo;

  NValueDo              := Int2int64 (GetTagValue(NMainCounterTagIdxHight), GetTagValue(NMainCounterTagIdxLow));
  NValuePosle           := NValueDo;

  np := 0;
  for i:=0 to cKomponent-1 do
      np := np + Komponent[i].ValueNeed;

  ValueNeed             := np;
  Bunk                  := dstBunk;


//====================================================================================
//        Записываем в БД "потери".
//====================================================================================
  //
   // тут считать последний элемен со счетчиком и найти разницу с текущим значением и
   // если она есть, то добавить приращение как расход.

    w := false;
    try
      sql := 'SELECT ';
      for i:=0 to cKomponent-1 do  sql := sql + ' WC' + inttostr(i+1)+'END,';
      sql := sql + ' WPEND, NPEND, DTEND ';
      sql := sql + 'FROM '+maintablename + ' WHERE (DTSTART=(SELECT MAX(DTSTART) FROM '+maintablename+' WHERE IDM='+inttostr(modulID)+')) AND (IDM='+inttostr(modulID)+')';

      qry.SQL.text := sql;
      qry.Transaction.StartTransaction;
      qry.ExecQuery;

      if qry.Eof then begin
      // фиг
      end else begin
        SetLength (cval, cKomponent);
        for i:=0 to cKomponent-1 do
          cval[i] := 0;

        pval := 0;
        nval := 0;
        isclear := true;

        while not qry.Eof do
          begin
             needremember := false;
             needforgot   := false;

             if isclear then needremember := true
                        else
                begin
                  //Если уже что то заполнено надо думать...

                  for i:=0 to cKomponent-1 do
                    if cval[i] < qry.Fields[i].AsInt64
                     then begin needremember := true; break; end
                     else if cval[i] > qry.Fields[i].AsInt64 then needforgot := true;

                  i := cKomponent;

                  if (NOT needremember) AND (NOT needforgot) then
                    if pval < qry.Fields[i+0].AsInt64
                     then begin needremember := true; break; end
                     else if pval > qry.Fields[i+0].AsInt64 then needforgot := true;


                  if (NOT needremember) AND (NOT needforgot) then
                    if nval < qry.Fields[i+1].AsInt64
                     then begin needremember := true; break; end
                     else if nval > qry.Fields[i+1].AsInt64 then needforgot := true;

                end;

             if (needremember) and (NOT needforgot) then
                begin
                   for i:=0 to cKomponent-1 do
                     cval[i] := qry.Fields[i].AsInt64;

                   i := cKomponent;
                   pval := qry.Fields[i+0].AsInt64;
                   nval := qry.Fields[i+1].AsInt64;
                   //t    := qry.Fields[i+2].AsDateTime;
                   isclear := false;
                end;

             qry.Next;
          end;

        if NOT isclear then
           begin
             for i:=0 to cKomponent-1 do
             if Komponent[i].ValueDo <> cval[i] then w:=true;

             if ValueDo <> pval then w:=true;
             if NValueDo <> nval then w:=true;
           end;
      end;
    Qry.Transaction.Commit;
    qry.Close;
    qry.FreeHandle;


  except
    log (DateTimeToStr(now) + ' Провал запроса: ' + sql);
    ExceptionClose;
    cval := nil;
    w:=false;
  end;


    //------------------------------------------------------------------
    // Если есть отличия, то делаем вставыш...
    if w then
      begin
         SavedToDB:=false;
        try
          if debug_mode then log('Отличия обнаружены, делаем вставку утраты');
          t := now; //дозируем сей момент

          sleep (1200);

          sql:='';
          sql := 'INSERT INTO '+maintablename + ' (IDM, DTSTART, PERTYPE, PERIOD, ';

          for i:=0 to cKomponent-1 do  sql := sql + ' DTW' + inttostr(i+1)+',';
          sql := sql + ' DTEND,';

          for i:=0 to cKomponent-1 do  sql := sql + ' PLANWC' + inttostr(i+1)+',';

          for i:=0 to cKomponent-1 do  sql := sql + ' WC' + inttostr(i+1)+'BEG,';
          for i:=0 to cKomponent-1 do  sql := sql + ' WC' + inttostr(i+1)+'END,';
          for i:=0 to cKomponent-1 do  sql := sql + ' WC' + inttostr(i+1)+',';

          sql := sql + ' WPBEG, WPEND, WP, NPBEG, NPEND,';

          for i:=0 to cKomponent-1 do  sql := sql + ' BUNKC' + inttostr(i+1)+',';
          sql := sql + ' BUNKP, ';

          sql := sql + ' UNKNOW ) VALUES (';

          sql := sql + inttostr(modulID)+', ';
          sql := sql + '''' + FormatDateTime(dt_format, t) + ''', ';
          sql := sql + '1, ';                              // пока всегда 1 смена
          sql := sql + IntToStr(GetTimeShtamp(t,1)) + ','; // пока всегда 1 смена

          for i:=0 to cKomponent-1 do
             sql := sql + '''' + FormatDateTime(dt_format, t) + ''', '; // компоненты дозир одновременно
          sql := sql + '''' + FormatDateTime(dt_format, t) + ''', ';    //конец

          for i:=0 to cKomponent-1 do
             sql := sql + '0, ';                              // планируем отвесить 0 кг

          for i:=0 to cKomponent-1 do
             sql := sql + inttostr(cval[i])+', ';             // страрые значения

          for i:=0 to cKomponent-1 do
             sql := sql + ' ' + inttostr(Komponent[i].ValueDo)+', '; // новые значения

          for i:=0 to cKomponent-1 do
               sql := sql + ' ' + inttostr(Komponent[i].ValueDo-cval[i])+', '; // разница


          sql := sql + inttostr(pval)+', ';             // страрые значения
          sql := sql + Inttostr(ValueDo)+ ', ';
          sql := sql + Inttostr(ValueDo-pval)+ ', ';

          sql := sql + inttostr(nval)+', ';             // страрые значения
          sql := sql + Inttostr(NValueDo)+ ', ';

          for i:=0 to cKomponent-1 do
               sql := sql + ' ' + inttostr(0)+', '; // номера всех бункеров 0

          sql := sql + ' ' + inttostr(0)+', '; // номера всех бункеров 0

          sql := sql + '1';
          sql := sql + ')';

          if debug_mode then log('Добавляем запись о начале дозирования в БД:'+sql);

          qry.SQL.text:=sql;
          qry.Transaction.StartTransaction;
          qry.ExecQuery;
          if debug_mode then log ('Затронуло '+inttostr(qry.rowsaffected)+' ячеек');

          if qry.rowsaffected = 1 then SavedToDB := true;

          if NOT SavedToDB then log ('Корректно не сработал запрос:' + sql);

          Qry.Transaction.Commit;
          qry.Close;
          qry.FreeHandle;

          cval := nil;

  except
     log (DateTimeToStr(now) + 'Провал запроса: '+sql);
     ExceptionClose;
     cval := nil;
  end;
      end;
    //------------------------------------------------------------------
//====================================================================================



//====================================================================================
//        Записываем в БД маркер начала дозирования
//====================================================================================
    SavedToDB := false;
   try

    id_rec:=-1;

    sql:='SELECT GEN_ID(gen_'+maintablename+'_id, 1) AS ID FROM RDB$DATABASE';

    if debug_mode then log('Получаем id для новой записи:'+sql);

    v :=  qry.Database.QueryValue(sql, 0);

    if VarType(v) <> varBoolean then
      begin
        id_rec := v;
      end
    else
      begin
        raise Exception.Create('GenerateId');
        id_rec := -1;
      end;

    if id_rec < 0 then
       begin
         log ('Ошибка получения id генератора');
         ShowMessage('Немогу сгенерировать id');
         exit;
       end;

    t := now;
    smnum := GetSmenaNumFromList (ModulList[dozatorMdlidx].smena , t);

    sql:='';
    sql := 'INSERT INTO '+maintablename + ' (ID, IDM, DTSTART, PERTYPE, PERIOD, ';
    for i:=0 to cKomponent-1 do  sql := sql + ' PLANWC' + inttostr(i+1)+',';
    for i:=0 to cKomponent-1 do  sql := sql + ' WC' + inttostr(i+1)+'BEG,';

    for i:=0 to cKomponent-1 do  sql := sql + ' WC' + inttostr(i+1)+'END,';

    for i:=0 to cKomponent-1 do  sql := sql + ' WC' + inttostr(i+1)+',';

    sql := sql + ' WPBEG, WPEND, WP, NPBEG, NPEND, ';
    for i:=0 to cKomponent-1 do  sql := sql + ' BUNKC' + inttostr(i+1)+',';
    sql := sql + ' BUNKP, IDPROD, IDBRIG, UNKNOW, MIXT ) VALUES (';
    sql := sql + IntToStr(v)+', ';
    sql := sql + inttostr(modulID)+', ';
    sql := sql + '''' + FormatDateTime(dt_format, t) + ''', ';

    if smnum>=0 then
        begin
          sql := sql + inttostr(smnum)+', ';                    // пока всегда 1 смена
          sql := sql + IntToStr(GetTimeShtamp(t, smnum)) + ','; // пока всегда 1 смена
        end
                else
        begin
          sql := sql + inttostr(0)+', ';                    // пока всегда 1 смена
          sql := sql + IntToStr(GetTimeShtamp(t, 0)) + ','; // пока всегда 1 смена
        end;

    for i:=0 to cKomponent-1 do  sql := sql + ' ' + inttostr(Komponent[i].ValueNeed)+', ';
    for i:=0 to cKomponent-1 do  sql := sql + ' ' + inttostr(Komponent[i].ValueDo)+', ';
    for i:=0 to cKomponent-1 do  sql := sql + ' ' + inttostr(Komponent[i].ValuePosle)+', ';


    for i:=0 to cKomponent-1 do
      begin
        if Komponent[i].ValuePosle < Komponent[i].ValueDo
          then sql := sql + ' ' + inttostr(0)+', '
          else sql := sql + ' ' + inttostr(Komponent[i].ValuePosle - Komponent[i].ValueDo)+', ';
      end;


    sql := sql + Inttostr(ValueDo)+ ', ';
    sql := sql + Inttostr(ValuePosle)+ ', ';

    if ValueDo > ValuePosle
      then sql := sql + Inttostr(0)+ ', '
      else sql := sql + Inttostr(ValuePosle - ValueDo)+ ', ';

    sql := sql + Inttostr(NValueDo)+ ', ';
    sql := sql + Inttostr(NValuePosle)+ ', ';


    for i:=0 to cKomponent-1 do  sql := sql + ' ' + inttostr(Komponent[i].Bunk)+', ';
    sql := sql + Inttostr(Bunk)+ ', ';
    sql := sql + inttostr(prod)+', '; //кода
    sql := sql + inttostr(brig)+','; //кода
    sql := sql + '0,';
    sql := sql + inttostr(MixT);
    sql := sql + ')';

    if debug_mode then log('Добавляем запись о начале дозирования в БД:'+sql);

    qry.SQL.text:=sql;
    qry.Transaction.StartTransaction;
    qry.ExecQuery;
    if debug_mode then log ('Затронуло '+inttostr(qry.rowsaffected)+' ячеек');

    if qry.rowsaffected = 1 then SavedToDB := true;

    Qry.Transaction.Commit;
    qry.Close;
    qry.FreeHandle;


    isSavedBeginToDB := SavedToDB AND (id_rec>=0);


  except
    SavedToDB := false;
    isSavedBeginToDB := false;
    log (DateTimeToStr(now) + 'Провал запроса: '+sql);
    id_rec := -1;
    ExceptionClose;
  end;
//====================================================================================
  if NOT SavedToDB
    then
      begin
        ShowMessage('Ошибка, не могу запуститься. Ошибка сохранения в БД');
        exit;
      end;

  cnt  := 0;

  if (GetTagValueByName(StartTag)<>StartValue) then
    begin
       // Отсылка реальной команды старта
       SetTagValueByName(StartTag, StartValue);
       Sost := 2;
    end                                        else
    begin
       // Отсылка фальшивой команды старта
       SetTagValueByName(StartTag, 2);
       Sost := 1;
    end;


end;


procedure TDozatorNKomp.Process;
var
  i, tmp : Integer;
  w, SavedToDB : boolean;
  new_Sost1, new_Sost2, new_Sost3 : integer;
begin
  inherited;
  if not rvgLogIn then Exit;

  if GetTagValue(ErrorFlagIdx) <> 0 then Exit;

  new_Sost1 := GetTagValue(SostTagIdx);
  new_Sost2 := GetTagValue(SostTagIdx2);
  new_Sost3 := GetTagValue(SostTagIdx3);

  if Sost = 0 then exit; //Если мы не работаем, какая разница что там происходит

  if debug_mode then log ('Режим работы:'+ inttostr(Sost)+ '.     Sost=' + inttostr(new_Sost1) + '  AdvSost=' + inttostr(new_Sost2) + '  Conponent=' + inttostr(new_Sost3));

  case Sost of
     1 : begin
           if (new_Sost1 = 1) OR (new_Sost1 = 2) OR (new_Sost1 = 3) OR
             (new_Sost1 = 4) OR (new_Sost1 = 5) OR (new_Sost1 = 6) OR (new_Sost1 = 7) then
              begin
                //Авария. Закрываем пустыми цифрами, только номер отвеса сохраяем
                SaveEndToDB (1);
              end;

           if (GetTagValueByName(StartTag) <> StartValue) then
              begin
                // Отсылка реальной команды старта
                SetTagValueByName(StartTag, StartValue);
                Sost := 2;
              end                                       else
              begin
                // Отсылка фальшивой команды старта, повторно
                SetTagValueByName(StartTag, 2);
                Sost := 1;
              end;


         end;


     2 : begin
           if (new_Sost1 = 1) OR (new_Sost1 = 2) OR (new_Sost1 = 3) OR (new_Sost1 = 5) OR (new_Sost1 = 6) OR (new_Sost1 = 7) then
              begin
                //Авария. Закрываем пустыми цифрами, только номер отвеса сохраяем
                SaveEndToDB (1);
              end;

           if new_Sost1 = 4 then
             begin
               // Тут проверить, что надо его вообще устанавливать....
               w := true;
               for i:=0 to cKomponent-1 do
                 begin
                   if (GetTagValue(Komponent[i].ReceiptTagIdxHight) <> Int642Int(Komponent[i].ValueNeed, true )) OR
                      (GetTagValue(Komponent[i].ReceiptTagIdxLow)   <> Int642Int(Komponent[i].ValueNeed, false)) then
                        begin  w:=false; break;  end;
                 end;

               if w then begin Sost := 4; end
                    else
                      begin
                        // Если надо тогда...
                        //====================================================================================
                        //            Установка рецепта
                        //====================================================================================
                        for i:=0 to cKomponent-1 do
                          begin
                            Komponent[i].FakeReceipt1 := 1;
                            while not ((Komponent[i].FakeReceipt1 > 0) and
                                       (Komponent[i].FakeReceipt1 <> GetTagValue(Komponent[i].ReceiptTagIdxHight)) and
                                       (Komponent[i].FakeReceipt1 <> Int642Int(Komponent[i].ValueNeed, true))) do
                               begin
                                 Komponent[i].FakeReceipt1 := 1 + Random(9);
                               end;

                            Komponent[i].FakeReceipt2 := 1;
                            while not ((Komponent[i].FakeReceipt2 > 0) and
                                       (Komponent[i].FakeReceipt2 <> GetTagValue(Komponent[i].ReceiptTagIdxLow)) and
                                       (Komponent[i].FakeReceipt2 <> Int642Int(Komponent[i].ValueNeed, false))) do
                               begin
                                 Komponent[i].FakeReceipt2 := 1 + Random(9);
                               end;

                            SetTagValue(Komponent[i].ReceiptTagIdxHight, Komponent[i].FakeReceipt1);
                            SetTagValue(Komponent[i].ReceiptTagIdxLow,   Komponent[i].FakeReceipt2);
                          end;
                        Sost := 3;
                      end;

               if GetTagValue(MixTagIdx) <> MixTime
                 then SetTagValue(MixTagIdx, MixTime);
               //====================================================================================

             end;

         end;

     3 : // Фальшивый рецепт послали, ждем когда он установится
         begin
           if (new_Sost1 = 0) OR (new_Sost1 = 1) OR (new_Sost1 = 2) OR (new_Sost1 = 3) OR (new_Sost1 = 5) OR (new_Sost1 = 6) OR (new_Sost1 = 7) then
              begin
                //Авария. Закрываем пустыми цифрами, только номер отвеса сохраяем
                SaveEndToDB (1);
              end;

           //====================================================================================
           //            Проверка установки рецепта
           //====================================================================================
           w := true;
           for i:=0 to cKomponent-1 do
             begin
               if (GetTagValue(Komponent[i].ReceiptTagIdxHight) <> Komponent[i].FakeReceipt1) OR
                  (GetTagValue(Komponent[i].ReceiptTagIdxLow) <> Komponent[i].FakeReceipt2)
                  then
                     begin
                       //Фи, не все так просто....
                       if (GetTagValue(Komponent[i].ReceiptTagIdxHight) <> Komponent[i].FakeReceipt1) OR
                            (GetTagValue(Komponent[i].ReceiptTagIdxLow) <> Komponent[i].FakeReceipt2)
                       then
                         begin
                          SetTagValue(Komponent[i].ReceiptTagIdxHight, Komponent[i].FakeReceipt1);
                          SetTagValue(Komponent[i].ReceiptTagIdxLow,   Komponent[i].FakeReceipt2);
                         end else
                         begin
                           // Это просто PZDc...
                           tmp := 1;

                           while NOT ((tmp <> Komponent[i].FakeReceipt1) AND
                                      (tmp <> Int642Int(Komponent[i].ValueNeed, true)) AND
                                      (tmp <> GetTagValue(Komponent[i].ReceiptTagIdxHight))) do
                              tmp:= 1 + random (9);
                           Komponent[i].FakeReceipt1 := tmp;

                           tmp := 1;
                           while NOT ((tmp <> Komponent[i].FakeReceipt2) AND
                                      (tmp <> Int642Int(Komponent[i].ValueNeed, false)) AND
                                      (tmp <> GetTagValue(Komponent[i].ReceiptTagIdxLow))) do
                              tmp:= 1 + random (9);
                           Komponent[i].FakeReceipt2 := tmp;

                           SetTagValue(Komponent[i].ReceiptTagIdxHight, Komponent[i].FakeReceipt1);
                           SetTagValue(Komponent[i].ReceiptTagIdxLow,   Komponent[i].FakeReceipt2);
                         end;
                       w := false;

//                          w := false;
//                          SetTagValue(Komponent[i].ReceiptTagIdxHight, Komponent[i].FakeReceipt1);
//                          SetTagValue(Komponent[i].ReceiptTagIdxLow,   Komponent[i].FakeReceipt2);
                     end;
             end;

           if GetTagValue(MixTagIdx) <> MixTime
              then
                begin
                  w := false;
                  SetTagValue(MixTagIdx, MixTime);
                end;


           if w then
              begin
                for i:=0 to cKomponent-1 do
                  begin
                    SetTagValue(Komponent[i].ReceiptTagIdxHight, Int642Int(Komponent[i].ValueNeed, true));
                    SetTagValue(Komponent[i].ReceiptTagIdxLow,   Int642Int(Komponent[i].ValueNeed, false));
                  end;

                Cnt := 0;
                Sost := 4;
              end else
              begin
                cnt := cnt + 1;
                if cnt > 40 then
                  begin
                     if debug_mode then log ('Подвисла установка рецепта. ' + inttostr(cnt));
                  end;
              end;


           //====================================================================================
         end;


     4 : // Рецепт послали, ждем когда он установится
         begin
           if (new_Sost1 = 0) OR (new_Sost1 = 1) OR (new_Sost1 = 2) OR (new_Sost1 = 3) OR (new_Sost1 = 5) OR (new_Sost1 = 6) OR (new_Sost1 = 7) then
              begin
                //Авария. Закрываем пустыми цифрами, только номер отвеса сохраяем
                SaveEndToDB (1);
              end;

           //====================================================================================
           //            Проверка установки рецепта
           //====================================================================================
           w := true;
           for i:=0 to cKomponent-1 do
             begin
               if (GetTagValue(Komponent[i].ReceiptTagIdxHight) <> Int642Int(Komponent[i].ValueNeed, true)) OR
                  (GetTagValue(Komponent[i].ReceiptTagIdxLow) <> Int642Int(Komponent[i].ValueNeed, false))
                  then
                    begin

                       if (GetTagValue(Komponent[i].ReceiptTagIdxHight) <> Int642Int(Komponent[i].ValueNeed, true)) and
                          (GetTagValue(Komponent[i].ReceiptTagIdxLow) <> Int642Int(Komponent[i].ValueNeed, false))
                       then
                         begin
                           SetTagValue(Komponent[i].ReceiptTagIdxHight, Int642Int(Komponent[i].ValueNeed, true));
                           SetTagValue(Komponent[i].ReceiptTagIdxLow,   Int642Int(Komponent[i].ValueNeed, false));
                         end else
                         begin
                           // Это просто PZDc...
                           tmp := 1;

                           while NOT ((tmp <> Komponent[i].FakeReceipt1) AND
                                      (tmp <> Int642Int(Komponent[i].ValueNeed, true)) AND
                                      (tmp <> GetTagValue(Komponent[i].ReceiptTagIdxHight))) do
                              tmp:= 1 + random (9);
                           Komponent[i].FakeReceipt1 := tmp;

                           tmp := 1;
                           while NOT ((tmp <> Komponent[i].FakeReceipt2) AND
                                      (tmp <> Int642Int(Komponent[i].ValueNeed, false)) AND
                                      (tmp <> GetTagValue(Komponent[i].ReceiptTagIdxLow))) do
                              tmp:= 1 + random (9);
                           Komponent[i].FakeReceipt2 := tmp;

                           SetTagValue(Komponent[i].ReceiptTagIdxHight, Komponent[i].FakeReceipt1);
                           SetTagValue(Komponent[i].ReceiptTagIdxLow,   Komponent[i].FakeReceipt2);
                           Sost := 3;
                         end;
                       w := false;
                    end;
             end;

           if GetTagValue(MixTagIdx) <> MixTime
              then
                begin
                  w := false;
                  SetTagValue(MixTagIdx, MixTime);
                end;


           if w then
              begin
                //====================================================================================
                //            Стартануть
                //====================================================================================
                SetTagValueByName(StartTag, 6);
                //====================================================================================
                Cnt := 0;
                Sost := 5;
              end else
              begin
                cnt := cnt + 1;
                if cnt > 20 then
                  begin
                    if debug_mode then log ('Подвисла установка рецепта.. ' + inttostr(cnt));
                  end;
              end;


           //====================================================================================
         end;


     5 : //Старт отослали, ждем когда состояние сменится на работу
         begin

           if (new_Sost1 = 0) OR (new_Sost1 = 5) then
              begin
                //Авария. Закрываем пустыми цифрами, только номер отвеса сохраяем
                SaveEndToDB (2);
              end;

           if (new_Sost1 = 1) OR (new_Sost1 = 2) OR
              (new_Sost1 = 3) OR
              (new_Sost1 = 6) OR (new_Sost1 = 7)
              then
              begin
                //Пошел процесс работы, ждем
                Cnt := 0;
                Sost := 6;
              end                         else
              begin
                cnt := cnt + 1;
                SetTagValueByName(StartTag, 6);
                if debug_mode then if cnt > 20 then log ('Подвисла команда старта ' + inttostr(cnt));
             end;

         end;

     6 : //Состояние работы...
         begin

           // Следим за состоянием дозирования... если новая фаза, то сохраняем в БД
           for i:=0 to cKomponent-1 do
             begin
               if (new_Sost3 = (i+1)) and (Komponent[i].TimeDosBeginComp = 0)
                 then
                   begin
                     Komponent[i].TimeDosBeginComp := Now;

                     if (i<>0) and (Komponent[i-1].TimeDosEndComp = 0) and (Komponent[i].TimeDosBeginComp <> 0)  then
                       begin
                         Komponent[i-1].TimeDosEndComp := Komponent[i].TimeDosBeginComp;
                       end;

                   end;
               if (i = (cKomponent-1)) and (Komponent[i].TimeDosEndComp = 0) and (old_Sost3 = cKomponent) and (new_Sost3 <> old_Sost3)
                 then  Komponent[i].TimeDosEndComp := now;
             end;


           if (new_Sost1 = 5) then
              begin
                //Авария. Закрываем цифрами по максимуму
                SaveEndToDB (3);
              end;

           if (new_Sost1 = 6) OR (new_Sost1 = 7) then
             begin
               SavedToDB := SaveEndToDB (4);
             end;


           //Если сработал стоп...
           if new_Sost1 = 0 then // возможно надо добавить еще и выход по аварии
             begin
               //Процесс работы, закончился
               //Процесс занял Cnt / 2 секунд

               //====================================================================================
               //        Записываем в БД маркер конца дозирования
               //====================================================================================
               SavedToDB := SaveEndToDB (4);


               if NOT SavedToDB then
                   SavedToDB := SaveEndToDB (4);

               Cnt := 0;
               Sost := 0;

               if NOT SavedToDB then
                  exit;

             end else // Если состояние не стоп...
             begin
               cnt := cnt + 1;
             end;

         end;


  else   // Фиг знает какое состояние
    begin
       if debug_mode then log('Неизвестное состояние'+inttostr(Sost));
    end;
  end;

 old_Sost1 := GetTagValue(SostTagIdx);
 old_Sost2 := GetTagValue(SostTagIdx2);
 old_Sost3 := GetTagValue(SostTagIdx3);

end;

end.
