#include "transfersfilterscreen.h"

#include "transfersscreen.h"

#include "../ui.h"
#include "../menuselectoptionelement.h"
#include "../menuselectoptiontextfield.h"
#include "../menuselectoptioncheckbox.h"
#include "../siteselection.h"

#include "../../commandowner.h"
#include "../../globalcontext.h"
#include "../../site.h"
#include "../../engine.h"
#include "../../race.h"
#include "../../transferjob.h"
#include "../../util.h"

TransfersFilterScreen::TransfersFilterScreen(Ui* ui) : UIWindow(ui, "TransfersFilterScreen"), mso(*vv) {
  keybinds.addBind(10, KEYACTION_ENTER, "Modify");
  keybinds.addBind('d', KEYACTION_DONE, "Done");
  keybinds.addBind('f', KEYACTION_FILTER, "Done");
  keybinds.addBind('c', KEYACTION_BACK_CANCEL, "Cancel");
  keybinds.addBind('r', KEYACTION_RESET, "Reset");
  keybinds.addBind(KEY_UP, KEYACTION_UP, "Navigate up");
  keybinds.addBind(KEY_DOWN, KEYACTION_DOWN, "Navigate down");
}

TransfersFilterScreen::~TransfersFilterScreen() {

}

void TransfersFilterScreen::initialize(unsigned int row, unsigned int col, const TransferFilteringParameters & tfp) {
  mso.reset();
  selectedspreadjobs = tfp.spreadjobsfilter;
  selectedtransferjobs = tfp.transferjobsfilter;
  int y = 1;
  mso.addCheckBox(y++, 1, "jobfilter", "Enable job filtering:", tfp.usejobfilter);
  mso.addStringField(y++, 1, "spreadjobs", "Spread jobs:", getSpreadJobsText(), false, 60, 512);
  mso.addStringField(y++, 1, "transferjobs", "Transfer jobs:", getTransferJobsText(), false, 60, 512);
  y++;
  mso.addCheckBox(y++, 1, "sitesfilter", "Enable sites filtering:", tfp.usesitefilter);
  mso.addStringField(y++, 1, "source", "Source:", util::join(tfp.sourcesitefilters, ","), false, 60, 2048);
  mso.addStringField(y++, 1, "destination", "Destination:", util::join(tfp.targetsitefilters, ","), false, 60, 2048);
  mso.addStringField(y++, 1, "anydirection", "Any direction:", util::join(tfp.anydirectionsitefilters, ","), false, 60, 2048);
  y++;
  mso.addCheckBox(y++, 1, "filenamefilter", "Enable file name filtering:", tfp.usefilenamefilter);
  mso.addStringField(y++, 1, "filename", "File name:", tfp.filenamefilter, false, 60, 512);
  y++;
  mso.addCheckBox(y++, 1, "statusfilter", "Enable transfer status filtering:", tfp.usestatusfilter);
  mso.addCheckBox(y++, 1, "statusinprogress", "In progress:", tfp.showstatusinprogress);
  mso.addCheckBox(y++, 1, "statusdone", "Done:", tfp.showstatusdone);
  mso.addCheckBox(y++, 1, "statusfail", "Failed:", tfp.showstatusfail);
  mso.addCheckBox(y++, 1, "statusdupe", "Dupe:", tfp.showstatusdupe);
  y++;
  mso.addCheckBox(y++, 1, "speedbelowfilter", "Enable speed below filtering:", tfp.usespeedbelowfilter);
  mso.addStringField(y++, 1, "speedbelow", "Speed below:", std::to_string(tfp.speedbelowfilter), false, 7, 7);
  mso.addCheckBox(y++, 1, "speedabovefilter", "Enable speed above filtering:", tfp.usespeedabovefilter);
  mso.addStringField(y++, 1, "speedabove", "Speed above:", std::to_string(tfp.speedabovefilter), false, 7, 7);

  mso.enterFocusFrom(0);
  init(row, col);
}

