#include "../tw7100.h"
#include "tw7100_select.h"
#include "esphome/core/log.h"
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"

namespace esphome {
namespace tw7100 {

std::map<std::string, std::string> tw7100Select::sources = {
  {"30", "HDMI1"},
  {"53", "LAN"},
  {"A0", "HDMI2"}
};
std::map<std::string, std::string> tw7100Select::luminance = {
  {"00", "Normal"},
  {"01", "Eco"},
  {"02", "Medium"}
};
std::map<std::string, std::string> tw7100Select::aspect = {
  {"00", "Normal"},
  {"30", "Auto"},
  {"40", "Full"},
  {"50", "Zoom"},
  {"80", "Anamorphic"},
  {"90", "Hsqueeze"}
};
std::map<std::string, std::string> tw7100Select::msel = {
  {"00", "Black"},
  {"01", "Blue"},
  {"02", "User logo"}
};
std::map<std::string, std::string> tw7100Select::speed = {
  {"00", "9600bps"},
  {"01", "19200bps"},
  {"02", "38400bps"},
  {"03", "57600bps"}
};
std::map<std::string, std::string> tw7100Select::mcfi = {
  {"00", "Off"},
  {"01", "Low"},
  {"02", "Normal"},
  {"03", "High"}
};
std::map<std::string, std::string> tw7100Select::clrspace = {
  {"00", "Auto"},
  {"01", "BT.709"},
  {"02", "BT.2020"}
};
std::map<std::string, std::string> tw7100Select::dynrange = {
  {"00", "Auto"},
  {"01", "SDR"},
  {"20", "HDR10"},
  {"30", "HLG"}
};
std::map<std::string, std::string> tw7100Select::imgpreset = {
  {"00", "Off"},
  {"01", "Setting 1"},
  {"02", "Setting 2"},
  {"03", "Setting 3"},
  {"04", "Setting 4"},
  {"05", "Setting 5"}
};
std::map<std::string, std::string> tw7100Select::gamma = {
  {"20", "Setting 2"},
  {"21", "Setting 1"},
  {"22", "Setting 0"},
  {"23", "Setting -1"},
  {"24", "Setting -2"},
  {"F0", "Custom"}
};
std::map<std::string, std::string> tw7100Select::cmode = {
  {"06", "Dynamic"},
  {"07", "Natural"},
  {"0C", "Bright Cinema"},
  {"15", "Cinema"}
};
std::map<std::string, std::string> tw7100Select::ovscan = {
  {"00", "Off"},
  {"02", "4%"},
  {"04", "8%"},
  {"A0", "Auto"}
};

std::vector<std::string> get_map_keys(std::map<std::string, std::string> map_) {
  std::vector<std::string> map_keys;
  for (auto element : map_) { map_keys.push_back(element.first); }
  return map_keys;
};

std::vector<std::string> get_map_values(std::map<std::string, std::string> map_) {
  std::vector<std::string> map_values;
  for (auto element : map_) { map_values.push_back(element.second); }
  return map_values;
};

void tw7100Select::setup() {
  static const char *const TAG = "tw7100Select::setup()";
  if (cmd_ == "SOURCE") {
    traits.set_options(get_map_values(sources));
  } else if (cmd_ == "LUMINANCE") {
    traits.set_options(get_map_values(luminance));
  } else if (cmd_ == "ASPECT") {
    traits.set_options(get_map_values(aspect));
  } else if (cmd_ == "OVSCAN") {
    traits.set_options(get_map_values(ovscan));
  } else if (cmd_ == "CMODE") {
    traits.set_options(get_map_values(cmode));
  } else if (cmd_ == "GAMMA") {
    traits.set_options(get_map_values(gamma));
  } else if (cmd_ == "IMGPRESET") {
    traits.set_options(get_map_values(imgpreset));
  } else if (cmd_ == "MCFI") {
    traits.set_options(get_map_values(mcfi));
  } else if (cmd_ == "CLRSPACE") {
    traits.set_options(get_map_values(clrspace));
  } else if (cmd_ == "DYNRANGE") {
    traits.set_options(get_map_values(dynrange));
  } else if (cmd_ == "MSEL") {
    traits.set_options(get_map_values(msel));
  } else if (cmd_ == "SPEED") {
    traits.set_options(get_map_values(speed));
  }
  ESP_LOGV(TAG, "setup done");
}

void tw7100Select::dump_config() {
  static const char *const TAG = "dump_config()";
  ESP_LOGCONFIG(TAG, "TW7100:");
  LOG_SELECT(TAG, "tw7100Select", this);
}

void tw7100Select::control(const std::string &value) {
  static const char *const TAG = "tw7100Select::control()";

  std::string param;
  if (cmd_ == "SOURCE") {
    for (auto element : sources) { if (element.second == value) { param = element.first; break; } }
  } else if (cmd_ == "LUMINANCE") {
    for (auto element : luminance) { if (element.second == value) { param = element.first; break; } }
  } else if (cmd_ == "ASPECT") {
    for (auto element : aspect) { if (element.second == value) { param = element.first; break; } }
  }

  if (param.length() > 0) {
    if (active_index() != index_of(value)) { // only send out commands if the value actually changed
      parent_->push_cmd(cmd_, param);
      ESP_LOGV("", "CMD: %s, PARAM: %s", cmd_.c_str(), param.c_str());
    }
  }
  publish_state(value); // but acknowledge everything

  ESP_LOGV(TAG, "control done");
};

}  // namespace tw7100
}  // namespace esphome