unit fAutoActions;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants, uRegExpr,
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
  System.Rtti, FMX.Grid.Style, FMX.Grid, FMX.ScrollBox, FMX.Edit, StrUtils,
  FMX.Controls.Presentation, uMyTimer, uRecords, System.Generics.Collections;

type
  TfrAutoActions = class(TFrame)
    GroupBox20: TGroupBox;
    edtMessage: TEdit;
    edtInterval: TEdit;
    btnAddMessage: TButton;
    btnRmMessage: TButton;
    btnEditMessage: TButton;
    btnNotifyTest: TButton;
    sgTimers: TStringGrid;
    ccTimerEnable: TCheckColumn;
    scTimerMessage: TStringColumn;
    icTimerInterval: TIntegerColumn;
    ccTimerO: TCheckColumn;
    GroupBox23: TGroupBox;
    edtBanWords: TEdit;
    btnBanWordsAdd: TButton;
    btnBanWordsEdt: TButton;
    btnBanWordsDel: TButton;
    sgBanWords: TStringGrid;
    scRegEx: TStringColumn;
    btnBanWordsCheck: TButton;
    Label6: TLabel;
    edtBanWordsCheck: TEdit;
    Label7: TLabel;
    lBanWordsCheck: TLabel;
    GroupBox17: TGroupBox;
    edtCounterName: TEdit;
    edtCounterTrigger: TEdit;
    edtCounterCount: TEdit;
    btnCounterAdd: TButton;
    btnCounterDelete: TButton;
    btnCounterP: TButton;
    btnCounterM: TButton;
    btnCounterEdit: TButton;
    sgCounter: TStringGrid;
    scCounterName: TStringColumn;
    scCounterTrigger: TStringColumn;
    icCounterCount: TIntegerColumn;
    ccCounterAuto: TCheckColumn;
    procedure btnAddMessageClick(Sender: TObject);
    procedure btnEditMessageClick(Sender: TObject);
    procedure btnRmMessageClick(Sender: TObject);
    procedure btnNotifyTestClick(Sender: TObject);
    procedure sgTimersEditingDone(Sender: TObject; const ACol, ARow: Integer);
    procedure btnBanWordsCheckClick(Sender: TObject);
    procedure btnBanWordsAddClick(Sender: TObject);
    procedure btnBanWordsEdtClick(Sender: TObject);
    procedure btnBanWordsDelClick(Sender: TObject);
    procedure btnCounterAddClick(Sender: TObject);
    procedure btnCounterEditClick(Sender: TObject);
    procedure btnCounterDeleteClick(Sender: TObject);
    procedure btnCounterPClick(Sender: TObject);
    procedure btnCounterMClick(Sender: TObject);
    procedure sgTimersCellClick(const Column: TColumn; const Row: Integer);
    procedure sgBanWordsCellClick(const Column: TColumn; const Row: Integer);
    procedure sgCounterCellClick(const Column: TColumn; const Row: Integer);
  private
    { Private declarations }
    procedure OnMyTimerExec(Sender: TObject; const txt: string; o: Boolean);

  public
    { Public declarations }
    FTimerList: TObjectList<TMyTimerThread>;
    listTimer: TArray<TListTimer>;
    listBanWords: TArray<TBanWord>;
    listCounters: TArray<TCounter>;
    destructor Destroy; override;
    procedure UpdateGridFromArray;
    procedure initTimers;
  end;

implementation

{$R *.fmx}

uses uGeneral;

procedure TfrAutoActions.btnAddMessageClick(Sender: TObject);
var
  TimerThread: TMyTimerThread;
  NewRec: TListTimer;
begin
  if (edtMessage.text = '') or (edtInterval.text = '') then
    exit;

  TimerThread := TMyTimerThread.Create(edtInterval.text.ToInteger,
    edtMessage.text, false);
  TimerThread.OnTimerExec := OnMyTimerExec;
  FTimerList.Add(TimerThread);

  NewRec.Enable := 1;
  NewRec.interval := edtInterval.text.ToInteger;
  NewRec.o := 0;
  NewRec.mess := edtMessage.text;

  SetLength(listTimer, Length(listTimer) + 1);
  listTimer[High(listTimer)] := NewRec;

  UpdateGridFromArray;
  DB.SaveRecordArray<TListTimer>('listTimer', listTimer);

  edtMessage.text := '';
  edtInterval.text := '10';
