unit MainForm;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ComCtrls, Spin, ExtCtrls, uHCTypeDefs;

type

  { TfrmMain }

  TfrmMain = class(TForm)
    GTHEbtnSet: TButton;
    HHQueueEventMessage: TButton;
    GTbtnResume: TButton;
    GTckbPause: TCheckBox;
    GTpctStructs: TPageControl;
    GTtshStartGroup: TTabSheet;
    GTtshWeatherGroups: TTabSheet;
    GTtshHarpEvents: TTabSheet;
    Label1: TLabel;
    Label2: TLabel;
    GTlblGameTime: TLabel;
    GTHEEventList: TListBox;
    GEHEmemDetail: TMemo;
    GTtshSonoBuoy: TTabSheet;
    GTtshDeadUnits: TTabSheet;
    Label3: TLabel;
    Label4: TLabel;
    GTHEspnedfuel: TSpinEdit;
    GTHEspnedUnit: TSpinEdit;
    GTHEspnedID: TSpinEdit;
    GTHEfuelling: TSpinEdit;
    GTHEspnedavailable: TSpinEdit;
    GTHEspnedEventTime: TSpinEdit;
    GTHEspedNxtAvailable: TSpinEdit;
    GTHEtglbxAutoPause: TToggleBox;
    GTHElbxAirUnitsInfo: TListBox;
    GTHElblUnitInfo: TLabel;
    GTHElblGrpID: TLabel;
    tshGT: TTabSheet;
    tshVC: TTabSheet;
    WGckbEnabled: TCheckBox;
    VCckbEnabled: TCheckBox;
    WGedtLines: TSpinEdit;
    VCedtLines: TSpinEdit;
    WGlblLines: TLabel;
    VClblLines: TLabel;
    WGmemMsgLog: TMemo;
    SHckbEnabled: TCheckBox;
    DUckbEnabled: TCheckBox;
    SHedtLines: TSpinEdit;
    DUedtLines: TSpinEdit;
    SHlblLines: TLabel;
    DUlblLines: TLabel;
    SHmemMsgLog: TMemo;
    SGlblUnitIDName: TLabel;
    SGlblUnitInfo: TLabel;
    SGpnlUnit: TPanel;
    SGlblGroups: TLabel;
    SGlblUnits: TLabel;
    SGlbxGroups: TListBox;
    SGlbxUnits: TListBox;
    SGpnl1: TPanel;
    SGlblDesc: TLabel;
    memDLLInit: TMemo;
    DUmemMsgLog: TMemo;
    SLckbEnabled: TCheckBox;
    SGckbEnabled: TCheckBox;
    HHckbEnabled: TCheckBox;
    SLedtLines: TSpinEdit;
    SGedtLines: TSpinEdit;
    HHedtLines: TSpinEdit;
    SLlblLines: TLabel;
    SGlblLines: TLabel;
    HHlblLines: TLabel;
    SLmemMsgLog: TMemo;
    SGmemMsgLog: TMemo;
    HHmemMsgLog: TMemo;
    tshWG: TTabSheet;
    tshDU: TTabSheet;
    tshSH: TTabSheet;
    tshStartGroup: TTabSheet;
    tshDLLInit: TTabSheet;
    tshScenLoad: TTabSheet;
    tshUnitFree: TTabSheet;
    tshUnitNew: TTabSheet;
    UGckbEnabled: TCheckBox;
    UNckbEnabled: TCheckBox;
    UGedtLines: TSpinEdit;
    UFckbEnabled: TCheckBox;
    UNedtLines: TSpinEdit;
    UGlblLines: TLabel;
    UFedtLines: TSpinEdit;
    UNlblLines: TLabel;
    UGmemMsgLog: TMemo;
    tshUnitToGroup: TTabSheet;
    tshTimeFactor: TTabSheet;
    tshUnitSink: TTabSheet;
    tshUnitShowingSide: TTabSheet;
    tshUnitAlt: TTabSheet;
    tshUnitSpeed: TTabSheet;
    tshUnitCourse: TTabSheet;
    tshUnitURegion: TTabSheet;
    tshUnitShowing: TTabSheet;
    TFckbEnabled: TCheckBox;
    TFedtLines: TSpinEdit;
    TFlblLines: TLabel;
    TFmemMsgLog: TMemo;
    UFlblLines: TLabel;
    UNmemMsgLog: TMemo;
    UFmemMsgLog: TMemo;
    USSckbEnabled: TCheckBox;
    USKckbEnabled: TCheckBox;
    USSedtLines: TSpinEdit;
    USKedtLines: TSpinEdit;
    USSlblLines: TLabel;
    USKlblLines: TLabel;
    USSmemMsgLog: TMemo;
    USPckbEnabled: TCheckBox;
    UAckbEnabled: TCheckBox;
    USPedtLines: TSpinEdit;
    UAedtLines: TSpinEdit;
    USPlblLines: TLabel;
    UAlblLines: TLabel;
    USPmemMsgLog: TMemo;
    ULLckbEnabled: TCheckBox;
    MLckbEnabled: TCheckBox;
    USckbEnabled: TCheckBox;
    ULLedtLines: TSpinEdit;
    MLlblLines: TLabel;
    UAmemMsgLog: TMemo;
    USKmemMsgLog: TMemo;
    UURckbEnabled: TCheckBox;
    USedtLines: TSpinEdit;
    ULLlblLines: TLabel;
    MLmemMsgLog: TMemo;
    UCckbEnabled: TCheckBox;
    UURedtLines: TSpinEdit;
    USlblLines: TLabel;
    ULLmemMsgLog: TMemo;
    PageControl1: TPageControl;
    MLedtLines: TSpinEdit;
    tshUnitLatLon: TTabSheet;
    tshMsgLog: TTabSheet;
    tshHH: TTabSheet;
    UCedtLines: TSpinEdit;
    UURlblLines: TLabel;
    USmemMsgLog: TMemo;
    UClblLines: TLabel;
    UURmemMsgLog: TMemo;
    UCmemMsgLog: TMemo;
    VCmemMsgLog: TMemo;
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormDestroy(Sender: TObject);
    procedure GTbtnResumeClick(Sender: TObject);
    procedure GTHEEventListSelectionChange(Sender: TObject; User: boolean);
    procedure GTHEspnedEventTimeEditingDone(Sender: TObject);
    procedure HHQueueEventMessageClick(Sender: TObject);
    procedure SGlbxGroupsSelectionChange(Sender: TObject; User: boolean);
    procedure SGlbxUnitsSelectionChange(Sender: TObject; User: boolean);
    procedure GTHEfuellingEditingDone(Sender: TObject);                           //ddt  start
    procedure GTHEspnedfuelEditingDone(Sender: TObject);
    procedure GTHEspnedUnitEditingDone(Sender: TObject);
    procedure GTHEEventListRefuelData(PRefuelEvent: PHCAirRefuelEvent; PThisEvent: PHCHarpoonEvent);          // ddt end
  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;
    HCdllCheckLatLonDepth: THCdllCheckLatLonDepth;
  end;

