unit uMount;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, AbNumEdit, Registry, ExtCtrls, _GClass, AbGradient, Math,
  uSETICommon, ComCtrls, AbLED, OleCtrls, DBOleCtl, ILLinearGauge, Mitov.Types,
  SLComponentCollection, SLControlCollection, ILAngularGauge, Mitov.VCLTypes, VCL.LPControl,
  LPControlDrawLayers, LPTransparentControl, ULBasicControl, ILAnalogInstrument, VCL.Samples.Spin, JvExControls, JvSpin;

const
  CLongitude = -117.1490099; // SETI Net Antenna  from ublox EVK-6T evaluation kit 2012-07-23
  CLatitude = 32.569866;

  SETINetMountKey = '\SOFTWARE\SETI Net\Mount'; // PUT A SPACE in SETI Net Dammit JIM

  AzimuthNeedleID = 3;
  AzStartNeedleID = 1;
  AzStopNeedleID = 0;

  ElevationNeedleID = 3;
  ElYellowNeedleID = 0;
  ElRedNeedleID = 1;

  annularAz = 0;
  annularElBottom = 1;
  annularElTop = 0;

type

  TClientProcedureAsParameter = procedure;

type
  TfrmMount = class(TForm)
    gbMount: TGroupBox;
    rgMount: TRadioGroup;
    gbElRange: TGroupBox;
    nsLatitude: TAbNumSpin;
    lblLatitude: TLabel;
    nsLongitude: TAbNumSpin;
    lblLongitude: TLabel;
    lblHPBW: TLabel;
    nsOpFreq: TAbNumSpin;
    lblOpFreq: TLabel;
    nsDishDia: TAbNumSpin;
    lblDishDia: TLabel;
    btnReset: TButton;
    lblGridSquare: TLabel;
    edGridSquare: TEdit;
    lblZoneCenter: TLabel;
    nsZoneWidth: TAbNumSpin;
    nsElStart: TAbNumSpin;
    nsElStop: TAbNumSpin;
    lblElStop: TLabel;
    lblElStart: TLabel;
    gZone: TILAngularGauge;
    ndlZone: TILExternalGaugeControlHandElement;
    lblZoneWidth: TLabel;
    neZoneCenter: TAbNumEdit;
    spinZoneCenter: TJvSpinButton;
    gElMinMax: TILLinearGauge;
    ndlElStop: TILExternalLinearGaugeControlHandElement;
    ndlElStart: TILExternalLinearGaugeControlHandElement;
    function getNewAntennaAzElAvailable: boolean;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    procedure btnResetClick(Sender: TObject);
    procedure nsLongitudeValueChanged(Sender: TObject);
    procedure nsLatitudeValueChanged(Sender: TObject);
    procedure rgMountClick(Sender: TObject);

    procedure nsElStartValueChanged(Sender: TObject);
    procedure nsElStopValueChanged(Sender: TObject);
    procedure ndlElStartChange(Sender: TObject; AValue, AMin, AMax: Real);
    procedure ndlElStopChange(Sender: TObject; AValue, AMin, AMax: Real);
    procedure ndlZoneCenterSelectChange(Sender: TObject; AValue, AMin, AMax: Real);
    procedure nsZoneWidthValueChanged(Sender: TObject);
    procedure nsZoneCenterValueChanged(Sender: TObject);
    procedure spinZoneCenterTopClick(Sender: TObject);
    procedure spinZoneCenterBottomClick(Sender: TObject);
    procedure FormDblClick(Sender: TObject);
    procedure ndlZoneChange(Sender: TObject; AValue, AMin, AMax: Real);

  private
    { Private declarations }
    FHPBW: TDegrees;
    FOpFreq: Single;

    FLongitude: TDegrees;
    FLatitude: TDegrees;

    FAzimuth: TDegrees;
    FElevation: TDegrees;

    FElStart: TDegrees;
    FElStop: TDegrees;
    FAzStart: TDegrees;
    FAzStop: TDegrees;

    FDiameter: Real;

    Function getHPBW: TDegrees;
    procedure setLongitude(value: TDegrees);
    procedure setLatitude(value: TDegrees);
    procedure setAzimuth(value: TDegrees);
    procedure setElevation(value: TDegrees);
    function getGridSquare: string;
    function getAzStart: TDegrees;
    function getAzStop: TDegrees;
    function getElStart: TDegrees;
    function getElStop: TDegrees;

  public
    { Public declarations }
    InUse: boolean;
    Mount: TMount;

    procedure setElBlack(value: double);
    procedure setAzBlack(value: double);
    function getElBlack: double;
    function getAzBlack: double;

    procedure NotifyUserOfChange;
    // procedure Callback(ClientProcedureAsParameter: TClientProcedureAsParameter);
    function InZone(TestValue: Integer; var Dif: Integer): boolean;
    Property HPBW: TDegrees read getHPBW;
    Property OpFreq: Single read FOpFreq;
    Property Longitude: TDegrees read FLongitude write setLongitude;
    Property Latitude: TDegrees read FLatitude write setLatitude;
    Property Azimuth: TDegrees read FAzimuth write setAzimuth;
    Property Elevation: TDegrees read FElevation write setElevation;

    Property Diameter: Real read FDiameter write FDiameter;

    Property GridSquare: string read getGridSquare;

    Property AzStop: TDegrees read getAzStop write FAzStop;
    Property AzStart: TDegrees read getAzStart write FAzStart;

    Property ElStop: TDegrees read getElStop write FElStop;
    Property ElStart: TDegrees read getElStart write FElStart;
    Property CheckNewAntAvailable: boolean Read getNewAntennaAzElAvailable;
    Property ELBlack: double read getElBlack write setElBlack;
    Property AzBlack: double read getAzBlack write setAzBlack;
  end;