end;

procedure TfrAutoActions.btnBanWordsAddClick(Sender: TObject);
var
  NewRec: TBanWord;
begin
  if (edtBanWords.text = '') then
    exit;

  NewRec.regexp := edtBanWords.text;

  SetLength(listBanWords, Length(listBanWords) + 1);
  listBanWords[High(listBanWords)] := NewRec;

  UpdateGridFromArray;
  DB.SaveRecordArray<TBanWord>('listBanWords', listBanWords);

  edtBanWords.text := '';

end;

procedure TfrAutoActions.btnBanWordsCheckClick(Sender: TObject);
var
  rx: TRegExpr;
begin
  rx := TRegExpr.Create;
  try
  rx.InputString := edtBanWordsCheck.text;
  rx.Expression := edtBanWords.text;
  if rx.Exec then
    lBanWordsCheck.text := 'есть банворд'
  else
    lBanWordsCheck.text := 'нет банворда';
  finally
    rx.Free;
  end;
end;

procedure TfrAutoActions.btnBanWordsDelClick(Sender: TObject);
var
  SelectedRow: Integer;
  I: Integer;
begin
  SelectedRow := sgBanWords.Row;
  // Проверяем валидность выбранной строки
  if (SelectedRow < 0) or (SelectedRow >= sgBanWords.RowCount) then
    exit;

  // Сдвигаем элементы массива
  for I := SelectedRow to High(listBanWords) - 1 do
    listBanWords[I] := listBanWords[I + 1];
  SetLength(listBanWords, Length(listBanWords) - 1);
  UpdateGridFromArray;
  DB.SaveRecordArray<TBanWord>('listBanWords', listBanWords);
end;

procedure TfrAutoActions.btnBanWordsEdtClick(Sender: TObject);
var
  SelectedRow: Integer;
  NewText, oldText: string;
  I: Integer;
  myRec: TBanWord;
begin
  SelectedRow := sgBanWords.Row;
  if (edtBanWords.text = '') or (SelectedRow <= 0) or
    (SelectedRow >= sgBanWords.RowCount) then
    exit;
  NewText := edtBanWords.text;
  oldText := sgBanWords.Cells[0, SelectedRow];
  for I := 0 to High(listBanWords) do
    if listBanWords[I].regexp = oldText then
    begin
      listBanWords[I].regexp := NewText;
      break;
    end;
  UpdateGridFromArray;
  DB.SaveRecordArray<TBanWord>('listBanWords', listBanWords);
  edtBanWords.text := '';
end;

procedure TfrAutoActions.btnCounterAddClick(Sender: TObject);
var
  NewRec: TCounter;
begin
  if (edtCounterName.text = '') or (edtCounterTrigger.text = '') then
    exit;
  if (edtCounterCount.text = '') then
    edtCounterCount.text := '0';

  NewRec.counterName := edtCounterName.text;
  NewRec.trigger := edtCounterTrigger.text;
  NewRec.count := strtoint(edtCounterCount.text);
  NewRec.auto := 0;

  SetLength(listCounters, Length(listCounters) + 1);
  listCounters[High(listCounters)] := NewRec;

  UpdateGridFromArray;
  DB.SaveRecordArray<TCounter>('listCounters', listCounters);

  edtCounterName.text := '';
  edtCounterTrigger.text := '';
  edtCounterCount.text := '0';

end;

procedure TfrAutoActions.btnCounterDeleteClick(Sender: TObject);
var
  SelectedRow: Integer;
  I: Integer;
begin
  SelectedRow := sgCounter.Row;
  // Проверяем валидность выбранной строки
  if (SelectedRow < 0) or (SelectedRow >= sgCounter.RowCount) then
    exit;

  for I := SelectedRow to High(listCounters) - 1 do
    listCounters[I] := listCounters[I + 1];
  SetLength(listCounters, Length(listCounters) - 1);
  UpdateGridFromArray;
  DB.SaveRecordArray<TCounter>('listCounters', listCounters);
end;

procedure TfrAutoActions.btnCounterEditClick(Sender: TObject);
var
  SelectedRow: Integer;
  oldName: string;
  I: Integer;