var
  frmMain: TfrmMain;
  PRefuelData: PHCAirRefuelEvent;    //ddt
  PEvent: PHCHarpoonEvent;

implementation

uses uLazGUIGlobals, uHCDefines, uHCEventHelpers;

{$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;

end;

procedure TfrmMain.GTbtnResumeClick(Sender: TObject);
begin
//  GTHEEventList.Clear;
//  GEHEmemDetail.Clear;
  GTckbPause.Checked:=False;
  GTbtnResume.Enabled:=False;
  GTckbPause.Enabled:=True;
  Byte(PDLLBusy^) := CFALSE; // ALE 20130816
  //ddt
    GTHEspnedfuel.Value:= 0;
    GTHEspnedUnit.Value:= 0;
    GTHEspnedID.Value:= 0;
    GTHEspnedavailable.Value:= 0;
    GTHEspedNxtAvailable.Value:= 0;
  // ddtend
end;



procedure TfrmMain.GTHEEventListSelectionChange(Sender: TObject; User: boolean);
var
  strSel: String;

  PEventMessage: PHCMessageEvent;

begin
  // ALE 20130317 User selected a group, pull up unit list.
  strSel := Copy(GTHEEventList.Items[GTHEEventList.ItemIndex], 12, 8);
  PEvent := PHarpEventHead;
  while (PEvent <> nil) do
  begin
    if (strSel = Format('%p', [PEvent])) then
       break;
    PEvent := PEvent^.next;
  end;

  // ALE 20130816 We found the event, do something.
  GEHEmemDetail.Clear;
  GEHEmemDetail.Lines.Add(Format('Pointer to Event: 0x%p', [PEvent]));
  GEHEmemDetail.Lines.Add(Format('Pointer to next Event: 0x%p', [PEvent^.next]));
  GEHEmemDetail.Lines.Add(Format('Event Type: %s', [HCEventType2String(PEvent^.flag AND CommandMask)]));
  GEHEmemDetail.Lines.Add(Format('Pointer to Group the Event applies to (if any): 0x%p', [PEvent^.ourGroup]));
  GEHEmemDetail.Lines.Add(Format('UnitID the Event applies to (if any): %3.3d', [PEvent^.UnitID]));
  GEHEmemDetail.Lines.Add(Format('Pointer to DataPtr: 0x%p', [PEvent^.DataPtr]));
  GEHEmemDetail.Lines.Add(Format('Event Time: %8.8d', [PEvent^.Time]));
  GEHEmemDetail.Lines.Add(Format('Event Time Type: %s', [HCEventTimeType2String(PEvent^.flag AND TimeMask)]));
  GEHEmemDetail.Lines.Add(Format('Event in_scroll_flag: %d', [PEvent^.in_scroll_flag]));
  if (PEvent^.flag AND CommandMask = MESSAGE_EVENT) then
  begin
    PEventMessage := PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('Message: %s', [PEventMessage^.Message]));
  end;
  // ddt start
  if (PEvent^.flag AND CommandMask = AIR_REFUEL_EVENT) then
  begin
  PRefuelData := PEvent^.DataPtr;
  GTHEEventListRefuelData(PRefuelData, PEvent);
  end;
  // ddt end