var
  frmMount: TfrmMount;
  CallbackProcedureInClient: TClientProcedureAsParameter;
  SETINetReg: TRegistry;

implementation

{$R *.dfm}
{$IF Defined(SkyMap)}

uses uAntenna, uSkyMap;
{$IFEND}
{$IF Defined(MOUNT)}

uses uAntenna, uSkyMap;
{$IFEND}
{$IF Defined(SETI)}

uses
  uSkyMap, uAntenna;
{$IFEND}
{$IF Defined(CLOCK)}

uses
  uSkyMap;
{$IFEND}
//
{$IF Defined(Antenna)}

uses
  uSkyMap, uAntenna;
{$IFEND}
{$REGION ' (* F o r m  C r e a t e *) ' }

procedure TfrmMount.FormCreate(Sender: TObject);
(* F o r m  C r e a t e *)
begin

  (* REGISTRY ENTRIES *)

  SETINetReg := TRegistry.Create;
  SETINetReg.LazyWrite := false;
  try
    SETINetReg.RootKey := HKEY_CURRENT_USER;
    if SETINetReg.KeyExists(SETINetMountKey) then
    begin { Key Exists }
      if SETINetReg.OpenKey(SETINetMountKey, false) then
      // OpenKey will create the key if the second parameter is TRUE and the key does not already exist
      // This one will NOT create the key
      begin // openkey
        try
          with SETINetReg do
          begin
            SETINetReg.OpenKey(SETINetMountKey, false);

            Mount := TMount(ReadInteger('MountType'));
            rgMount.ItemIndex := Integer(Mount);
            ndlZone.value := ReadInteger('ZoneCenter');

            nsZoneWidth.ValueAsInt := ReadInteger('ZoneWidth');
            nsElStop.ValueAsInt := ReadInteger('ElStop');
            nsElStart.ValueAsInt := ReadInteger('ElStart');

            edGridSquare.Text := ReadString('GridSquare');
            nsLongitude.value := ReadFloat('Longitude');
            nsLatitude.value := ReadFloat('Latitude');
          end { with SETINetReg }
        except // an exception is raised if there isn't a version entry
          SETINetReg.DeleteKey(SETINetMountKey); // If the version value didn't exist delete the whole key
        end; // Open Key
      end; // Open Key
    End; // SETINetMountKey exists

    if not SETINetReg.KeyExists(SETINetMountKey) then // D E F A U L T   R E G   E N T R I E S
    begin // New User or incomplete registry entries so rebuild.
      with SETINetReg do
      begin
        OpenKey(SETINetMountKey, True);
        Longitude := CLongitude;
        Latitude := CLatitude;
        ndlZone.value := 180;
        nsZoneWidth.ValueAsInt := 10;
        ndlElStop.value := 90.0;
        ndlElStart.value := 0;

        Azimuth := 180;
        Elevation := 19.7;
        Mount := mtAzEl;
        edGridSquare.Text := 'DM12jw';
      end;
    end;
  finally // Setup Clock
    SETINetReg.Free;
  end;
  // nsAzStop.value := ndlAzStop.value;
  // nsAzStart.value := ndlAzStart.value;
  // gFlyZone.value := ndlAzStop.value;

end;

procedure TfrmMount.FormDblClick(Sender: TObject);
begin

end;

// Form Create
{$ENDREGION}

//
function TfrmMount.InZone(TestValue: Integer; var Dif: Integer): boolean;