begin
  SelectedRow := sgCounter.Row;
  if (edtCounterName.text = '') or (edtCounterTrigger.text = '') then
    exit;
  if (edtCounterCount.text = '') then
    edtCounterCount.text := '0';
  oldName := sgCounter.Cells[0, SelectedRow];
  for I := 0 to high(listCounters) do
    if listCounters[I].counterName = oldName then
    begin
      listCounters[I].counterName := edtCounterName.text;
      listCounters[I].trigger := edtCounterTrigger.text;
      listCounters[I].count := strtoint(edtCounterCount.text);
    end;
  UpdateGridFromArray;
  DB.SaveRecordArray<TCounter>('listCounters', listCounters);
  edtCounterName.text := '';
  edtCounterTrigger.text := '';
  edtCounterCount.text := '0';
end;

procedure TfrAutoActions.btnCounterMClick(Sender: TObject);
begin
  edtCounterCount.text := inttostr(strtoint(edtCounterCount.text) - 1);
end;

procedure TfrAutoActions.btnCounterPClick(Sender: TObject);
begin
  edtCounterCount.text := inttostr(strtoint(edtCounterCount.text) + 1);
end;

procedure TfrAutoActions.btnEditMessageClick(Sender: TObject);
var
  SelectedRow: Integer;
  NewText: string;
  NewInterval: Integer;

begin
  SelectedRow := sgTimers.Row;
  if (edtMessage.text = '') or (edtInterval.text = '') or (SelectedRow <= 0) or
    (SelectedRow >= sgTimers.RowCount) then
    exit;
  NewText := edtMessage.text;
  NewInterval := StrToIntDef(edtInterval.text, 0);

  // Обновляем настройки таймера
  FTimerList[SelectedRow].Update(sgTimers.Cells[2, SelectedRow].ToInteger,
    sgTimers.Cells[1, SelectedRow], (sgTimers.Cells[3, SelectedRow] = 'True'));
  listTimer[SelectedRow].interval := NewInterval;
  listTimer[SelectedRow].mess := NewText;
  UpdateGridFromArray;
  DB.SaveRecordArray<TListTimer>('listTimer', listTimer);

  edtMessage.text := '';
  edtInterval.text := '';
end;

procedure TfrAutoActions.btnNotifyTestClick(Sender: TObject);
var
  s: string;
  B: Boolean;
begin
  s := sgTimers.Cells[1, sgTimers.Row];
  B := sgTimers.Cells[3, sgTimers.Row] = 'True';
  { if B then
    ttw_API.sendNotify(s)
    else
    ttw_IRS.sendMessage(s); }
end;

procedure TfrAutoActions.btnRmMessageClick(Sender: TObject);
var
  SelectedRow: Integer;
  I: Integer;
begin
  SelectedRow := sgTimers.Row;
  // Проверяем валидность выбранной строки
  if (SelectedRow < 0) or (SelectedRow >= sgTimers.RowCount) then
    exit;
  // Проверяем наличие таймера в списке
  if (SelectedRow < FTimerList.count) then
  begin
    // Останавливаем и уничтожаем таймер
    if Assigned(FTimerList[SelectedRow]) then
    begin
      FTimerList[SelectedRow].StopT;
      FTimerList[SelectedRow].Terminate; // Метод для остановки потока
      FTimerList[SelectedRow].Free;
      FTimerList.Delete(SelectedRow); // Удаляем из списка с автоуничтожением
    end;
  end;

  for I := SelectedRow to High(listTimer) - 1 do
    listTimer[I] := listTimer[I + 1];
  SetLength(listTimer, Length(listTimer) - 1);
  UpdateGridFromArray;
  DB.SaveRecordArray<TListTimer>('listTimer', listTimer);
end;

destructor TfrAutoActions.Destroy;
var
  i: Integer;
begin
  if Assigned(FTimerList) then
  begin
    for i := FTimerList.Count - 1 downto 0 do
    begin
      if Assigned(FTimerList[i]) then
      begin
        FTimerList[i].StopT;
        FTimerList[i].Terminate;
        FTimerList[i].Free;
      end;
    end;
    FreeAndNil(FTimerList);
  end;
  inherited;
end;

procedure TfrAutoActions.initTimers;
var
  I: Integer;
  TimerThread: TMyTimerThread;
