#include "galaxy.h"

#include <boost/format.hpp>
#include <exception>
#include <ostream>
#include <string>

// c++ default exceptions list
// https://en.cppreference.com/w/cpp/error/exception

bool buysell::operator==(const buysell &rhs) const {
  return ((foe[0] == rhs.foe[0]) && (foe[1] == rhs.foe[1]) &&
          (foe[2] == rhs.foe[2]));
}

std::ostream &operator<<(std::ostream &os, const buysell &bs) {
  os << bs.foe[0] << bs.foe[1] << bs.foe[2];
  return os;
}

bool buysell_text::operator==(const buysell_text &rhs) const {
  return ((txt[0] == rhs.txt[0]) && (txt[1] == rhs.txt[1]) &&
          (txt[2] == rhs.txt[2]));
}

std::ostream &operator<<(std::ostream &os, const buysell_text &bst) {
  os << '"' << bst.txt[0] << bst.txt[1] << bst.txt[2] << '"';
  return os;
}

std::ostream &operator<<(std::ostream &os, const port &p) {
  if (p.type == 0) {
    os << p.sector << ": " << (int)p.type;
  } else {
    os << p.sector << ": " << (int)p.type << " " << text_from_type(p.type)
       << " " << p.amount[0] << "," << p.amount[1] << "," << p.amount[2];
  }
  return os;
}

sector_warps::sector_warps() {
  sector = 0;
  for (int x = 0; x < MAX_WARPS; ++x) warps[x] = 0;
}

void sector_warps::add(sector_type new_sector) {
  for (int x = 0; x < MAX_WARPS; ++x) {
    if (warps[x] == new_sector) return;
    if (warps[x] == 0) {
      warps[x] = new_sector;
      return;
    }
  }
  std::string message = str(boost::format("More then MAX %1% sectors for %2%") %
                            MAX_WARPS % (int)sector);
  throw std::out_of_range(message);
}

std::ostream &operator<<(std::ostream &os, const sector_warps &warps) {
  os << "Sector: " << warps.sector << " ";
  for (int x = 0; x < MAX_WARPS; ++x) {
    if (warps.warps[x] != 0) {
      if (x != 0) os << ",";
      os << warps.warps[x];
    }
  }
  return os;
}
#define GTEST_COUT std::cerr << "[          ] [ INFO ]"
// #define GTEST_DEBUG

struct port parse_portcim(const std::string line) {
  struct port p;
  p.sector = std::stoi(line);
  //  20 - 1708  97% -  710  56%    287  15%
  static std::regex portrx(
      "[ ]*([0-9]+) (.)[ ]+([0-9]+)[ ]+([0-9]+%) (.)[ "
      "]+([0-9]+)[ ]+([0-9]+%) (.)[ ]+([0-9]+)[ ]+([0-9]+%)[ ]*",
      std::regex_constants::ECMAScript);

  // does it not understand {3} ??
  // NO, it does not, from regex101.com:
  // A repeated capturing group will only capture the last iteration. Put a
  // capturing group around the repeated group to capture all iterations or use
  // a non-capturing group instead if you're not interested in the data
  //
  //  static std::regex portrx("[ ]*([0-9]+)( (.)[ ]+([0-9]+)[ ]+([0-9]+%)){3}[
  //  ]*",
  //                           std::regex_constants::ECMAScript);

  // sector + amount pct + amount pct + amount pct
  // 1      2 3      4   5 6      7   8 9      10

#ifdef GTEST_DEBUG
  GTEST_COUT << "Sector: " << p.sector << std::endl;
  GTEST_COUT << "Line: [" << line << "]" << std::endl;
#endif

  buysell port_buysell;

  std::smatch matches;
  if (std::regex_match(line, matches, portrx)) {
#ifdef GTEST_DEBUG
    for (size_t x = 1; x < matches.size(); ++x) {
      GTEST_COUT << x << " : " << matches[x] << std::endl;
    }
#endif

    if (matches.size() != 11) {
#ifdef GTEST_DEBUG
      GTEST_COUT << "Now you have 101 problems." << std::endl;
#endif
      p.sector = 0;
      p.type = 0;
      return p;
    }
    // GTEST_COUT << "matches: " << matches.size() << std::endl;
    p.sector = stoi(matches[1]);
    // GTEST_COUT << "sector: " << matches[1] << std::endl;
    // for (int x = 1; x < 11; ++x) {
    //   GTEST_COUT << x << " : " << matches[x] << std::endl;
    // }
    for (int x = 0; x < 3; ++x) {
      int pos = x * 3;
      port_buysell.foe[x] = matches[pos + 2] == "-";
      p.amount[x] = stoi(matches[pos + 3]);
      p.percent[x] = stoi(matches[pos + 4]);
    }
    p.type = type_from_buysell(port_buysell);
#ifdef GTEST_DEBUG
    GTEST_COUT << "port is type " << (int)p.type << std::endl;
#endif
    return p;
  } else {
#ifdef GTEST_DEBUG
    GTEST_COUT << "regex_match failed." << std::endl;
#endif
    p.type = 0;
    p.sector = 0;
    return p;
  }
}