unit fEvents;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants, System.Generics.Collections, ShellAPI, uSoundManager,
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
  FMX.Edit, FMX.ListBox, FMX.Controls.Presentation, System.Rtti, FMX.Grid.Style,
  FMX.ScrollBox, FMX.Grid, uRecords, uDataBase, FMX.Menus, uKeyEvent,
  fColorSettings, fFontSettings;

type
  TfrEvents = class(TFrame)
    Label1: TLabel;
    cbEventList: TComboBox;
    edtIF: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    cbActions: TComboBox;
    cbRevards: TComboBox;
    sgEvents: TStringGrid;
    Label4: TLabel;
    edtParams: TEdit;
    StringColumn1: TStringColumn;
    StringColumn2: TStringColumn;
    StringColumn3: TStringColumn;
    StringColumn4: TStringColumn;
    btnAdd: TButton;
    btnDelete: TButton;
    PopupMenu1: TPopupMenu;
    MenuItem1: TMenuItem;
    OpenDialog1: TOpenDialog;
    pVKGenerate: TPanel;
    cbKey1: TComboBox;
    Label54: TLabel;
    cbKey3: TComboBox;
    cbKey2: TComboBox;
    Label56: TLabel;
    procedure cbEventListChange(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure btnDeleteClick(Sender: TObject);
    procedure MenuItem1Click(Sender: TObject);
    procedure cbActionsChange(Sender: TObject);
  private
    procedure toLog(aCode: integer; aMethod, aMess: string);
    procedure ExecuteAction(const aAction: integer; const aParam, aUserInput, aUserName, aUserLogin: string);
  public
    ListEvents: TArray<TEventGlobal>;
    CustomRewardEvents: TList<TCustomRewardEvent>;

    procedure UpdateGrid;
    procedure ESOnGetCustomReward(CustomReward: TCustomRewardEvent);
    procedure OnDonate(aNick, aMessage, aSum: string);
  end;

implementation

{$R *.fmx}

uses uGeneral;

{ --- UI --- }

procedure TfrEvents.btnAddClick(Sender: TObject);
var
  NewRec: TEventGlobal;
begin
  if (cbEventList.ItemIndex < 0) or (cbActions.ItemIndex < 0) then
    Exit;

  NewRec.Event := cbEventList.ItemIndex;
  NewRec.Action := cbActions.ItemIndex;
  NewRec.Param := edtParams.Text;

  if edtIF.Visible then
    NewRec.Condition := edtIF.Text
  else if cbRevards.Visible then
    NewRec.Condition := cbRevards.Text;

  ListEvents := ListEvents + [NewRec];

  DB.SaveRecordArray<TEventGlobal>('ListEvents', ListEvents);
  UpdateGrid;
end;

procedure TfrEvents.btnDeleteClick(Sender: TObject);
var
  RowIndex: integer;
begin
  RowIndex := sgEvents.Row;
  if (RowIndex < 0) or (RowIndex > High(ListEvents)) then
    Exit;

  Delete(ListEvents, RowIndex, 1);

  DB.SaveRecordArray<TEventGlobal>('ListEvents', ListEvents);
  UpdateGrid;
end;

procedure TfrEvents.cbActionsChange(Sender: TObject);
begin
  pVKGenerate.Visible := cbActions.ItemIndex = 0;
end;

procedure TfrEvents.cbEventListChange(Sender: TObject);
begin
  edtIF.Visible := cbEventList.ItemIndex = 0;
  cbRevards.Visible := cbEventList.ItemIndex = 1;
  Label2.Visible := cbEventList.ItemIndex <= 1;
end;

procedure TfrEvents.MenuItem1Click(Sender: TObject);
begin
  if OpenDialog1.Execute and (PopupMenu1.PopupComponent is TEdit) then
    TEdit(PopupMenu1.PopupComponent).Text := OpenDialog1.FileName;
end;

{ --- Общая логика --- }

procedure TfrEvents.ExecuteAction(const aAction: integer; const aParam, aUserInput, aUserName, aUserLogin: string);
var
  sm: TSongMachine;
  f: TfrColorSettings;
  t: TfrFontSettings;
  i, j: Integer;
  notify: TOBSNotify;
  se: TStyleEvent;
begin
  sm := TSongMachine.Create;
  try
    case aAction of
      0: begin // Нажать кнопку
           toLog(0, 'ExecuteAction', 'Симуляция нажатия: ' + aParam);
           kePoints.SimulateKeyPress(aParam, 500);
         end;
      1: begin // Воспроизведение звука
           toLog(0, 'ExecuteAction', 'Воспроизведение звука: ' + aParam);
           sm.PlayPublic(aParam, '100');
         end;
      2: begin // Kandinsky
           toLog(0, 'ExecuteAction', 'Генерация Kandinsky для: ' + aUserInput);
           Kandinsky.generate(aUserInput, aUserLogin);
         end;
      3: begin // OBS Notify
           f := TfrColorSettings.Create(Self);
           t := TfrFontSettings.Create(Self);
           try
             for i := 0 to High(TTW_Bot.frOBS1.listNotify) do
               if TTW_Bot.frOBS1.listNotify[i].TypeEvent = 5 then
               begin
                 notify := TTW_Bot.frOBS1.listNotify[i];
                 se.Title := StringReplace(notify.HeaderText, '[NICK]', aUserName, [rfReplaceAll]);
                 se.Context := notify.MessText;
                 se.Url := notify.Picture;
                 se.SoundURL := notify.Sound;
                 se.Timestamp := Now;
                 se.TimeMsg := notify.TimeMess;
                 se.BorderColor := notify.ColorBorder;
                 se.BorderSize := notify.SolidBorder;
                 se.BlockColor := notify.ColorBlock;
                 se.FontTitle.Font := notify.HeaderStyleFont;
                 se.FontTitle.Size := notify.HeaderSizeFont;
                 se.FontTitle.Color := notify.HeaderColorFont;
                 se.FontContext.Font := notify.MessStyleFont;
                 se.FontContext.Size := notify.MessSizeFont;
                 se.FontContext.Color := notify.MessColorFont;
                 se.RequireInteraction := True;

                 for j := 0 to TTW_Bot.frOBS1.EventWebServers.Count - 1 do
                   TTW_Bot.frOBS1.EventWebServers[j].WebServerChat.AddMessage(se);
               end;
           finally
             f.Free;
             t.Free;
           end;
         end;
      4: toLog(0, 'ExecuteAction', 'Написать в чат: ' + aUserInput);
      5: begin // Запуск файла
           toLog(0, 'ExecuteAction', 'Запуск файла: ' + aParam);
           ShellExecute(0, 'open', PWideChar(aParam), nil, nil, 0);
         end;
    end;
  finally
    sm.Free;
  end;
end;

procedure TfrEvents.ESOnGetCustomReward(CustomReward: TCustomRewardEvent);
var
  ev: TEventGlobal;
begin
  toLog(3, 'ESOnGetCustomReward', 'Начало обработки награды: ' + CustomReward.Event.revard.Title);

  for ev in ListEvents do
    if (ev.Event = 1) and (ev.Condition = CustomReward.Event.revard.Title) then
      ExecuteAction(ev.Action, ev.Param, CustomReward.Event.user_input, CustomReward.Event.user_name, CustomReward.Event.user_login);
end;

procedure TfrEvents.OnDonate(aNick, aMessage, aSum: string);
var
  i, aSumInt, BestRow, BestPriority, BestValue,
  CurrentPriority, CurrentValue, MinVal, MaxVal: integer;
  Condition: string;
  Parts: TStringList;
begin
  aSumInt := StrToIntDef(aSum, 0);
  BestRow := -1;
  BestPriority := -1;
  BestValue := 0;

  for i := 0 to High(ListEvents) do
  begin
    if ListEvents[i].Event <> 0 then
      Continue;

    Condition := ListEvents[i].Condition;
    CurrentPriority := -1;
    CurrentValue := 0;

    if TryStrToInt(Condition, CurrentValue) then
    begin
      if aSumInt = CurrentValue then
        CurrentPriority := 4;
    end
    else if Pos('-', Condition) > 0 then
    begin
      Parts := TStringList.Create;
      try
        Parts.Delimiter := '-';
        Parts.StrictDelimiter := True;
        Parts.DelimitedText := Condition;
        if Parts.Count = 2 then
        begin
          MinVal := StrToIntDef(Trim(Parts[0]), 0);
          MaxVal := StrToIntDef(Trim(Parts[1]), 0);
          if (aSumInt >= MinVal) and (aSumInt <= MaxVal) then
          begin
            CurrentPriority := 3;
            CurrentValue := MinVal;
          end;
        end;
      finally
        Parts.Free;
      end;
    end
    else if (Condition.StartsWith('>')) then
    begin
      CurrentValue := StrToIntDef(Copy(Condition, 2), 0);
      if aSumInt >= CurrentValue then
        CurrentPriority := 2;
    end
    else if (Condition.StartsWith('<')) then
    begin
      CurrentValue := StrToIntDef(Copy(Condition, 2), 0);
      if aSumInt <= CurrentValue then
        CurrentPriority := 1;
    end;

    if (CurrentPriority <> -1) and
       ((CurrentPriority > BestPriority) or
       ((CurrentPriority = BestPriority) and
        (((CurrentPriority in [2,3]) and (CurrentValue > BestValue)) or
         ((CurrentPriority = 1) and (CurrentValue < BestValue))))) then
    begin
      BestPriority := CurrentPriority;
      BestValue := CurrentValue;
      BestRow := i;
    end;
  end;

  if BestRow <> -1 then
    ExecuteAction(ListEvents[BestRow].Action, ListEvents[BestRow].Param, aMessage, aNick, aNick);
end;



procedure TfrEvents.UpdateGrid;
var
  i: integer;
begin
  sgEvents.BeginUpdate;
  try
    sgEvents.RowCount := Length(ListEvents);
    for i := 0 to High(ListEvents) do
    begin
      sgEvents.Cells[0, i] := cbEventList.Items[ListEvents[i].Event];
      sgEvents.Cells[1, i] := ListEvents[i].Condition;
      sgEvents.Cells[2, i] := cbActions.Items[ListEvents[i].Action];
      sgEvents.Cells[3, i] := ListEvents[i].Param;
    end;
  finally
    sgEvents.EndUpdate;
  end;
end;

procedure TfrEvents.toLog(aCode: integer; aMethod, aMess: string);
begin
  TTW_Bot.toLog('fEvents', aMethod, aMess, aCode);
end;

end.