begin
  for I := 0 to High(listTimer) do
  begin
    TimerThread := TMyTimerThread.Create(listTimer[I].interval,
      listTimer[I].mess, listTimer[I].o = 1);
    TimerThread.OnTimerExec := OnMyTimerExec;
    FTimerList.Add(TimerThread);
  end;
end;

procedure TfrAutoActions.OnMyTimerExec(Sender: TObject; const txt: string;
  o: Boolean);
begin
  { if o then
    ttw_API.sendNotify(txt)
    else
    ttw_IRS.sendMessage(txt); }
end;

procedure TfrAutoActions.sgBanWordsCellClick(const Column: TColumn;
  const Row: Integer);
begin
  edtBanWords.text := sgBanWords.Cells[0, Row];
end;

procedure TfrAutoActions.sgCounterCellClick(const Column: TColumn;
  const Row: Integer);
begin
  edtCounterName.text := sgCounter.Cells[0, Row];
  edtCounterTrigger.text := sgCounter.Cells[1, Row];
  edtCounterCount.text := sgCounter.Cells[2, Row];
end;

procedure TfrAutoActions.sgTimersCellClick(const Column: TColumn;
  const Row: Integer);
begin
  edtMessage.text := sgTimers.Cells[1, Row];
  edtInterval.text := sgTimers.Cells[2, Row];

end;

procedure TfrAutoActions.sgTimersEditingDone(Sender: TObject;
  const ACol, ARow: Integer);
var
  NewRec: TListTimer;
begin
  NewRec.Enable := strtoint(ifthen(sgTimers.Cells[0, ARow] = 'True', '1', '0'));
  NewRec.o := strtoint(ifthen(sgTimers.Cells[3, ARow] = 'True', '1', '0'));
  NewRec.interval := strtoint(sgTimers.Cells[2, ARow]);
  NewRec.mess := sgTimers.Cells[1, ARow];
  if ACol = 0 then // Колонка enabled
  begin
    if NewRec.Enable = 1 then
      FTimerList[ARow].StartT
    else
      FTimerList[ARow].StopT;
  end;
  if ACol = 3 then // Колонка o
  begin
    // Обновляем настройки таймера
    FTimerList[ARow].Update(NewRec.interval, NewRec.mess, (NewRec.o = 1));
  end;
  listTimer[ARow] := NewRec;
  UpdateGridFromArray;
  DB.SaveRecordArray<TListTimer>('listTimer', listTimer);
end;

procedure TfrAutoActions.UpdateGridFromArray;
var
  I: Integer;
begin
  sgTimers.BeginUpdate;
  try
    sgTimers.RowCount := 0; // Сбрасываем строки (оставляем только заголовки)

    for I := 0 to High(listTimer) do
    begin
      sgTimers.RowCount := I + 1;
      sgTimers.Cells[0, I] := ifthen(listTimer[I].Enable = 1, 'True', 'False');
      sgTimers.Cells[1, I] := listTimer[I].mess;
      sgTimers.Cells[2, I] := inttostr(listTimer[I].interval);
      sgTimers.Cells[3, I] := ifthen(listTimer[I].o = 1, 'True', 'False');
    end;
  finally
    sgTimers.EndUpdate;
  end;
  sgBanWords.BeginUpdate;
  try
    sgBanWords.RowCount := 0; // Сбрасываем строки (оставляем только заголовки)

    for I := 0 to High(listBanWords) do
    begin
      sgBanWords.RowCount := I + 1;
      sgBanWords.Cells[0, I] := listBanWords[I].regexp;
    end;
  finally
    sgBanWords.EndUpdate;
  end;
  sgCounter.BeginUpdate;
  try
    sgCounter.RowCount := 0; // Сбрасываем строки (оставляем только заголовки)

    for I := 0 to High(listCounters) do
    begin
      sgCounter.RowCount := I + 1;
      sgCounter.Cells[0, I] := listCounters[I].counterName;
      sgCounter.Cells[1, I] := listCounters[I].trigger;
      sgCounter.Cells[2, I] := inttostr(listCounters[I].count);
      sgCounter.Cells[3, I] := ifthen(listCounters[I].auto = 1, '1', '0');
    end;
  finally
    sgCounter.EndUpdate;
  end;
end;

end.