void TransfersFilterScreen::redraw() {
  vv->clear();
  bool highlight;
  for (unsigned int i = 0; i < mso.size(); i++) {
    std::shared_ptr<MenuSelectOptionElement> msoe = mso.getElement(i);
    highlight = false;
    if (mso.getSelectionPointer() == i) {
      highlight = true;
      if (active && msoe->cursorPosition() >= 0) {
        ui->showCursor();
        vv->moveCursor(msoe->getRow(), msoe->getCol() + msoe->getLabelText().length() + 1 + msoe->cursorPosition());
      }
      else {
        ui->hideCursor();
      }
    }
    vv->putStr(msoe->getRow(), msoe->getCol(), msoe->getLabelText(), highlight);
    vv->putStr(msoe->getRow(), msoe->getCol() + msoe->getLabelText().length() + 1, msoe->getContentText());
    if (msoe->getIdentifier() == "speedbelow" || msoe->getIdentifier() == "speedabove") {
      vv->putStr(msoe->getRow(), msoe->getCol() + msoe->getLabelText().length() + 1 +
       std::static_pointer_cast<MenuSelectOptionTextField>(msoe)->getData().length() + 1, "MB/s");
    }
  }
}

void TransfersFilterScreen::command(const std::string & command, const std::string & arg) {
  if (command == "returnselectitems") {
    std::list<std::string> items = util::trim(util::split(arg, ","));
    std::string identifier = activeelement->getIdentifier();
    if (identifier == "spreadjobs") {
      selectedspreadjobs.clear();
      for (std::list<std::string>::const_iterator it = items.begin(); it != items.end(); it++) {
        selectedspreadjobs.push_back(global->getEngine()->getRace(std::stoi(*it))->getName());
      }
      std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("spreadjobs"))->setText(getSpreadJobsText());
    }
    else if (identifier == "transferjobs") {
      selectedtransferjobs.clear();
      for (std::list<std::string>::const_iterator it = items.begin(); it != items.end(); it++) {
        selectedtransferjobs.push_back(global->getEngine()->getTransferJob(std::stoi(*it))->getName());
      }
      std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("transferjobs"))->setText(getTransferJobsText());
    }
    else {
      std::static_pointer_cast<MenuSelectOptionTextField>(activeelement)->setText(arg);
    }
    if (!items.empty()) {
      if (identifier == "spreadjobs" || identifier == "transferjobs") {
        std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("jobfilter"))->setValue(true);
      }
      else if (identifier == "source" || identifier == "destination" || identifier == "anydirection") {
        std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("sitesfilter"))->setValue(true);
      }
    }
    ui->redraw();
  }
}

bool TransfersFilterScreen::onDeactivated(const std::shared_ptr<MenuSelectOptionElement>& msoe) {
  if (activeelement->getIdentifier() == "filename" && !std::static_pointer_cast<MenuSelectOptionTextField>(activeelement)->getData().empty()) {
    std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("filenamefilter"))->setValue(true);
  }
  return false;
}

