// Copyright 2017 Schmolders
// Adds support for Argo Ulisse 13 DCI Mobile Split ACs.

// Supports:
//   Brand: Argo,  Model: Ulisse 13 DCI Mobile Split A/C

#ifndef IR_ARGO_H_
#define IR_ARGO_H_

#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
#ifdef UNIT_TEST
#include "IRsend_test.h"
#endif


//  ARGO Ulisse DCI

/*
	Protocol Description:
  All in LSB first as it is sent. argo message array will be stored MSB first!
  do LSB-MSB conversion in sendData
  Byte 0: const 0	0	1	1	0	1	0	1
  Byte 1: const 1	0	1	0	1	1	1	1
  Byte 2: 0 0 0, 3bit Cool/Heat Mode, 2bit start SetTemp LSB first
  Byte 3: 3bit End SetTemp, 2bit Fan Mode, 3bit RoomTemp LSB first
  Byte 4: 2bit RoomTemp, 3bit Flap Mode, 3bit OnTimer
  Byte 5: 8bit OnTimer
  Byte 6: 8Bit OffTimer
  Byte 7: 3bit OffTimer, 5bit Time
  Byte 8: 6bit Time, 1bit Timer On/Off, 1bit Timer Program
  Byte 9: 1bit Timer Program, 1bit Timer 1h, 1 bit Night Mode, 1bit Max Mode, 1bit Filter, 1bit on/off, 1bit const 0, 1bit iFeel
  Byte 10: 2bit const 0 1, 6bit Checksum
  Byte 11: 2bit Checksum
*/

// Constants. Store MSB left.

// byte[2]
const uint8_t kArgoHeatBit =      0b00100000;
const uint8_t kArgoModeMask =     0b00111000;
const uint8_t kArgoTempLowMask =  0b11000000;
const uint8_t kArgoCool =           0b000;  // 0b000 (LSB) 0
const uint8_t kArgoDry =            0b001;  // 0b100 (LSB) 1
const uint8_t kArgoAuto =           0b010;  // 0b010 (LSB) 2
const uint8_t kArgoOff =            0b011;  // 0b110 (LSB) 3
const uint8_t kArgoHeat =           0b100;  // 0b001 (LSB) 4
const uint8_t kArgoHeatAuto =       0b101;  // 0b101 (LSB) 5
// ?no idea what mode that is
const uint8_t kArgoHeatBlink = 0b110;  // 0b011 (LSB) 6

// byte[3]
const uint8_t kArgoTempHighMask =    0b00000111;
const uint8_t kArgoFanMask =         0b00011000;
const uint8_t kArgoRoomTempLowMask = 0b11100000;
const uint8_t kArgoFanAuto = 0;  // 0b00
const uint8_t kArgoFan3 = 3;  // 0b11
const uint8_t kArgoFan2 = 2;  // 0b01
const uint8_t kArgoFan1 = 1;  // 0b10

// byte[4]
const uint8_t kArgoRoomTempHighMask = 0b00000011;
const uint8_t kArgoTempOffset = 4;
const uint8_t kArgoMaxRoomTemp = ((1 << 5) - 1) + kArgoTempOffset;  // 35C

// byte[9]
const uint8_t kArgoPowerBit = 0b00100000;
const uint8_t kArgoMaxBit =   0b00001000;
const uint8_t kArgoNightBit = 0b00000100;
const uint8_t kArgoIFeelBit = 0b10000000;

const uint8_t kArgoMinTemp = 10;  // Celsius offset +4
const uint8_t kArgoMaxTemp = 32;  // Celsius

const uint8_t kArgoFlapAuto = 0;  // 0b000
const uint8_t kArgoFlap1 = 1;  // 0b100
const uint8_t kArgoFlap2 = 2;  // 0b010
const uint8_t kArgoFlap3 = 3;  // 0b110
const uint8_t kArgoFlap4 = 4;  // 0b001
const uint8_t kArgoFlap5 = 5;  // 0b101
const uint8_t kArgoFlap6 = 6;  // 0b011
const uint8_t kArgoFlapFull = 7;  // 0b111

// Legacy defines. (Deperecated)
#define ARGO_COOL_ON              kArgoCoolOn
#define ARGO_COOL_OFF             kArgoCoolOff
#define ARGO_COOL_AUTO            kArgoCoolAuto
#define ARGO_COOL_HUM             kArgoCoolHum
#define ARGO_HEAT_ON              kArgoHeatOn
#define ARGO_HEAT_AUTO            kArgoHeatAuto
#define ARGO_HEAT_BLINK           kArgoHeatBlink
#define ARGO_MIN_TEMP             kArgoMinTemp
#define ARGO_MAX_TEMP             kArgoMaxTemp
#define ARGO_FAN_AUTO             kArgoFanAuto
#define ARGO_FAN_3                kArgoFan3
#define ARGO_FAN_2                kArgoFan2
#define ARGO_FAN_1                kArgoFan1
#define ARGO_FLAP_AUTO            kArgoFlapAuto
#define ARGO_FLAP_1               kArgoFlap1
#define ARGO_FLAP_2               kArgoFlap2
#define ARGO_FLAP_3               kArgoFlap3
#define ARGO_FLAP_4               kArgoFlap4
#define ARGO_FLAP_5               kArgoFlap5
#define ARGO_FLAP_6               kArgoFlap6
#define ARGO_FLAP_FULL            kArgoFlapFull


class IRArgoAC {
 public:
  explicit IRArgoAC(const uint16_t pin, const bool inverted = false,
                    const bool use_modulation = true);

#if SEND_ARGO
  void send(const uint16_t repeat = kArgoDefaultRepeat);
  uint8_t calibrate(void) { return _irsend.calibrate(); }
#endif  // SEND_ARGO
  void begin(void);
  void on(void);
  void off(void);

  void setPower(const bool on);
  bool getPower(void);

  void setTemp(const uint8_t degrees);
  uint8_t getTemp(void);

  void setFan(const uint8_t fan);
  uint8_t getFan(void);

  void setFlap(const uint8_t flap);
  uint8_t getFlap(void);

  void setMode(const uint8_t mode);
  uint8_t getMode(void);

  void setMax(const bool on);
  bool getMax(void);

  void setNight(const bool on);
  bool getNight(void);

  void setiFeel(const bool on);
  bool getiFeel(void);

  void setTime(void);
  void setRoomTemp(const uint8_t degrees);
  uint8_t getRoomTemp(void);

  uint8_t* getRaw(void);
  void setRaw(const uint8_t state[]);
  static uint8_t calcChecksum(const uint8_t state[],
                              const uint16_t length = kArgoStateLength);
  static bool validChecksum(const uint8_t state[],
                            const uint16_t length = kArgoStateLength);
  static uint8_t convertMode(const stdAc::opmode_t mode);
  static uint8_t convertFan(const stdAc::fanspeed_t speed);
  static uint8_t convertSwingV(const stdAc::swingv_t position);
  static stdAc::opmode_t toCommonMode(const uint8_t mode);
  static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
  stdAc::state_t toCommon(void);
  String toString();
#ifndef UNIT_TEST

 private:
  IRsend _irsend;  // instance of the IR send class
#else
  IRsendTest _irsend;  // instance of the testing IR send class
#endif
  // # of bytes per command
  uint8_t argo[kArgoStateLength];  // Defined in IRremoteESP8266.h
  void stateReset(void);
  void checksum(void);

  // Attributes
  uint8_t flap_mode;
  uint8_t heat_mode;
  uint8_t cool_mode;
};

#endif  // IR_ARGO_H_