end;

procedure TfrmMain.GTHEspnedEventTimeEditingDone(Sender: TObject);
begin
  if PEvent <> nil then
  PEvent^.Time:= GTHEspnedEventTime.Value;
end;



procedure TfrmMain.GTHEEventListRefuelData(PRefuelEvent: PHCAirRefuelEvent; PThisEvent: PHCHarpoonEvent);
var
  N: Integer;
  PThisG: PHCGroup;
  PThisU: PHCUnit;
begin
  if (GTHEtglbxAutoPause.Checked) then
    begin                        //  bring up screen and pause,
      Byte(PDLLBusy^) := CTRUE; //  stop GE processing
      GTbtnResume.Enabled:=True;
      GTckbPause.Enabled:=False;
      PageControl1.ActivePageIndex:=21;
    end;
  PThisG:= PThisEvent^.ourGroup;
  GTHEspnedavailable.Value:= PRefuelEvent^.fuel_range;    // this was the fuel available before this refuel
  // look at some situations
    // 1- end of a refuel cycle
    if  (PRefuelEvent^.planestofuel[0]  = 255) and (PRefuelEvent^.fuel_range > 200) then
          begin                                 // at end of a cycle
            PRefuelEvent^.now_refueling := 0;   // prevent tanker going home
         PThisEvent^.Time:= PThisEvent^.Time + (20*60);   // delay 20 mins
         PRefuelEvent^.planestofuel[0]:= 205;             // start refuelling again
          end;
    // 2- refuelling a unit
      if  (PRefuelEvent^.planestofuel[0] < 200)
        and (PRefuelEvent^.now_refueling = 1)   then
      begin                        // calculating the total fuel
      PThisU:= PThisG^.Units;    // cycle thru group units to match with refuelled unit
        while (PThisU^.id <> PRefuelEvent^.planestofuel[0]) do    //not got right unit
              PThisU := PThisU^.next;                      // should check for nil nextunit too
          GTHEspedNxtAvailable.Value:= (PThisU^.Air^.PlatNow * PRefuelEvent^.fuel_per_plane[0]);
          PRefuelEvent^.fuel_range:= PRefuelEvent^.fuel_range - GTHEspedNxtAvailable.Value;
      end;

    // now fill in refuel cycle data

    GTHElblGrpID.Caption:= Format('%2.2s', [PThisG^.id]);
    GEHEmemDetail.Lines.Add(Format('Group: %2.2s', [PThisG^.id]));        //event.targetgroup=blank? PThisG^.id
    GEHEmemDetail.Lines.Add(Format('Fueling Unit: %3.3d', [PRefuelEvent^.fuelingUnit]));
    GEHEmemDetail.Lines.Add(Format('Tanker Type: %3.3d',[PRefuelEvent^.which_plane_type]));
    GEHEmemDetail.Lines.Add(Format('Number of Tankers: %2.2d', [PRefuelEvent^.num_tankers]));  // +128 for altR refuel
    GEHEmemDetail.Lines.Add(Format('Fueling: %3.3d', [PRefuelEvent^.now_refueling]));   // 0=No, 1= yes
    GEHEmemDetail.Lines.Add(Format('Fuel Range: %4.4d', [PRefuelEvent^.fuel_range]));   // this may have been recalced
    GEHEmemDetail.Lines.Add('. . . . . . . .');

    // now do each unit refuel info

    N := 0;
    repeat
    begin
    GEHEmemDetail.Lines.Add(Format('# %d: unit %2.2d', [N, PRefuelEvent^.planestofuel[N]]));
    If PRefuelEvent^.planestofuel[N] = 255 then
      GEHEmemDetail.Lines.Add('Refuel cycle finished')
      else
      if PRefuelEvent^.planestofuel[N] = 205 then
        GEHEmemDetail.Lines.Add('Awaiting start of refuel?')
        else
        GEHEmemDetail.Lines.Add(Format('Per Plane Amount: %4.4d', [PRefuelEvent^.fuel_per_plane[N]]));
    N := N+1;
    end;
    until  PRefuelEvent^.planestofuel[N-1] > 200;

       // insert data to respective spin box
    GTHEspnedUnit.Value:= 0;
    GTHEspnedID.Value:= PRefuelEvent^.planestofuel[0];
    GTHEspnedfuel.Value := PRefuelEvent^.fuel_per_plane[0];
    GTHEspnedEventTime.Value:= PThisEvent^.Time;
    GTHEfuelling.Value:= PRefuelEvent^.now_refueling;

    // now fill in unit info box
    begin
      GTHElbxAirUnitsInfo.Items.Clear;
      GTHElbxAirUnitsInfo.Sorted := True;
      PThisU := PThisG^.Units;
      while (PThisU <> nil) do
      begin
        GTHElbxAirUnitsInfo.Items.Add(Format('%0.3d %2.2d - %s  %4.4d', [PThisU^.id,  PThisU^.Air^.PlatNow, PThisU^.name,
            PThisU^.Air^.Endurance]));
        PThisU := PThisU^.next;
      end;
    end;
     PRefuelData:= PRefuelEvent;