bool TransfersFilterScreen::keyPressed(unsigned int ch) {
  int action = keybinds.getKeyAction(ch);
  switch (action) {
    case KEYACTION_UP: {
      bool moved = mso.goUp();
      ui->update();
      return moved;
    }
    case KEYACTION_DOWN: {
      bool moved = mso.goDown();
      ui->update();
      return moved;
    }
    case KEYACTION_DONE:
    case KEYACTION_FILTER:
    {
      TransferFilteringParameters tfp;
      tfp.usejobfilter = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("jobfilter"))->getData();
      tfp.spreadjobsfilter = selectedspreadjobs;
      tfp.transferjobsfilter = selectedtransferjobs;
      tfp.usesitefilter = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("sitesfilter"))->getData();
      tfp.sourcesitefilters = util::trim(util::split(std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("source"))->getData(), ","));
      tfp.targetsitefilters = util::trim(util::split(std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("destination"))->getData(), ","));
      tfp.anydirectionsitefilters = util::trim(util::split(std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("anydirection"))->getData(), ","));
      tfp.usefilenamefilter = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("filenamefilter"))->getData();
      tfp.filenamefilter = std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("filename"))->getData();
      tfp.usestatusfilter = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("statusfilter"))->getData();
      tfp.showstatusinprogress = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("statusinprogress"))->getData();
      tfp.showstatusdone = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("statusdone"))->getData();
      tfp.showstatusfail= std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("statusfail"))->getData();
      tfp.showstatusdupe = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("statusdupe"))->getData();
      tfp.usespeedbelowfilter = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("speedbelowfilter"))->getData();
      try {
        tfp.speedbelowfilter = std::stol(std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("speedbelow"))->getData());
      }
      catch (std::exception&) {
        tfp.speedbelowfilter = 0;
      }
      tfp.usespeedabovefilter = std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("speedabovefilter"))->getData();
      try {
        tfp.speedabovefilter = std::stol(std::static_pointer_cast<MenuSelectOptionTextField>(mso.getElement("speedabove"))->getData());
      }
      catch (std::exception&) {
        tfp.speedabovefilter = 0;
      }
      ui->returnTransferFilters(tfp);
      return true;
    }
    case KEYACTION_ENTER:
    {
      std::shared_ptr<MenuSelectOptionElement> msoe = mso.getElement(mso.getSelectionPointer());
      if (msoe->getIdentifier() == "spreadjobs") {
        activeelement = msoe;
        ui->goSelectSpreadJobs();
        return true;
      }
      if (msoe->getIdentifier() == "transferjobs") {
        activeelement = msoe;
        ui->goSelectTransferJobs();
        return true;
      }
      if (msoe->getIdentifier() == "source" || msoe->getIdentifier() == "destination" || msoe->getIdentifier() == "anydirection") {
        std::string preselectstr = std::static_pointer_cast<MenuSelectOptionTextField>(msoe)->getData();
        std::list<std::shared_ptr<Site>> preselected;
        fillPreselectionList(preselectstr, &preselected);
        activeelement = msoe;
        std::string headerword = msoe->getIdentifier() + " ";
        if (headerword == "anydirection") {
          headerword = "";
        }
        ui->goSelectSites("Show these " + headerword + "sites in transfers", preselected, std::list<std::shared_ptr<Site>>());
        return true;
      }
      bool activation = msoe->activate();
      if (!activation) {
        std::string identifier = msoe->getIdentifier();
        if ((identifier == "statusinprogress" || identifier == "statusdone" || identifier == "statusdupe" || identifier == "statusfail") &&
            std::static_pointer_cast<MenuSelectOptionCheckBox>(msoe)->getData())
        {
          std::static_pointer_cast<MenuSelectOptionCheckBox>(mso.getElement("statusfilter"))->setValue(true);
        }
        ui->update();
        return true;
      }
      active = true;
      activeelement = msoe;
      ui->setLegend();
      ui->update();
      return true;
    }
    case KEYACTION_RESET:
      initialize(row, col, TransferFilteringParameters());
      ui->redraw();
      return true;
    case KEYACTION_BACK_CANCEL:
      ui->returnToLast();
      return true;
  }
  return false;
}

std::string TransfersFilterScreen::getInfoLabel() const {
  return "TRANSFERS FILTERING";
}

std::string TransfersFilterScreen::getSpreadJobsText() const {
  size_t size = selectedspreadjobs.size();
  std::string text;
  if (size == 1) {
    text = selectedspreadjobs.front();
  }
  else if (size > 1) {
    text = std::to_string((int)size) + " spread jobs selected...";
  }
  return text;
}

std::string TransfersFilterScreen::getTransferJobsText() const {
  size_t size = selectedtransferjobs.size();
  std::string text;
  if (size == 1) {
    text = selectedtransferjobs.front();
  }
  else if (size > 1) {
    text = std::to_string((int)size) + " transfer jobs selected...";
  }
  return text;
}
