#include "scripts.h"

#include <boost/format.hpp>

#include "logging.h"

ScriptTerror::ScriptTerror(Director &d) : Dispatch(d) {
  BUGZ_LOG(warning) << "ScriptTerror()";
  init();
}

ScriptTerror::~ScriptTerror() { BUGZ_LOG(warning) << "~ScriptTerror()"; }

void ScriptTerror::init(void) {
  BUGZ_LOG(fatal) << "ScriptTerror::init()";

  move = std::make_shared<MoveDispatch>(director);
  md = static_cast<MoveDispatch *>(&(*move));
  // setup notify functions for results/completion.
  md->setNotify([this]() { this->move_notify(); });

  input = std::make_shared<InputDispatch>(director);
  id = static_cast<InputDispatch *>(&(*input));
  id->prompt = "Number of loops: ";
  id->max_length = 4;
  id->numeric = true;
  id->setNotify([this]() { this->input_notify(); });

  trader = std::make_shared<TraderDispatch>(director);
  td = static_cast<TraderDispatch *>(&(*trader));
  td->setNotify([this]() { this->trade_notify(); });
  BUGZ_LOG(fatal) << "ScriptTerror::init() completed.";
}

void ScriptTerror::activate(void) {
  BUGZ_LOG(warning) << "ScriptTerror::activate()";
  // Need: InputDispatch, MoveDispatch, ScriptTrader

  // Save the trade_end_empty setting, and set to Y
  if (director.galaxy.config["trade_end_empty"]) {
    old_trade_end_empty =
        director.galaxy.config["trade_end_empty"].as<std::string>();
  } else {
    old_trade_end_empty = "Y";
  }
  director.galaxy.config["trade_end_empty"] = "Y";

  // Step 0:  Get ship information / # of holds
  max_loops = loops = -1;
  to_server("I");

  // Step 1:  Get number of loops of terror
  // director.chain = input;
  // input->activate();

  // Step 2:  Look for closest trades, try ScriptTrade until none < some
  // level. Step 3:  Move on, unless out of loops (or low on turns)

  // deactivate();
}

void ScriptTerror::deactivate(void) {
  BUGZ_LOG(warning) << "ScriptTerror::deactivate()";
  // restore the original value.
  director.galaxy.config["trade_end_empty"] = old_trade_end_empty;
  notify();
}

void ScriptTerror::input_notify(void) {
  if (id->input.empty()) {
    deactivate();
    return;
  }
  if (id->aborted) {
    deactivate();
    return;
  }

  max_loops = sstoi(id->input, -1);
  if (max_loops == -1) {
    deactivate();
    return;
  }
  id->input.clear();
  BUGZ_LOG(warning) << "Loops of terror: " << max_loops;
  loops = max_loops;

  // find nearest
  int stop_percent;
  if (director.galaxy.config["stop_percent"]) {
    stop_percent = director.galaxy.config["stop_percent"].as<int>();
  } else {
    stop_percent = 25;
    director.galaxy.config["stop_percent"] = stop_percent;
  }

  ppt = director.galaxy.find_closest_trade(director.current_sector, 3,
                                           stop_percent);
  if (ppt.type == 0) {
    to_client("No trades found!  You've burnt the galaxy!\n\r");
    deactivate();
    return;
  }
  // ok, step 2:  move!
  // md->setNotify([this]() { this->proxy_deactivate(); });

  if (director.current_sector != ppt.s1) {
    BUGZ_LOG(fatal) << "Moving to: " << ppt.s1;
    md->move_to = ppt.s1;
    director.chain = move;
    director.chain->activate();
    return;
  } else {
    // We're already there!
    to_client("Ok!  Get trading!\n\r");

    td->port[0] = ppt.s1;
    td->port[1] = ppt.s2;
    td->trades = ppt.trades;
    td->type = ppt.type;
    director.chain = trader;
    director.chain->activate();
    return;
  }
}

void ScriptTerror::move_notify(void) {
  BUGZ_LOG(fatal) << "move_notify()";
  if (md->aborted) {
    to_client("Move cancel.\n\r");
    deactivate();
    return;
  }

  // Check for success, and start trading!
  if (md->success) {
    to_client("We're here, get trading!\n\r");

    td->port[0] = ppt.s1;
    td->port[1] = ppt.s2;
    td->trades = ppt.trades;
    td->type = ppt.type;
    director.chain = trader;
    director.chain->activate();
    return;
  } else {
    to_client("Move FAILED.\n\r");
    deactivate();
  }
}

void ScriptTerror::server_prompt(const std::string &prompt) {
  if ((loops == -1) && (max_loops == -1)) {
    if (at_command_prompt(prompt)) {
      // Step 1:  Get number of loops of terror
      director.chain = input;
      input->activate();
      return;
    }
  }
}

void ScriptTerror::trade_notify(void) {
  // Done trading -- maybe! :P
  if (td->aborted) {
    to_client("Trade cancel.\n\r");
    deactivate();
    return;
  }

  if (td->success) {
    // success!

    // find nearest
    int stop_percent;
    if (director.galaxy.config["stop_percent"]) {
      stop_percent = director.galaxy.config["stop_percent"].as<int>();
    } else {
      stop_percent = 25;
      director.galaxy.config["stop_percent"] = stop_percent;
    }

    ppt = director.galaxy.find_closest_trade(director.current_sector, 3,
                                             stop_percent);
    if (ppt.type == 0) {
      to_client("No trades found!  You've burnt the galaxy!\n\r");
      deactivate();
      return;
    }
    if ((director.current_sector == ppt.s1) ||
        (director.current_sector == ppt.s2)) {
      // We're still here...
      BUGZ_LOG(fatal) << "Trade it again, Sam.";
      to_client("Keep trading.\n\r");
      td->port[0] = ppt.s1;
      td->port[1] = ppt.s2;
      td->trades = ppt.trades;
      td->type = ppt.type;
      director.chain = trader;
      director.chain->activate();
      return;
    }
    // Ok, this isn't a local trade.
    if (loops == 0) {
      to_client("We're done terrorizing, for now...\n\r");
      deactivate();
      return;
    }
    --loops;
    // Move to our next target
    BUGZ_LOG(fatal) << "Moving to: " << ppt.s1;
    md->move_to = ppt.s1;
    director.chain = move;
    director.chain->activate();
    return;
  }
  to_client("Ok, trade is done.\n\r");
  deactivate();
}