begin
  result := false;

  If InRange(TestValue, Trunc(ndlZone.value) - (nsZoneWidth.ValueAsInt DIV 2), Trunc(ndlZone.value) + (nsZoneWidth.ValueAsInt DIV 2)) then
  begin
    result := True
  end;
  if (ndlZone.value + nsZoneWidth.ValueAsInt div 2 > 360) then
  begin
    If InRange(TestValue, ndlZone.value + (nsZoneWidth.ValueAsInt div 2), 360) then
    begin
      result := True
    end;

    if InRange(TestValue, 0, Width div 2) then
    begin
      result := True
    end;
  end;

  Dif := TestValue - Trunc(ndlZone.value);

end;

function TfrmMount.getElBlack: double;
begin
  result := gElMinMax.value;
end;

function TfrmMount.getAzBlack: double;
begin
  result := gZone.value;
end;

procedure TfrmMount.setElBlack(value: double);
begin
  gElMinMax.value := value;
  // Elevation := value;
end;

procedure TfrmMount.setAzBlack(value: double);
begin
  gZone.value := value;

end;

function TfrmMount.getNewAntennaAzElAvailable: boolean;

begin

  if frmSkyMap.NewAntAvailable then // First Check in with SkyMap
  begin // Yes there is a new antenna position so go get Az/El

{$IF Defined(SETI)}
    if (frmAntenna.Ready) then
{$ENDIF}
    begin
{$IF Not Defined(Clock)}
      frmAntenna.AzYellow := frmSkyMap.MouseAz;
      frmAntenna.ElYellow := frmSkyMap.MouseEl;
{$ENDIF}
{$IF Defined(Clock)}
      AzBlack := frmSkyMap.MouseAz;
      ELBlack := frmSkyMap.MouseEl;
{$ENDIF}
    end;
    result := True;
  end
  else // Nothing new
    result := false;
end;

function TfrmMount.getGridSquare: string;
begin
  result := edGridSquare.Text;
end;

function TfrmMount.getAzStart: TDegrees;
begin
  result := neZoneCenter.ValueAsInt + (nsZoneWidth.ValueAsInt div 2);
end;

function TfrmMount.getAzStop: TDegrees;
begin
  result := neZoneCenter.ValueAsInt - (nsZoneWidth.ValueAsInt div 2);
end;

function TfrmMount.getElStart: TDegrees;
begin
  result := nsElStart.value
end;

function TfrmMount.getElStop: TDegrees;
begin
  result := nsElStop.value;
end;

Function TfrmMount.getHPBW: TDegrees;
var
  W: Real;
begin
  FOpFreq := nsOpFreq.value * 1000000;
  W := (299792458 / (OpFreq));
  FHPBW := RadToDeg(W / nsDishDia.value); // HPBW = W/Dia
  lblHPBW.Caption := 'HPBW: ' + FloatToStrF((FHPBW), ffGeneral, 2, 2) + ' deg.';
  result := FHPBW;
end;

procedure TfrmMount.setLongitude(value: TDegrees);
begin
  FLongitude := value;
  nsLongitude.value := value;
end;

procedure TfrmMount.spinZoneCenterBottomClick(Sender: TObject);
begin
  ndlZone.value := ndlZone.value - 1;
end;

procedure TfrmMount.spinZoneCenterTopClick(Sender: TObject);
begin
  ndlZone.value := ndlZone.value + 1;
end;

procedure TfrmMount.setLatitude(value: TDegrees);
begin
  FLatitude := value;
  nsLatitude.value := value;
end;

procedure TfrmMount.nsElStartValueChanged(Sender: TObject);
begin
  if nsElStart.value > ElStop then
  begin
    ndlElStart.value := ElStop - 0.1;
    beep();
  end
  else
  begin
    ndlElStart.value := nsElStart.value;
    FElStart := nsElStart.value;
  end;
end;

procedure TfrmMount.nsElStopValueChanged(Sender: TObject);
begin
  if nsElStop.value < ElStart then
  begin
    ndlElStop.value := ElStart + 0.1;
    beep();
  end
  else
  begin
    ndlElStop.value := nsElStop.value;
    FElStop := nsElStop.value;
  end;
end;

procedure TfrmMount.setAzimuth(value: TDegrees);
begin
  FAzimuth := value;
  gZone.value := FAzimuth;

end;

procedure TfrmMount.setElevation(value: TDegrees);
begin
  FElevation := value;
  // frmAntenna.ElYellow := (value - ElStart);
  gElMinMax.value := FElevation;
end;