end; //ddt end

procedure TfrmMain.GTHEfuellingEditingDone(Sender: TObject);     //ddt
begin
  PRefuelData^.now_refueling:= GTHEfuelling.Value;
  if (GTHEfuelling.Value = 0) then
              PRefuelData^.targetGroup := ' ';  // ensure not flagged as intemeadiate refuels of cycle
end;

procedure TfrmMain.GTHEspnedfuelEditingDone(Sender: TObject);   //ddt
var
N: Integer;

begin
  N:= GTHEspnedUnit.Value;
  PRefuelData^.planestofuel[N]:= GTHEspnedID.Value;
  PRefuelData^.fuel_per_plane[N] := GTHEspnedfuel.Value;
  PRefuelData^.fuel_range:= GTHEspnedavailable.Value;
  PRefuelData^.now_refueling:= GTHEfuelling.Value;

end;

procedure TfrmMain.GTHEspnedUnitEditingDone(Sender: TObject);       //ddt
var
N: Integer;

begin
  N:= GTHEspnedUnit.Value;
  GTHEspnedID.Value:= PRefuelData^.planestofuel[N];
  GTHEspnedfuel.Value := PRefuelData^.fuel_per_plane[N];
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^.flag:=MESSAGE_EVENT OR TimeDelta;
  PHarpoonEvent^.next:=nil;
  PHarpoonEvent^.ourGroup:=nil;
  PHarpoonEvent^.UnitID:=0;
  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';
  Byte(uLazGUIGlobals.PDLLBusy^) := CTRUE;
  HCQueueHarpoonEvent(PHarpoonEvent);
  Byte(uLazGUIGlobals.PDLLBusy^) := CFALSE;
end;

procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
end;

procedure TfrmMain.SGlbxUnitsSelectionChange(Sender: TObject; User: boolean);
var
  strSel: String;
  PHCUThis: PHCUnit;
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('%2.2s%0.3d %s', [PHCGroup(PSelectedUnit^.Group)^.id,
          PSelectedUnit^.id, PSelectedUnit^.name]);
      If (PSelectedUnit^.Air <> nil) then                 //ddt
        SGlblUnitInfo.Caption:= Format('quantity: %2.2d, Endurance: %5.5d',[PSelectedUnit^.Air^.PlatNow,
          PSelectedUnit^.Air^.Endurance]);

    end;
end;

end.

