unit SimulatedSensor;

  interface
    uses
      AdsData          (* used by AdsFunc *),
      AdsFunc          (* used by AdsTable *),
      AdsTable         (* tAdsQuery *),
      Buttons          (* tBitBtn *),
      Classes          (**),
      Controls         (**),
      DB               (* used by AdsTable *),
      ExtCtrls         (* tRadioGroup *),
      Forms            (* tForm *),
      LabeledSpinEdits (* tLabeledSpinFloat, tLabeledSpinInteger *),
      RRFSpinBase      (* used by LabeledSpinEdits *),
      StdCtrls         (* tButton, tGroupBox, tLabel; also used by ExtCtrls *),
      Windows          (**);

    type
      tfmSimulatedSensor = class(tForm)
          qNewFridgeSetting: tAdsQuery;
          btnCancel: tBitBtn;
          btnOK:     tBitBtn;
          grpDewpoint: tGroupBox;
            btnGoForDP: tButton;
            lbspflTempFforDP: tLabeledSpinFloat;
            lbspintRH: tLabeledSpinInteger;
          grpHumidex: tGroupBox;
            btnGo: tButton;
            lbHumidex: tLabel;
            lbspflDewpointF: tLabeledSpinFloat;
            lbspflTempF:     tLabeledSpinFloat;
          lbspflGCFridgeSetting: tLabeledSpinFloat;
          rgWhatSimulated: tRadioGroup;

          procedure btnCancelClick (Sender: tObject);
          procedure btnGoClick     (Sender: tObject);
          procedure btnGoForDPClick(Sender: tObject);
          procedure btnOKClick     (Sender: tObject);
          procedure FormShow       (Sender: tObject);
        private
          dtLastTableEntry: tDateTime;
          SettingX10: integer;
          procedure NewFridgeSetting(const LocalWhen: tDateTime);
        public
          procedure Initialize;
        end (* tfmSimulatedSensor *);

    var
      fmSimulatedSensor: tfmSimulatedSensor;

  implementation
    uses
      DateUtils              (* DateOf, IncDay, IncSecond, StartOfTheDay, Today *),
      HC3Utilities           (* CtoF, FtoC, INILoadDateTime, INILoadInteger,
                                  INISaveDateTime, INISaveInteger, LastUIDOf *),
      MyConsts               (* UsualFormColor *),
      RRF_StringAndTimeUtils (* LocalToUTC *),
      Table_Generic_Helper   (* GetDewPointF, GetHumidexF *),
      SysUtils               (* Now *);
      {$R *.dfm}

    procedure tfmSimulatedSensor.btnCancelClick(Sender: tObject);
      (* give up *)
    
      begin (* tfmSimulatedSensor.btnCancelClick *)
        Close
      end   (* tfmSimulatedSensor.btnCancelClick *);

    procedure tfmSimulatedSensor.btnOKClick(Sender: tObject);
      (* simple for any specific table entry *)

      begin (* tfmSimulatedSensor.btnOKClick *)
        case rgWhatSimulated.ItemIndex of
          0: begin (* catch up edge, install new data *)
               NewFridgeSetting(IncSecond(Now, -1));
               SettingX10 := round(10 * lbspflGCFridgeSetting.Value);
               NewFridgeSetting(Now)
             end   (* catch up edge, install new data *)
          end (* degenerate case on radiogroup *);

        Close
      end   (* tfmSimulatedSensor.btnOKClick *);

    procedure tfmSimulatedSensor.FormShow(Sender: tObject);
      (* initialize *)

      begin (* tfmSimulatedSensor.FormShow *)
        self.Color := UsualFormColor;
        lbHumidex.Visible := false
      end   (* tfmSimulatedSensor.FormShow *);

    procedure tfmSimulatedSensor.Initialize;
      (* called from Main.  Catchup to today.  Pattern is that of OnOff *)
    
      const
        DefaultSettingX10 = 20;

      begin (* tfmSimulatedSensor.Initialize *)
        SettingX10       := INILoadInteger ('garbage-closet fridge', 'FridgeSettingX10', DefaultSettingX10);
        dtLastTableEntry := INILoadDateTime(                         'LastTableEntry', Now);

        while DateOf(dtLastTableEntry) < DateOf(Today) do
          begin (* force start of today *)
            NewFridgeSetting(LastSecondOfTheDay(dtLastTableEntry));
            dtLastTableEntry := StartOfTheDay(IncDay(dtLastTableEntry));
            NewFridgeSetting(dtLastTableEntry)
          end   (* force start of today *);
        dtLastTableEntry := Now;
        NewFridgeSetting(dtLastTableEntry);
        
        lbspflGCFridgeSetting.Value := SettingX10 / 10.0
      end   (* tfmSimulatedSensor.Initialize *);

    procedure tfmSimulatedSensor.NewFridgeSetting(const LocalWhen: tDateTime);
      (* update the table and the INI *)

      var
        NewUID: integer;

      begin (* tfmSimulatedSensor.NewFridgeSetting *)
          NewUID := LastUIDOf('TRHP') + 1;
          with qNewFridgeSetting do
            begin (* qNewFridgeSetting *)
              ParamByName('TempF'          ).AsFloat    := SettingX10;
              ParamByName('UID'            ).AsInteger  := NewUID;
              ParamByName('WhenRecorded'   ).AsDateTime := LocalWhen;
              ParamByName('WhenRecordedUTC').AsDateTime := LocalToUTC(LocalWhen);
              ExecSQL
            end   (* qNewFridgeSetting *);
        INISaveInteger ('garbage-closet fridge', 'FridgeSettingX10', SettingX10);
        INISaveDateTime(                         'LastTableEntry',  dtLastTableEntry)
      end   (* tfmSimulatedSensor.NewFridgeSetting *);

    procedure tfmSimulatedSensor.btnGoClick(Sender: tObject);
      (* calculate *)

      var
        HumidexF: real;

      begin (* tfmSimulatedSensor.btnGoClick *)
        HumidexF := GetHumidexF(FtoC(lbspflTempF.Value), FtoC(lbspflDewpointF.Value));
        with lbHumidex do
          Caption := Format('Humidex = %.1f °F (%.1f °C)', [HumidexF, FtoC(HumidexF)]);
        lbHumidex.Visible := true
      end   (* tfmSimulatedSensor.btnGoClick *);

    procedure tfmSimulatedSensor.btnGoForDPClick(Sender: tObject);
      (* other form doed the work *)

      var
        DewPointF: real;

      begin (* tfmSimulatedSensor.btnGoForDPClick *)
        if GetDewPointF(lbspflTempFforDP.Value, lbspintRH.Value, DewpointF) then
          begin (* success *)
            lbspflTempF.Value := lbspflTempFforDP.Value;
            lbspflDewpointF.Value := DewPointF
          end   (* success *)
      end   (* tfmSimulatedSensor.btnGoForDPClick *);

end.
