//+----------------------------------------------------------------------------+
//| Description:  Magic Set Editor - Program to make Magic (tm) cards          |
//| Copyright:    (C) Twan van Laarhoven and the other MSE developers          |
//| License:      GNU General Public License 2 or later (see file COPYING)     |
//+----------------------------------------------------------------------------+

// ----------------------------------------------------------------------------- : Includes

#include <util/prec.hpp>
#include <gui/set/style_panel.hpp>
#include <gui/set/window.hpp>
#include <gui/control/package_list.hpp>
#include <gui/control/card_viewer.hpp>
#include <gui/control/native_look_editor.hpp>
#include <gui/util.hpp>
#include <util/window_id.hpp>
#include <data/set.hpp>
#include <data/game.hpp>
#include <data/card.hpp>
#include <data/stylesheet.hpp>
#include <data/action/set.hpp>
#include <data/action/value.hpp>

// ----------------------------------------------------------------------------- : StylePanel : initialization

StylePanel::StylePanel(Window* parent, int id)
  : SetWindowPanel(parent, id)
{
  // delayed initialization by initControls()
}

void StylePanel::initControls() {
  // init controls
  preview       = new CardViewer   (this, wxID_ANY);
  list          = new PackageList  (this, wxID_ANY);
  use_for_all   = new wxButton     (this, ID_STYLE_USE_FOR_ALL, _BUTTON_("use for all cards"));
  use_custom_options = new wxCheckBox(this, ID_STYLE_USE_CUSTOM, _BUTTON_("use custom styling options"));
  editor        = new StylingEditor(this, ID_EDITOR, wxNO_BORDER);

  stylesheet_filter = new FilterCtrl(this, ID_STYLESHEET_FILTER, _LABEL_("search stylesheet list"), _HELP_("search stylesheet list control"));
  stylesheet_filter->setFilter(stylesheet_filter_value);

  // init sizer
  wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
    s->Add(preview, 0, wxRIGHT,  2);
    wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
      s2->Add(list,        0, wxEXPAND | wxBOTTOM,                4);
      wxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
        s3->Add(stylesheet_filter, 0, wxBOTTOM | wxLEFT, 4);
        s3->AddStretchSpacer();
        s3->Add(use_for_all, 0, wxBOTTOM | wxRIGHT, 4);
      s2->Add(s3, wxSizerFlags().Expand().Border(wxALL, 6));
      wxSizer* s4 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("styling options"));
        s4->Add(use_custom_options, 0, wxEXPAND | wxALL, 4);
        s4->Add(editor,             2, wxEXPAND, 0);
      s2->Add(s4, 1, wxEXPAND | wxALL, 2);
    s->Add(s2,      1, wxEXPAND, 8);
  s->SetSizeHints(this);
  SetSizer(s);
}

void StylePanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
  if (!isInitialized()) {
    wxBusyCursor busy;
    initControls();
    CardP cur_card = card;
    onChangeSet();
    selectCard(cur_card);
  }
}

void StylePanel::updateListSize() {
  if (!isInitialized() || list_size_already_initialized) return;
  // how many columns fit?
  size_t fit_columns = (size_t)((GetSize().y - 400) / 152);
  // we only need enough columns to show all items
  int x_room = GetSize().x - editor->GetBestSize().x - 6;
  size_t need_columns = (size_t)ceil(list->requiredWidth() / (double)x_room);
  size_t column_count = max((size_t)1, min(fit_columns, need_columns));
  // change count
  if (column_count != list->column_count) {
    list->column_count = column_count;
    static_cast<SetWindow*>(GetParent())->fixMinWindowSize();
  }

  list_size_already_initialized = true;
}

bool StylePanel::Layout() {
  updateListSize();
  return SetWindowPanel::Layout();
}

// ----------------------------------------------------------------------------- : StylePanel

void StylePanel::onChangeSet() {
  if (!isInitialized()) return;
  list->showData<StyleSheet>(set->game->name() + _("-*"));
  list->select(set->stylesheet->name(), false);
  editor->setSet(set);
  preview->setSet(set);
  card = CardP();
  use_for_all->Enable(false);
}