procedure TfrmMount.btnResetClick(Sender: TObject);
begin
  edGridSquare.Text := 'DM12jw';
  Longitude := CLongitude;
  Latitude := CLatitude;
  Mount := mtAzEl;
  nsElStart.value := 9;
  nsElStop.value := 90;
  rgMount.ItemIndex := Integer(mtAzEl);
  Diameter := 3.0;
  Elevation := nsElStart.value;
  ndlZone.value := 181;
  nsZoneWidth.ValueAsInt := 2;

  nsOpFreq.value := 1420;
  nsDishDia.value := 3.2;
  gElMinMax.value := ElStart;

  with ndlZone do
  begin
    with Hand do
    begin
      Color := clRed;

      Length.Proportional := True;
      Length.value := 0.8;

      TailIndentSize.Proportional := True;
      TailIndentSize.value := 1;

      TailLength.Proportional := false;
      TailLength.value := 1;

      TailWidth.Proportional := false;
      TailWidth.value := 0.01;

      TipWidth.Proportional := false;
      TipWidth.value := 10;
      nsZoneWidthValueChanged(Self);
    end;
  end;
end;

// procedure TfrmMount.Callback(ClientProcedureAsParameter: TClientProcedureAsParameter);
// begin
// CallbackProcedureInClient := ClientProcedureAsParameter;
// end;

procedure TfrmMount.NotifyUserOfChange;
begin
  // Something in the Antenna Parameters user interface changed so notify the user (if any )
  // if Assigned(CallbackProcedureInClient) then
  // CallbackProcedureInClient;
end;

// function TfrmMount.InNoFly(value: integer): boolean;
// (* I n   N o  F L Y   Z o n e *)
// begin
// result := false;
// // if (ndlAzStart.value < ndlAzStop.value) then
// if True then
//
// begin // Normal
// // if ((Azimuth > nsAzStart.value) and (Azimuth < nsAzStart.value)) then
// result := True;
// end
// else
// begin // Reversed
// // if ((Azimuth < nsAzStart.value) and (Azimuth > nsAzStart.value)) then
// result := True;
// end;
//
// end;

(* =================  G E T T E R S  and  S E T T E R S   ================== *)

procedure TfrmMount.ndlElStartChange(Sender: TObject; AValue, AMin, AMax: Real);
begin
  nsElStart.value := AValue;
end;

procedure TfrmMount.ndlElStopChange(Sender: TObject; AValue, AMin, AMax: Real);
begin
  nsElStop.value := AValue;
end;

procedure TfrmMount.ndlZoneCenterSelectChange(Sender: TObject; AValue, AMin, AMax: Real);
begin
  ndlZone.value := ndlZone.value;
  neZoneCenter.ValueAsInt := Trunc(ndlZone.value);
end;

procedure TfrmMount.ndlZoneChange(Sender: TObject; AValue, AMin, AMax: Real);
begin
  neZoneCenter.ValueAsInt := Trunc(ndlZone.value);
end;

procedure TfrmMount.nsLatitudeValueChanged(Sender: TObject);
begin
  FLatitude := nsLatitude.value;
end;

procedure TfrmMount.nsLongitudeValueChanged(Sender: TObject);
begin
  FLongitude := nsLongitude.value;
end;

procedure TfrmMount.nsZoneCenterValueChanged(Sender: TObject);
begin
  ndlZone.value := neZoneCenter.ValueAsSingle;
end;

procedure TfrmMount.nsZoneWidthValueChanged(Sender: TObject);
begin
  ndlZone.Hand.TipWidth.value := nsZoneWidth.value + 5; // Jim the 15 'adjusts' tip width to look right
end;

procedure TfrmMount.rgMountClick(Sender: TObject);
begin
  // TMountType = (mtDrift, mtAllSky);
  case TMount(rgMount.ItemIndex) of
    mtDrift:
      Mount := mtDrift;
    mtAzEl:
      Mount := mtAzEl;
    mtBirdBath:
      Mount := mtBirdBath;
  end;
end;

procedure TfrmMount.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  SETINetReg := TRegistry.Create;
  try
    with SETINetReg do
    begin
      RootKey := HKEY_CURRENT_USER;
      DeleteKey(SETINetMountKey); // Kill the whole key every time.
      OpenKey(SETINetMountKey, True);
      // OpenKey will create the key if the second parameter is true and the key does not already exist
      WriteInteger('MountType', Integer(Mount));
      WriteFloat('OpFreq', nsOpFreq.value);
      WriteFloat('Latitude', Latitude);
      WriteFloat('Longitude', Longitude);
      WriteFloat('Azimuth', Azimuth);
      WriteFloat('Elevation', Elevation);

      WriteInteger('ElStart', nsElStart.ValueAsInt);
      WriteInteger('ElStop', nsElStop.ValueAsInt);

      WriteInteger('ZoneCenter', Trunc(ndlZone.value));
      WriteInteger('ZoneWidth', nsZoneWidth.ValueAsInt);
      WriteString('GridSquare', edGridSquare.Text);
      CloseKey;
    end; { SETINetReg }
  finally
    SETINetReg.Free;
  end; // try..finally

end;

end.
