unit MainForm;

{$mode objfpc}{H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ComCtrls, Spin, ExtCtrls, Grids, FileCtrl, uHCTypeDefs, uHCAnnexDefs,
  uHCAnnexHelpers, types;

type

  { TfrmMain }

  TfrmMain = class(TForm)
    SGbtnRunwayRestore: TButton;
    SGlbUOrigDP: TLabel;
    SGedUDP: TEdit;
    SGbtGSideSet: TButton;
    SGcbGSide: TFilterComboBox;
    MLbtnPostMessage: TButton;
    MLedtMessageToPost: TEdit;
    SGbtnRefresh: TButton;
    SGlblUnitClassName: TLabel;
    SGlblUnitDP1: TLabel;
    SGlblUnitInfo1: TLabel;
    SGlblUnitDP: TLabel;
    SGlblUnitIDName: TLabel;
    SGlblUnitInfo: TLabel;
    SGpnlUnit: TPanel;
    SGlblGroups: TLabel;
    SGlblUnits: TLabel;
    SGlbxGroups: TListBox;
    SGlbxUnits: TListBox;
    SGpnl1: TPanel;
    memDLLInit: TMemo;
    tshStartGroup: TTabSheet;
    tshDLLInit: TTabSheet;
    MLckbEnabled: TCheckBox;
    MLlblLines: TLabel;
    MLmemMsgLog: TMemo;
    PageControl1: TPageControl;
    MLedtLines: TSpinEdit;
    tshMsgLog: TTabSheet;
    procedure GTbtnResumeClick(Sender: TObject);
    procedure HHQueueEventMessageClick(Sender: TObject);
    procedure MLbtnPostMessageClick(Sender: TObject);
    procedure SGbtGSideSetClick(Sender: TObject);
    procedure SGbtnRefreshClick(Sender: TObject);
    procedure SGbtnRunwayRestoreClick(Sender: TObject);
    procedure SGcbGSideChange(Sender: TObject);
    procedure SGedUDPChange(Sender: TObject);
    procedure SGlbxGroupsSelectionChange(Sender: TObject; User: boolean);
    procedure SGlbxUnitsSelectionChange(Sender: TObject; User: boolean);
  private
    { private declarations }
  public
    { public declarations }
    // ALE 20130812 Big bad pointers that hold most of the game data
    PStartGroup: PHCGroup;
    PHarpEventHead: PHCHarpoonEvent;
    PSonobuoyRegionHead: PHCSonobuoyRegion;
    PAllDeadUnitsPtr: PHCDeadListItem;
    PWeatherGroups: PHCGroup;
    PVictoryConditionsList: PHCVictoryConditions;
    // ALE 20130812 transient pointers
    PSelectedUnit: PHCUnit;
    // ALE 20130812 misc globals
    //blnInvestigatingStructs: Boolean;
    // ALE 20130908 pointers to functions exported by the GE
    HCQueueHarpoonEvent: THCQueueHarpoonEvent;
    NewPtr: THCNewPtr;
    DisposPtr: THCDisposPtr;
    HCdllCheckLatLonDepth: THCdllCheckLatLonDepth;
    HCannex_id_to_disk_id: THCannex_id_to_disk_id;
    HCdisk_id_to_annex_id: THCdisk_id_to_annex_id;
    HCMessageLogLine: THCMessageLogLine;
    HCassign_group_id: THCassign_group_id;
    procedure PopulateGroupListInstallations(const pListBox: TListBox);
  end;

var
  frmMain: TfrmMain;

implementation

uses uLazTurncoatGlobals, uHCDefines, uHCEventHelpers, uHCUtils;

{$R *.lfm}

{ TfrmMain }


procedure TfrmMain.SGlbxGroupsSelectionChange(Sender: TObject; User: boolean);
var
  strSel: string;
  PHCGThis: PHCGroup;
  PHCUThis: PHCUnit;
begin
  // ALE 20130317 User selected a group, pull up unit list.
  strSel := SGlbxGroups.Items[SGlbxGroups.ItemIndex];
  PHCGThis := PStartGroup;
  while (PHCGThis <> nil) do
  begin
    if (strSel = PHCGThis^.id) then
      break;
    PHCGThis := PHCGThis^.toSouth;
  end;

  // ALE 20130317 in theory we have the group from which
  //  we can enumerate the units.
  SGlbxUnits.Items.Clear;
  SGlbxUnits.Sorted := True;
  PHCUThis := PHCGThis^.Units;
  while (PHCUThis <> nil) do
  begin
    SGlbxUnits.Items.Add(Format('%2.2s%0.3d %s',
      [PHCGThis^.id, PHCUThis^.id, PHCUThis^.Name]));
    PHCUThis := PHCUThis^.Next;
  end;

  // ALE 20200814 Deselect all of the Unit stuff
  PSelectedUnit:=nil;
  SGlblUnitIDName.Caption:='';
  SGlblUnitClassName.Caption:='';
  SGedUDP.Text:='';
  SGedUDP.Enabled:=False;
  SGlbUOrigDP.Caption:='';
  SGcbGSide.ItemIndex:=-1;
  SGcbGSide.Text:='';
  SGcbGSide.Enabled:=False;
  SGbtnRunwayRestore.Enabled:=False;
  SGbtGSideSet.Enabled:=False;

  // ALE 20200517 show the group's side
  SGcbGSide.ItemIndex := PHCGThis^.side;
  SGcbGSide.ItemIndex := PHCGThis^.side;

end;

procedure TfrmMain.GTbtnResumeClick(Sender: TObject);
begin
  byte(PDLLBusy^) := CFALSE; // ALE 20130816
end;

// ALE 20130908 An example of setting up a HarpoonEvent that
//  will go in the HarpoonEventHead list of events that holds
//  all of the events that are not associated with course
//  points.
//  HCQueueHarpoonEvent will add it to the HarpoonEventHead
//   list in the proper order.
procedure TfrmMain.HHQueueEventMessageClick(Sender: TObject);
var
  PHarpoonEvent: PHCHarpoonEvent;
  PEventMessage: PHCMessageEvent;
begin
  PHarpoonEvent := NewPtr(SizeOf(THCHarpoonEvent));
  PEventMessage := NewPtr(SizeOf(THCMessageEvent));

  PHarpoonEvent^.in_scroll_flag := CFALSE;
  PHarpoonEvent^.DataPtr := PEventMessage;
  PHarpoonEvent^.event_type := MESSAGE_EVENT;
  PHarpoonEvent^.time_type := TimeDelta;
  PHarpoonEvent^.Next := nil;
  PHarpoonEvent^.ourGroup := nil;
  PHarpoonEvent^.unit_uuid := '';
  PHarpoonEvent^.Time := 5; // ALE 20130908 Show us message 5 game seconds from now
  PEventMessage^.Message := FormatDateTime('yyyy-mm-dd hh:nn:ss', Now()) +
    #10 + ' Message Created';
  PEventMessage^.MessageFormat := Ord(THCTextTypes.ASCII);
  PEventMessage^.Side := ANYSIDE;
  byte(uLazTurncoatGlobals.PDLLBusy^) := CTRUE;
  HCQueueHarpoonEvent(PHarpoonEvent);
  byte(uLazTurncoatGlobals.PDLLBusy^) := CFALSE;
end;

procedure TfrmMain.MLbtnPostMessageClick(Sender: TObject);
begin
  HCMessageLogLine(PAnsiChar(MLedtMessageToPost.Text));
end;

procedure TfrmMain.SGbtGSideSetClick(Sender: TObject);
var
   PHCGThis: PHCGroup;
   strSel: String;
   lGroupType: AnsiChar;
   lGroupIdOrig: String;
   lGroupSideOrig: NativeInt;
begin
  if (SGlbxGroups.ItemIndex <> -1) then
  begin
    strSel := SGlbxGroups.Items[SGlbxGroups.ItemIndex];
    PHCGThis := PStartGroup;
    while (PHCGThis <> nil) do
    begin
      if (strSel = PHCGThis^.id) then
        break;
      PHCGThis := PHCGThis^.toSouth;
    end;

    if (PHCGThis <> nil) then
    begin
      // ALE 20210122 store 'before' group id
      lGroupIdOrig:=PHCGThis^.id;
      // ALE 20200815 get_group_id_type(group)
      lGroupType:=HCget_group_id_type(PHCGThis);
      // ALE 20220202 store 'before' side
      lGroupSideOrig:=PHCGThis^.side;

      // ALE 20200523 Potentially change the side of a group
      PHCGThis^.side := SGcbGSide.ItemIndex;

      if HCassign_group_id(PHCGThis, CTRUE) = CTRUE then
      begin
        // ALE 20200815 set_group_id_type(group)
        HCset_group_id_type(PHCGThis, lGroupType);
        // ALE 20200824 undestroy the base
        SGedUDP.Text:='0';
        // ALE 20200824 Bring the Runways back
        SGbtnRunwayRestore.Click;
        PopulateGroupListInstallations(SGlbxGroups);
        // ALE 20200819 clear out unit information as well
        SGlbxGroups.ItemIndex:=SGlbxGroups.Items.IndexOf(PHCGThis^.id);
      end
      else
      begin
        // ALE 20210122 no valid group id available, roll back change
        PHCGThis^.id := lGroupIdOrig;
        PHCGThis^.side := lGroupSideOrig;
        SGcbGSide.ItemIndex := lGroupSideOrig;
        MessageDlg('Side change failed', 'Side change failed, no group id available', mtWarning, [mbOK], 0);
      end;
    end;
  end;
end;

procedure TfrmMain.SGbtnRefreshClick(Sender: TObject);
begin
  // ALE 20130317 Fill up the SGlbxGroups
  PopulateGroupListInstallations(SGlbxGroups);
end;

procedure TfrmMain.SGbtnRunwayRestoreClick(Sender: TObject);
var
   PHCAnnexP1: PHCAnnexP1_disk;
begin
  // TODO ALE 20200814 unit->flooding = P1->Runway;
  if (PSelectedUnit <> nil) then
  begin
    case (HCAnnexHelper.HCAnnexShift(PSelectedUnit^.Annex)) of
      {
      SHIP_FLAG:
      begin
        PHCAnnexA1 := HCAnnexHelper.HCGetAnnexA1(PSelectedUnit^.Annex);
        SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexA1^.ClassName;
        // ALE 20150820 also could have done it in an ugly one-liner SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexA1_disk(AnnexData^.PA1_DISK_PTR_LIST + HCannex_id_to_disk_id(PSelectedUnit^.Annex) - (HCAnnexShift(PSelectedUnit^.Annex) * 4096 + 2048))^.ClassName;
      end;
      SUB_FLAG:
      begin
        PHCAnnexA2 := HCAnnexHelper.HCGetAnnexA2(PSelectedUnit^.Annex);
        SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexA2^.ClassName;
      end;
      PLANE_FLAG:
      begin
        PHCAnnexB1 := HCAnnexHelper.HCGetAnnexB1(PSelectedUnit^.Annex);
        SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexB1^.ClassName;
      end;
      }
      BASE_FLAG:
      begin
        PHCAnnexP1 := HCAnnexHelper.HCGetAnnexP1(PSelectedUnit^.Annex);
        PSelectedUnit^.flooding:=PHCAnnexP1^.Runway;  // ALE 20200814 restores runway capability
      end;
      else
        PSelectedUnit^.flooding:=0;
    end;
  end;
end;

procedure TfrmMain.SGcbGSideChange(Sender: TObject);
begin
  SGbtGSideSet.Click;
end;

procedure TfrmMain.SGedUDPChange(Sender: TObject);
var
  lDP: Integer;
begin
  if ((PSelectedUnit <> nil) AND (TryStrToInt(SGedUDP.Text, lDP))) then
  begin
    if (lDP <> PSelectedUnit^.CurrDp) then
    begin
      PSelectedUnit^.CurrDp:=lDP;
      //HCMessageLogLine(PAnsiChar('Changed DP to ' + SGedUDP.Text));
    end;
  end;
end;

procedure TfrmMain.SGlbxUnitsSelectionChange(Sender: TObject; User: boolean);
var
  strSel: string;
  PHCUThis: PHCUnit;
  PHCAnnexA1: PHCAnnexA1_disk;
  PHCAnnexA2: PHCAnnexA2_disk;
  PHCAnnexB1: PHCAnnexB1_disk;
  PHCAnnexP1: PHCAnnexP1_disk;
begin
  // ALE 20130317 User selected a unit, pull up unit info.
  strSel := SGlbxUnits.Items[SGlbxUnits.ItemIndex];
  PHCUThis := PStartGroup^.Units;
  while (PHCUThis <> nil) do
  begin
    if (Pos(Format('%2.2s%0.3d', [PHCGroup(PHCUThis^.Group)^.id, PHCUThis^.id]),
      strSel) = 1) then
    begin
      break;
    end;
    PHCUThis := PHCUThis^.toSouth;
  end;
  PSelectedUnit := PHCUThis;

  if (PSelectedUnit <> nil) then
  begin
    SGlblUnitIDName.Caption :=
      Format('Unit Name: %2.2s%0.3d %s', [PHCGroup(PSelectedUnit^.Group)^.id,
      PSelectedUnit^.id, PSelectedUnit^.Name]);
    SGedUDP.Text := IntToStr(PHCUThis^.CurrDp);
    //SGedUDP.Enabled:=True;
    SGlbUOrigDP.Caption := IntToStr(PHCUThis^.OrigDp);
    SGbtnRunwayRestore.Enabled:=True;
    SGbtGSideSet.Enabled:=True;
    SGcbGSide.Enabled:=True;
    SGcbGSide.Enabled:=True;
    case (HCAnnexHelper.HCAnnexShift(PSelectedUnit^.Annex)) of
      SHIP_FLAG:
      begin
        PHCAnnexA1 := HCAnnexHelper.HCGetAnnexA1(PSelectedUnit^.Annex);
        SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexA1^.ClassName;
        // ALE 20150820 also could have done it in an ugly one-liner SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexA1_disk(AnnexData^.PA1_DISK_PTR_LIST + HCannex_id_to_disk_id(PSelectedUnit^.Annex) - (HCAnnexShift(PSelectedUnit^.Annex) * 4096 + 2048))^.ClassName;
      end;
      SUB_FLAG:
      begin
        PHCAnnexA2 := HCAnnexHelper.HCGetAnnexA2(PSelectedUnit^.Annex);
        SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexA2^.ClassName;
      end;
      PLANE_FLAG:
      begin
        PHCAnnexB1 := HCAnnexHelper.HCGetAnnexB1(PSelectedUnit^.Annex);
        SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexB1^.ClassName;
      end;
      BASE_FLAG:
      begin
        PHCAnnexP1 := HCAnnexHelper.HCGetAnnexP1(PSelectedUnit^.Annex);
        SGlblUnitClassName.Caption := 'Class Name: ' + PHCAnnexP1^.Name;
      end;
      else
        SGlblUnitClassName.Caption := '';
    end;
  end;

end;


procedure TfrmMain.PopulateGroupListInstallations(const pListBox: TListBox);
var
  PHCGThis: PHCGroup;
begin
  // ALE 20130317 Fill up the SGlbxGroups
  pListBox.Items.BeginUpdate;
  pListBox.Items.Clear;
  pListBox.Sorted := True;
  PHCGThis := PStartGroup;
  while (PHCGThis <> nil) do
  begin
    // ALE 20200517 we only want installations
    if (HCIsFixedBase(PHCGThis^.gtype)) then
    begin
      pListBox.Items.Add(PHCGThis^.id);

    end;
    PHCGThis := PHCGThis^.toSouth;
  end;
  pListBox.Items.EndUpdate;
end;

end.
