unit ArcViewer;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, pFIBDatabase, StdCtrls, ExtCtrls,
  DbChart, ComCtrls, ActnList, ToolWin, ActnMan, ActnCtrls,
  XPStyleActnCtrls, FIBDatabase, DB, FIBDataSet, pFIBDataSet,
  avBase, janXMLParser2, ImgList, Menus, Buttons, frxClass,
  frxCross;

const
  fix_col = 3;

type
  TavSQL = record
    Arcname: string;
    Text: string;
    rec: integer;
    dt: TDatetime;
  end;

type
  TArcViewerForm = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Splitter1: TSplitter;
    tree: TTreeView;
    ActionManager1: TActionManager;
    ActionToolBar1: TActionToolBar;
    ActionToolBar2: TActionToolBar;
    acGroupAdd: TAction;
    acGroupDel: TAction;
    acGroupEdit: TAction;
    acTrendGroupNew: TAction;
    Splitter2: TSplitter;
    listNav: TListView;
    acUpdate: TAction;
    list: TListView;
    ds: TpFIBDataSet;
    trn: TpFIBTransaction;
    ImageList1: TImageList;
    acPrint: TAction;
    acBack: TAction;
    acForward: TAction;
    acOnLine: TAction;
    acMemPeriod: TAction;
    acRstPeriod: TAction;
    acGoto: TAction;
    Timer: TTimer;
    PrinterSetupDialog: TPrinterSetupDialog;
    acGroupClone: TAction;
    Panel3: TPanel;
    ActionToolBar3: TActionToolBar;
    acStrokaAdd: TAction;
    acStrokaDel: TAction;
    acStrokaEdit: TAction;
    acStrokaClone: TAction;
    acVisualizators: TAction;
    Panel4: TPanel;
    pnlCurDT: TPanel;
    Panel5: TPanel;
    btFwdHour: TSpeedButton;
    btFwdMin10: TSpeedButton;
    btFwdMin: TSpeedButton;
    btFwdSec10: TSpeedButton;
    btFwdSec: TSpeedButton;
    btBckDay: TSpeedButton;
    btBckHour: TSpeedButton;
    btBckMin10: TSpeedButton;
    btBckMin: TSpeedButton;
    btBckSec10: TSpeedButton;
    btBckSec: TSpeedButton;
    btFwdDay: TSpeedButton;
    trn_upd: TpFIBTransaction;
    PopupMenu1: TPopupMenu;
    N8: TMenuItem;
    N10: TMenuItem;
    N11: TMenuItem;
    N22: TMenuItem;
    N23: TMenuItem;
    PopupMenu2: TPopupMenu;
    PopupMenu3: TPopupMenu;
    N24: TMenuItem;
    N25: TMenuItem;
    N26: TMenuItem;
    N27: TMenuItem;
    N28: TMenuItem;
    N29: TMenuItem;
    N30: TMenuItem;
    N31: TMenuItem;
    N32: TMenuItem;
    N33: TMenuItem;
    N34: TMenuItem;
    N35: TMenuItem;
    N36: TMenuItem;
    procedure FormDestroy(Sender: TObject);
    procedure acGroupAddEditExecute(Sender: TObject);
    procedure treeChange(Sender: TObject; Node: TTreeNode);
    procedure acTrendGroupNewExecute(Sender: TObject);
    procedure acUpdateExecute(Sender: TObject);
    procedure acBackForwardExecute(Sender: TObject);
    procedure TimerTimer(Sender: TObject);
    procedure acOnLineExecute(Sender: TObject);
    procedure acGotoExecute(Sender: TObject);
    procedure listAdvancedCustomDrawSubItem(Sender: TCustomListView;
      Item: TListItem; SubItem: Integer; State: TCustomDrawState;
      Stage: TCustomDrawStage; var DefaultDraw: Boolean);
    procedure acMemPeriodExecute(Sender: TObject);
    procedure acRstPeriodExecute(Sender: TObject);
    procedure treeDragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure treeDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure acGroupDelExecute(Sender: TObject);
    procedure acPrintExecute(Sender: TObject);
    procedure acStrokaAddExecute(Sender: TObject);
    procedure acStrokaDelExecute(Sender: TObject);
    procedure acVisualizatorsExecute(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure acStrokaCloneExecute(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btFwdSecClick(Sender: TObject);
  private
    SQL: array of TavSQL;
  public
    Visulizators: TVisulizators;

    CurGroup: TavGroup;
    CurDT: TDatetime;
    MemDt: TDatetime;

    db: TpFIBDatabase;
    fname: string;
    Readonly: boolean;

    procedure Init;
    procedure Load;
    procedure Save;
  end;


implementation
uses
  avGroupProp,
  avTagList,
  avStrokaProp,
  avVisualizators,
  avGoto,
  avClone,
  avPrint,
  hyperstr,
  DateUtils;

{$R *.dfm}

{ TArcViewerForm }

procedure TArcViewerForm.FormCreate(Sender: TObject);
begin
  Visulizators := TVisulizators.Create;
  DoubleBuffered := true;
end;

////////////////////////////////////////////////////////////////////////////////
// DESTROY
////////////////////////////////////////////////////////////////////////////////
procedure TArcViewerForm.FormDestroy(Sender: TObject);
var
  i: integer;
begin
  for i:=0 to tree.Items.Count-1 do
    TavGroup(tree.Items[i].Data).Free;

  Visulizators.Free;  
end;

////////////////////////////////////////////////////////////////////////////////
// INIT
////////////////////////////////////////////////////////////////////////////////
procedure TArcViewerForm.Init;
begin
  // óñòàíîâêà DB
  ds.Database := db;
  ds.Transaction := trn;
  ds.UpdateTransaction := trn_upd;
  ds.Transaction.DefaultDatabase := db;
  ds.UpdateTransaction.DefaultDatabase := db;

  Load;

  if Readonly then begin
    acGroupAdd.Enabled := false;
    acGroupDel.Enabled := false;
    acGroupEdit.Enabled := false;
    acGroupClone.Enabled := false;
    tree.DragMode := dmManual;
    tree.Align := alClient;
    ActionToolBar1.Visible := false;
    ActionToolBar3.Visible := false;
    Panel3.Visible := false;
  end;
end;

////////////////////////////////////////////////////////////////////////////////
// LOAD
////////////////////////////////////////////////////////////////////////////////
procedure TArcViewerForm.Load;

    procedure _load_group(xnode: TjanXMLNode2; treenode: TTreeNode);
    var
      i,q,k,j: integer;
      gr: TavGroup;
      st: TavStroka;
      tg: TavTag;
      cl: TavColumn;
      s: string;
    begin
      with xnode do begin
        gr := TavGroup.Create;
        gr.Name := text;
        val(attribute['ColWidthName'], gr.ColWidthName, q);
        val(attribute['ColWidthDescr'], gr.ColWidthDescr, q);

        treenode := tree.Items.AddChildObject(treenode, gr.Name, gr);

        with forceChildByName('Stroki') do
          for i:=0 to nodes.Count-1 do
            with TjanXMLNode2(nodes[i]) do begin
              k := length(gr.Stroki);
              SetLength(gr.Stroki, k+1);
              st := TavStroka.Create;
              gr.Stroki[k] := st;

              st.Group := gr;
              st.Name := text;
              st.Descr := forceChildByName('Descr').text;;

              with forceChildByName('Tags') do
                for j:=0 to nodes.Count-1 do
                  with TjanXMLNode2(nodes[j]) do begin
                    k := length(st.Tags);
                    SetLength(st.Tags, k+1);
                    tg := TavTag.Create;
                    st.Tags[k] := tg;

                    tg.TagName := text;
                    tg.Transform := forceChildByName('Transform').text;;
                    s := trim(forceChildByName('Visulizator').text);
                    if s<>'' then begin
                      for k:=0 to length(Visulizators.Items)-1 do
                        if s = Visulizators.Items[k].Name then begin
                          tg.Visulizator := Visulizators.Items[k];
                        end;
                    end;

                  end;
            end;

        with forceChildByName('Columns') do
          for i:=0 to nodes.Count-1 do
            with TjanXMLNode2(nodes[i]) do begin
              k := length(gr.Columns);
              SetLength(gr.Columns, k+1);
              cl := TavColumn.Create;
              gr.Columns[k] := cl;

              cl.Name := text;
              val(attribute['Width'], cl.Width, q);
              val(attribute['Alignment'], k ,q);
              cl.Alignment := TAlignment(k);
            end;

        with forceChildByName('Groups') do
          for i:=0 to nodes.Count-1 do
            _load_group( TjanXMLNode2(nodes[i]), treenode);

      end;
    end;


    procedure _load_visualizators(xnode: TjanXMLNode2);
    var
      i,q,k: integer;
      vz: TavVisulizator;
    begin
      with xnode do begin
        vz := TavVisulizator.Create;
        vz.Name := text;

        k := length(Visulizators.Items);
        SetLength(Visulizators.Items, k+1);
        Visulizators.Items[k] := vz;


        with forceChildByName('Items') do
          for i:=0 to nodes.Count-1 do
            with TjanXMLNode2(nodes[i]) do begin
              k := length(vz.Items);
              SetLength(vz.Items, k+1);
              vz.Items[i] := TavVisulizatorItem.Create;

              vz.Items[i].Condition := forceChildByName('Condition').text;
              vz.Items[i].Expression := forceChildByName('Expression').text;
              vz.Items[i].UseColor := attribute['UseColor'] = '1';
              val( attribute['FontColor'], vz.Items[i].FontColor, q );
              val( attribute['BackColor'], vz.Items[i].BackColor, q );
            end;

      end;
    end;


var
  i: integer;
  dom: TjanXMLParser2;
  node: TjanXMLNode2;
begin
  dom := TjanXMLParser2.create;
  try
    dom.LoadXML(fname);

    tree.Items.Clear;
    tree.Items.Add(nil, 'Ãðóïïû');

    node := dom.forceChildByName('Visualizators');
    for i:=0 to node.nodes.Count-1 do begin
      _load_visualizators( TjanXMLNode2(node.nodes[i]) );
    end;

    node := dom.forceChildByName('Groups');
    for i:=0 to node.nodes.Count-1 do begin
      _load_group( TjanXMLNode2(node.nodes[i]), tree.Items[0]);
    end;


  finally
    dom.Free;
  end;

  tree.AlphaSort;
end;

////////////////////////////////////////////////////////////////////////////////
// SAVE
////////////////////////////////////////////////////////////////////////////////
procedure TArcViewerForm.Save;

    procedure _save_group(xnode: TjanXMLNode2; treenode: TTreeNode);
    var
      i,j: integer;
      gr: TavGroup;
      st: TavStroka;
      tg: TavTag;
      cl: TavColumn;
      node: TjanXMLNode2;
    begin
      gr := TavGroup(treenode.Data);
      with xnode.addChildByName('g') do begin

        text := gr.Name;
        attribute['ColWidthName'] := inttostr(gr.ColWidthName);
        attribute['ColWidthDescr'] := inttostr(gr.ColWidthDescr);

        with addChildByName('Stroki') do
          for i:=0 to length(gr.Stroki)-1 do
            with addChildByName('s') do begin
              st := gr.stroki[i];
              text := st.Name;
              addChildByName('Descr').text := st.Descr;

              with addChildByName('Tags') do
                for j:=0 to length(st.Tags)-1 do
                  with addChildByName('t') do begin
                    tg := st.Tags[j];
                    text := tg.TagName;
                    addChildByName('Transform').text := tg.Transform;
                    if tg.Visulizator<>nil then
                      addChildByName('Visulizator').text := tg.Visulizator.Name;
                  end;
            end;

        with addChildByName('Columns') do
          for i:=0 to length(gr.Columns)-1 do
            with addChildByName('c') do begin
              cl := gr.Columns[i];
              text := cl.Name;
              attribute['Width'] := inttostr(cl.Width);
              attribute['Alignment'] := inttostr(ord(cl.Alignment));
            end;

        node := addChildByName('Groups');
        with node do
          for i:=0 to treenode.Count-1 do
            if treenode.Item[i].Data<>nil then
              if TObject(treenode.Item[i].Data).ClassType = TavGroup then
                _save_group(node, treenode.Item[i]);

      end;
    end;


    procedure _save_visualizators(xnode: TjanXMLNode2; M: TavVisulizator);
    var
      i: integer;
    begin
      with xnode.addChildByName('v') do begin
        text := M.Name;

        with addChildByName('Items') do
          for i:=0 to length(M.Items)-1 do
            with addChildByName('i') do begin
              addChildByName('Condition').text := M.Items[i].Condition;
              addChildByName('Expression').text := M.Items[i].Expression;
              attribute['UseColor'] := iif(M.Items[i].UseColor, '1', '');
              attribute['FontColor'] :=  inttostr( M.Items[i].FontColor );
              attribute['BackColor'] :=  inttostr( M.Items[i].BackColor );
            end;
      end;
    end;


var
  i: integer;
  dom: TjanXMLParser2;
  node: TjanXMLNode2;
begin
  dom := TjanXMLParser2.create;
  try

    dom.name := 'root';

    node := dom.addChildByName('Visualizators');
    for i:=0 to length(Visulizators.Items)-1 do
      _save_visualizators( node, Visulizators.Items[i] );

    node := dom.addChildByName('Groups');
    for i:=0 to tree.Items[0].Count-1 do
      _save_group( node, tree.Items[0].Item[i] );

    dom.SaveXML(fname);
  finally
    dom.Free;
  end;

end;


////////////////////////////////////////////////////////////////////////////////
// ADD / EDIT GROUP
////////////////////////////////////////////////////////////////////////////////
procedure TArcViewerForm.acGroupAddEditExecute(Sender: TObject);
var
  newflag: boolean;
  w: TavGroupPropForm;
  T: TTreeNode;
begin

  if avTagListForm=nil then begin
    avTagListForm := TavTagListForm.Create(self);
    avTagListForm.db := db;
    avTagListForm.Init;
  end;

  newflag := Sender = acGroupAdd;

  if tree.Selected=nil then tree.Selected := tree.Items[0];

  if not newflag then
    if tree.Selected.Data = nil then exit;

  w := TavGroupPropForm.Create(self);
  try

    if newflag then
      w.M := nil
    else
      w.M := TavGroup( tree.Selected.data );

    if w.ShowModal=mrOk then begin
      if newflag then begin
        T := tree.Items.AddChildObject(tree.Selected, w.M.Name, w.M);
      end else
        T := tree.Selected;

      T.Text := w.M.Name;
      Save;
    end;
  finally
    w.Free;
  end;

//  treeChange(nil,tree.Selected);
end;

procedure TArcViewerForm.treeChange(Sender: TObject; Node: TTreeNode);
var
  i: integer;
begin
  listNav.Items.Clear;
  if node.Data=nil then exit;
  with TavGroup(node.Data) do
    for i:=0 to length(Stroki)-1 do
      with listNav.Items.Add do begin
        Caption := Stroki[i].Name + ' '  +  Stroki[i].Descr;
        Data := Stroki[i];
      end;
end;


{
procedure TArcViewerForm.AddTagToTrend(ATag: TavTag);
//var
//  i: integer;
//  M: TtvTrendTag;
begin

    M := TtvTrendTag.Create(db, chart);
    with ATag do begin
      M.Name := Name;

      M.Descr := GetLegname;
      M.Transform := Transform;
      M.Width := Width;
      M.UseColor := UseColor;
      M.Color := Color;
      M.Stairs := Stairs;
      M.Pointers := Pointers;
    end;
    M.Init(OptimizedSelect);

    with listTrend.Items.Add do begin
      Data := M;
      Caption := M.Descr;
      SubItems.Add('');
      if M.IdTag <> -1 then
        SubItems.Add('')
      else
        SubItems.Add('íåò!');
      Checked := true;
      StateIndex := 1;
    end;

end;
}

////////////////////////////////////////////////////////////////////////////////
// Îòîáðàæåíèå ãðóïïû íà òðåíäå
////////////////////////////////////////////////////////////////////////////////
procedure TArcViewerForm.acTrendGroupNewExecute(Sender: TObject);
var
  i,j,k,n: integer;
  flag: boolean;
  st: TavStroka;
  tg: TavTag;
begin
  if not db.Connected then exit;

  if tree.Selected = nil then exit;

  tree.Selected.Expanded := not tree.Selected.Expanded;

  if tree.Selected.Data = nil then exit;
  CurGroup := TavGroup(tree.Selected.Data);

  list.Columns[0].Width := CurGroup.ColWidthName;
  list.Columns[1].Width := CurGroup.ColWidthDescr;

  n := length(CurGroup.Columns);
  while list.Columns.Count-fix_col > n do
    list.Columns.Delete(fix_col);

  for i:=0 to n-1 do begin
    if list.Columns.Count-fix_col < n then list.Columns.Add;
    list.Columns[i+fix_col].Width := CurGroup.Columns[i].Width;
    list.Columns[i+fix_col].Caption := CurGroup.Columns[i].Name;
    list.Columns[i+fix_col].Alignment := CurGroup.Columns[i].Alignment;
  end;

  list.Items.BeginUpdate;
  list.Items.Clear;
  for i:=0 to length(CurGroup.Stroki)-1 do
    with list.Items.Add do begin
      st := CurGroup.Stroki[i];
      Data := st;
      Caption := st.Name;
      SubItems.Add(st.Descr);
      SubItems.Add('-');
      for j:=0 to length(st.Tags)-1 do begin
        st.Tags[j].TransformValue(0, flag);
        SubItems.Add('-');
      end;
    end;
  list.AlphaSort;

  SQL := nil;

  ds.SelectSQL.Text := 'SELECT TAGLIST.IDTAG, TAGLIST.TAGNAME, ARCLIST.ARCNAME '+
        'FROM ARCLIST INNER JOIN TAGLIST ON (ARCLIST.IDARC = TAGLIST.IDARC) '+
        'ORDER BY TAGLIST.TAGNAME';
  try
    ds.Open;
    for i:=0 to length(CurGroup.Stroki)-1 do
      for j:=0 to length(CurGroup.Stroki[i].Tags)-1 do
      begin
        tg := CurGroup.Stroki[i].Tags[j];
        if (tg.TagName<>'-') and (ds.Locate('TAGNAME', tg.TagName, [])) then begin
          tg.IdTag := ds.fieldbyname('IDTAG').AsInteger;
          tg.ArcName := uppercase(ds.fieldbyname('ARCNAME').AsString);

          flag := false;
          for k:=0 to length(SQL)-1 do
            if SameText(SQL[k].Arcname, tg.ArcName) then begin
              flag := true;
              break;
            end;

          if not flag then begin
            k:=length(SQL);
            SetLength(SQL, k+1);
            SQL[k].Arcname := tg.ArcName;
            SQL[k].Text := '';
          end;

          SQL[k].Text := SQL[k].Text + ',T'+inttostr(tg.IdTag);

        end else
          tg.IdTag := -1;
      end;
    ds.Close;
  except
    ds.Transaction.Active:=false;
  end;



  for i:=0 to length(sql)-1 do begin
    delete(sql[i].Text, 1, 1);
  end;
  list.Items.EndUpdate;

  acUpdateExecute(nil);
end;

// UPDATE
procedure TArcViewerForm.acUpdateExecute(Sender: TObject);
var
  q,i,j,x: integer;
  tg: TavTag;
//  gr: TavGroup;
  st: TavStroka;
  fld: TField;
  s: string;
  tag_col_name: string;
  cch: boolean;
//  delta: TDatetime;
begin
  if CurGroup=nil then exit;

  if CurDT=0 then CurDT:=now;

  for q:=0 to length(SQL)-1 do begin


    try
      ds.SelectSQL.Text := 'SELECT FIRST 1 DT,REC,' + SQL[q].Text + ' FROM ' + SQL[q].Arcname +
            ' WHERE DT<=:DT ORDER BY DT DESC';
      ds.Prepare;
      ds.ParamByName('DT').AsDateTime := CurDT;
      ds.Open;

      SQL[q].dt := ds.Fields[0].AsDateTime;
      SQL[q].rec := ds.Fields[1].AsInteger;


//      list.Items.BeginUpdate;
      for i:=0 to list.Items.Count-1 do begin
        st := TavStroka(list.Items[i].Data);

        for j:=0 to length(st.Tags)-1 do begin
          tg := st.Tags[j];

          if tg.TagName<>'-' then begin
            tag_col_name := 'T' + inttostr(tg.IdTag);

            if pos( ','+tag_col_name+',' , ','+SQL[q].Text+',') > 0 then begin
              s := '';
              if tg.IdTag<>-1 then begin
                fld := ds.FindField(tag_col_name);
                if fld <> nil then begin
                  x := fld.AsInteger;

                  s := tg.TransformValue(x, cch);
                end;
              end;

              if j+fix_col < list.Columns.Count then begin

                if list.Items[i].SubItems[1] <> ds.Fields[0].AsString then
                  list.Items[i].SubItems[1] := ds.Fields[0].AsString;

                if list.Items[i].SubItems[j+fix_col-1] <> s then
                  list.Items[i].SubItems[j+fix_col-1] := s;

              end;
            end;
          end;

        end;
      end;
//      list.Items.EndUpdate;

      ds.Close;
    except
      ds.Transaction.Active:=false;
    end;

    if ds.Transaction.Active then
      ds.Transaction.Commit;
      
  end;

  pnlCurDT.Caption := DateTimeToStr(CurDT);


end;

//     BACK <==    FORWARD ==>
procedure TArcViewerForm.acBackForwardExecute(Sender: TObject);
//var
//  dtDelta: TDatetime;
begin
{
  if CurGroup=nil then exit;
  dtDelta := CurGroup.dtEnd - CurGroup.dtBeg;
  if Sender = acBack then begin
    CurGroup.dtEnd := CurGroup.dtEnd - dtDelta;
    CurGroup.dtBeg := CurGroup.dtBeg - dtDelta;
  end else begin
    CurGroup.dtEnd := CurGroup.dtEnd + dtDelta;
    CurGroup.dtBeg := CurGroup.dtBeg + dtDelta;
  end;

  acUpdateExecute(nil);
}
end;



procedure TArcViewerForm.TimerTimer(Sender: TObject);
begin
  if CurGroup=nil then exit;
  CurDT := now;
  acUpdateExecute(nil);
end;

procedure TArcViewerForm.acOnLineExecute(Sender: TObject);
begin

  Timer.Enabled := not Timer.Enabled;
  if Timer.Enabled then
    acOnLine.ImageIndex := 20
  else
    acOnLine.ImageIndex := 12;

end;



// ÏÅÐÅÕÎÄ Ê ÏÅÐÈÎÄÓ
procedure TArcViewerForm.acGotoExecute(Sender: TObject);
var
  w: TavGotoForm;
begin
  if CurGroup=nil then exit;
  w := TavGotoForm.Create(self);
  try
    w.dtBegDate.DateTime := CurDT;
    w.dtBegTime.DateTime := CurDT;
    if w.ShowModal=mrOk then begin
      CurDT := w.dtBegDate.DateTime;
      ReplaceTime(CurDT, w.dtBegTime.DateTime);
      acUpdateExecute(nil);
    end;
  except
    w.Free;
  end;
end;


procedure TArcViewerForm.listAdvancedCustomDrawSubItem(
  Sender: TCustomListView; Item: TListItem; SubItem: Integer;
  State: TCustomDrawState; Stage: TCustomDrawStage;
  var DefaultDraw: Boolean);
var
  st: TavStroka;
  i: integer;
begin
  if SubItem-1 < Item.SubItems.Count then begin
//    Item.SubItems[SubItem-1] := inttostr(SubItem);
//  exit;

    if SubItem>fix_col-1 then begin
      st := TavStroka(Item.Data);
      i := SubItem-fix_col;
      if i < length(st.Tags) then
      list.Canvas.Font.Color := st.tags[i].FontColor;
      list.Canvas.Brush.Color := st.tags[i].BackColor;
//      Item.SubItems[SubItem-1] := st.Name;
//      list.Canvas.Font.Color := st.tags[i].FontColor;
//      list.Canvas.Brush.Color := clRed;
    end;

  end else begin
    list.Canvas.Font.Color := clBlack;
    list.Canvas.Brush.Color := clWhite;
  end;

end;


procedure TArcViewerForm.acMemPeriodExecute(Sender: TObject);
begin
  MemDt := CurDT;
  acRstPeriod.Hint := DateTimeToStr(MemDT);
  acRstPeriod.Enabled := true;
end;

procedure TArcViewerForm.acRstPeriodExecute(Sender: TObject);
begin
  if CurGroup=nil then exit;

  if (MemDt=0) then exit;
  CurDT := MemDt;
  acUpdateExecute(nil);
end;


procedure TArcViewerForm.treeDragDrop(Sender, Source: TObject; X,
  Y: Integer);
begin
  Tree.Selected.MoveTo(Tree.DropTarget, naAddChild);
  Save;
end;

procedure TArcViewerForm.treeDragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
begin
//
end;

procedure TArcViewerForm.acGroupDelExecute(Sender: TObject);
var
  i: integer;
begin
  if tree.Selected=nil then exit;
  if tree.Selected.Data=nil then exit;

  for i:=0 to tree.Selected.Count-1 do
    TavGroup(tree.Selected.Item[i].Data).Free;

  tree.Selected.Delete;
  save;
end;

procedure TArcViewerForm.acPrintExecute(Sender: TObject);
begin
  with TavPrintForm.Create(self) do try
    L := list;
    ShowModal;
  finally
    Free
  end
end;



// STROKA ADD
procedure TArcViewerForm.acStrokaAddExecute(Sender: TObject);
var
  newflag: boolean;
  w: TavStrokaPropForm;
//  k: integer;
begin

  if avTagListForm=nil then begin
    avTagListForm := TavTagListForm.Create(self);
    avTagListForm.db := db;
    avTagListForm.Init;
  end;

  newflag := Sender = acStrokaAdd;

  if tree.Selected = nil then exit;
  if tree.Selected.Data = nil then exit;
  if not newflag then
    if listNav.Selected=nil then exit;

  w := TavStrokaPropForm.Create(self);
  try

    w.G := TavGroup( tree.Selected.data );
    if newflag then
      w.M := nil
    else
      w.M := TavStroka( listNav.Selected.data );

    if w.ShowModal=mrOk then begin
      if newflag then begin
        listNav.Selected := listNav.Items.Add;
        listNav.Selected.Data := w.M;
      end;

      listNav.Selected.Caption := w.M.Name + ' ' + w.M.Descr;
      Save;
    end;
  finally
    w.Free;
  end;

//  treeChange(nil,tree.Selected);
end;

procedure TArcViewerForm.acStrokaDelExecute(Sender: TObject);
var
  i,k: integer;
  G: TavGroup;
  M: TavStroka;
begin
  if tree.Selected = nil then exit;
  if tree.Selected.Data = nil then exit;
  if listNav.Selected=nil then exit;

  G := TavGroup( tree.Selected.data );
  M := TavStroka( listNav.Selected.data );

  M.Free;
  listNav.Selected.Delete;
  k := listNav.Items.Count;

  SetLength(G.Stroki, k);
  for i:=0 to k-1 do
    G.Stroki[i] := listNav.Items[i].Data;

  save;  
end;

// ÌÅÒÎÄÛ ÎÒÎÁÐÀÆÅÍÈß
procedure TArcViewerForm.acVisualizatorsExecute(Sender: TObject);
begin
  with TavVisualizatorsForm.Create(self) do try
    A := Visulizators;
    ShowModal;
    save;
  finally
    free;
  end;

end;



////////////////////////////////////////////////////////////////////////////////
// Êëîíèðîâàíèå ãðóïïû
////////////////////////////////////////////////////////////////////////////////
{
procedure TArcViewerForm.acGroupCloneExecute(Sender: TObject);

var
  sFind1: string;
  sRepl1: string;
  sFind2: string;
  sRepl2: string;
  sFind3: string;
  sRepl3: string;


  function repl_str(s: string): string;
  begin
    ReplaceS(s, sFind1, sRepl1);
    ReplaceS(s, sFind2, sRepl2);
    ReplaceS(s, sFind3, sRepl3);
    result := s;
  end;


  procedure copy_stroka_props(st1,st2: TavStroka);
  var
    i,j: integer;
    m1,m2: TtvGroup;
  begin
    m1 := t1.Data;
    m2 := TtvGroup.Create;
    t2.Data := m2;

    m2.Name := repl_str(m1.Name);
    m2.UnitName := m1.UnitName;
    m2.Descr := m1.Descr;
    m2.UseColor := m1.UseColor;
    m2.Color := m1.Color;
    m2.DefaultDelta := m1.DefaultDelta;
    m2.DefaultYmin := m1.DefaultYmin;
    m2.DefaultYmax := m1.DefaultYmax;

    SetLength(m2.Tags, length(m1.Tags) );
    for j:=0 to length(m1.Tags)-1 do begin
      m2.Tags[j] := TtvTag.Create;
      m2.Tags[j].Name := repl_str(m1.Tags[j].Name);
      m2.Tags[j].Descr := repl_str(m1.Tags[j].Descr);
      m2.Tags[j].LegName := repl_str(m1.Tags[j].LegName);
      m2.Tags[j].Transform := m1.Tags[j].Transform;
      m2.Tags[j].Width := m1.Tags[j].Width;
      m2.Tags[j].UseColor := m1.Tags[j].UseColor;
      m2.Tags[j].Stairs := m1.Tags[j].Stairs;
      m2.Tags[j].Pointers := m1.Tags[j].Pointers;
    end;

    t2.Text := m2.Name;
  end;


  procedure replicate_node(t1,t2: TTreeNode);
  var
    i: integer;
    t: TTreeNode;
  begin
    copy_group_props(t1, t2);
    for i:=0 to t1.Count-1 do begin
      t := tree.Items.AddChild(t2, 'clone');
      replicate_node(t1.Item[i], t);
    end;
  end;



//var
//  i,j,k1,k2: integer;
//  t1,t2: TTreenode;
begin

  if tree.Selected = nil then exit;
  if tree.Selected.Level=0 then exit;

  with TtvCloneForm.Create(self) do try
    i := ShowModal;
    sFind1 := edFind1.Text;
    sRepl1 := edRepl1.Text;
    sFind2 := edFind2.Text;
    sRepl2 := edRepl2.Text;
    sFind3 := edFind3.Text;
    sRepl3 := edRepl3.Text;
  finally
    free;
  end;
  if i<>mrOk then exit;

  t1 := tree.Selected;
  t2 := tree.Items.AddChild(tree.Selected.Parent, 'clone');
  replicate_node(t1,t2);

  Save;

end;
}



// ÊËÎÍÈÐÎÂÀÍÈÅ ÑÒÐÎÊÈ
procedure TArcViewerForm.acStrokaCloneExecute(Sender: TObject);
var
  sFind1: string;
  sRepl1: string;
  sFind2: string;
  sRepl2: string;
  sFind3: string;
  sRepl3: string;


  function repl_str(s: string): string;
  begin
    ReplaceS(s, sFind1, sRepl1);
    ReplaceS(s, sFind2, sRepl2);
    ReplaceS(s, sFind3, sRepl3);
    result := s;
  end;


  procedure copy_stroka_props(st1,st2: TavStroka);
  var
    j: integer;
  begin
    st2.Name := repl_str(st1.Name);
    st2.Descr := repl_str(st1.Descr);

    SetLength(st2.Tags, length(st1.Tags) );
    for j:=0 to length(st1.Tags)-1 do begin
      st2.Tags[j] := TavTag.Create;
      st2.Tags[j].TagName := repl_str(st1.Tags[j].TagName);
      st2.Tags[j].Transform := st1.Tags[j].Transform;
      st2.Tags[j].Visulizator := st1.Tags[j].Visulizator;
    end;
  end;

var
  i,k: integer;
  st1,st2: TavStroka;
  gr: TavGroup;
begin
  if listNav.Selected = nil then exit;
  if tree.Selected = nil then exit;
  if tree.Selected.Level=0 then exit;

  with TavCloneForm.Create(self) do try
    i := ShowModal;
    sFind1 := edFind1.Text;
    sRepl1 := edRepl1.Text;
    sFind2 := edFind2.Text;
    sRepl2 := edRepl2.Text;
    sFind3 := edFind3.Text;
    sRepl3 := edRepl3.Text;
  finally
    free;
  end;
  if i<>mrOk then exit;


  st1 := TavStroka(listNav.Selected.Data);
  st2 := TavStroka.Create;
  copy_stroka_props(st1,st2);

  gr := TavGroup(tree.Selected.Data);
  k := length(gr.Stroki);
  SetLength(gr.Stroki, k+1);
  gr.Stroki[k] := st2;
  st2.Group := gr;


  with listNav.Items.Add do begin
    Caption := st2.Name + ' ' + st2.Descr;
    Data := st2;
  end;

  Save;
end;

procedure TArcViewerForm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Release;
end;

procedure TArcViewerForm.btFwdSecClick(Sender: TObject);
begin
  if sender = btFwdSec    then
    CurDT := CurDT + OneSecond else
  if sender = btFwdSec10  then
    CurDT := CurDT + OneSecond*10 else
  if sender = btFwdMin    then
    CurDT := CurDT + OneMinute else
  if sender = btFwdMin10  then
    CurDT := CurDT + OneMinute*10 else
  if sender = btFwdHour   then
    CurDT := CurDT + OneHour else
  if sender = btFwdDay    then
    CurDT := CurDT + 1 else
  if sender = btBckSec    then
    CurDT := CurDT - OneSecond else
  if sender = btBckSec10  then
    CurDT := CurDT - OneSecond*10 else
  if sender = btBckMin    then
    CurDT := CurDT - OneMinute else
  if sender = btBckMin10  then
    CurDT := CurDT - OneMinute*10 else
  if sender = btBckHour   then
    CurDT := CurDT - OneHour else
  if sender = btBckDay    then
    CurDT := CurDT - 1;
  acUpdateExecute(nil);
end;

end.