void StylePanel::onAction(const Action& action, bool undone) {
  if (!isInitialized()) return;
  TYPE_CASE_(action, ChangeSetStyleAction) {
    list->select(set->stylesheetFor(card).name(), false);
    editor->showCard(card);
  }
  TYPE_CASE(action, ChangeCardStyleAction) {
    if (action.card == card) {
      list->select(set->stylesheetFor(card).name(), false);
      editor->showCard(card);
    }
  }
  TYPE_CASE(action, ChangeCardHasStylingAction) {
    if (action.card == card) {
      editor->showCard(card);
    }
  }
  TYPE_CASE(action, ValueAction) {
    // is it a styling action?
    if (!action.card) {
      const StyleSheet& s = set->stylesheetFor(card);
      FOR_EACH_CONST(f, s.styling_fields) {
        if (action.valueP->fieldP == f) {
          // refresh the viewer
          preview->redraw();
          return;
        }
      }
    }
  }
  use_for_all->Enable(card && card->stylesheet);
  use_custom_options->Enable((bool)card);
  use_custom_options->SetValue(card ? card->has_styling : false);
}

void StylePanel::onStylesheetFilterUpdate(wxCommandEvent&) {
  if (list->hasSelection()) {
    StyleSheetP existingStylesheetSelection = list->getSelection<StyleSheet>(false);
    list->setFilter(stylesheet_filter->getFilter<PackageData>());
    list->select(existingStylesheetSelection->name());
  }
  else {
    list->setFilter(stylesheet_filter->getFilter<PackageData>());
  }
}

// ----------------------------------------------------------------------------- : Selection

void StylePanel::selectCard(const CardP& card) {
  this->card = card;
  if (!isInitialized()) return;
  preview->setCard(card);
  editor->showStylesheet(set->stylesheetForP(card));
  editor->showCard(card);
  list->select(set->stylesheetFor(card).name(), false);
  use_for_all->Enable(card && card->stylesheet);
  use_custom_options->Enable((bool)card);
  use_custom_options->SetValue(card ? card->has_styling : false);
}

// ----------------------------------------------------------------------------- : Clipboard

// determine what control to use for clipboard actions
#define CUT_COPY_PASTE(op,return) \
  if (!isInitialized()) return false; \
  int id = focused_control(this); \
  if (id == ID_EDITOR) { return editor->op(); } \
  else                 { return false; }

bool StylePanel::canCopy()  const { CUT_COPY_PASTE(canCopy,  return) }
bool StylePanel::canCut()   const { CUT_COPY_PASTE(canCut,   return) }
bool StylePanel::canPaste() const { CUT_COPY_PASTE(canPaste, return) }
void StylePanel::doCopy()         { CUT_COPY_PASTE(doCopy,   return (void)) }
void StylePanel::doCut()          { CUT_COPY_PASTE(doCut,    return (void)) }
void StylePanel::doPaste()        { CUT_COPY_PASTE(doPaste,  return (void)) }
bool StylePanel::canSelectAll() const { CUT_COPY_PASTE(canSelectAll, return) }
void StylePanel::doSelectAll()        { CUT_COPY_PASTE(doSelectAll,  return (void)) }

// ----------------------------------------------------------------------------- : Events

void StylePanel::onStyleSelect(wxCommandEvent&) {
  if (list->hasSelection() && card) {
    StyleSheetP stylesheet = list->getSelection<StyleSheet>();
    if (stylesheet->game != set->game) {
      throw PackageError(_("Stylesheet made for the wrong game"));
    }
    if (stylesheet == set->stylesheet) {
      // select no special style when selecting the same style as the set default
      stylesheet = StyleSheetP();
    }
    set->actions.addAction(make_unique<ChangeCardStyleAction>(card, stylesheet));
    Layout();
  }
}

void StylePanel::onUseForAll(wxCommandEvent&) {
  set->actions.addAction(make_unique<ChangeSetStyleAction>(*set, card));
  Layout();
}

void StylePanel::onUseCustom(wxCommandEvent&) {
  set->actions.addAction(make_unique<ChangeCardHasStylingAction>(*set, card));
}

BEGIN_EVENT_TABLE(StylePanel, wxPanel)
  EVT_GALLERY_SELECT(wxID_ANY,             StylePanel::onStyleSelect)
  EVT_COMMAND_RANGE(ID_STYLESHEET_FILTER, ID_STYLESHEET_FILTER, wxEVT_COMMAND_TEXT_UPDATED, StylePanel::onStylesheetFilterUpdate)
  EVT_BUTTON        (ID_STYLE_USE_FOR_ALL, StylePanel::onUseForAll)
  EVT_CHECKBOX      (ID_STYLE_USE_CUSTOM,  StylePanel::onUseCustom)
END_EVENT_TABLE()
