#include "GenerateCodeDlg.h"

#include "GenerateCodeSketch.h"

#include <GG/Button.h>
#include <GG/DrawUtil.h>
#include <GG/DropDownList.h>
#include <GG/Edit.h>
#include <GG/GUI.h>
#include <GG/Layout.h>
#include <GG/Button.h>
#include <GG/TextControl.h>
#include <GG/dialogs/ThreeButtonDlg.h>

#include <boost/filesystem/operations.hpp>
#include <boost/assign/list_of.hpp>

namespace {
    bool ContainsInvalidCharacters(const std::string& str)
    {
        return str.find_first_not_of("_-.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") != std::string::npos;
    }

    void PopulateList(GG::DropDownList* list, const std::vector<std::string>& strings, boost::shared_ptr<GG::Font> font)
    {
        list->SetStyle(GG::LB_NOSORT);
        list->SetInteriorColor(GG::CLR_GRAY);
        for (unsigned int i = 0; i < strings.size(); ++i) {
            GG::ListBox::Row* row = new GG::ListBox::Row();
            row->push_back(strings[i], font);
            list->Insert(row);
        }
        list->Select(0);
    }

    const std::vector<std::string> HEADER_EXTENSIONS =
        boost::assign::list_of<std::string>(".h")(".H")(".hpp")(".HPP")(".Hxx")(".HXX");
    const std::vector<std::string> IMPL_EXTENSIONS =
        boost::assign::list_of<std::string>(".cpp")(".Cpp")(".CPP")(".cc")(".C")(".cxx")(".Cxx")(".CXX");
    const std::vector<std::string> SKETCH_EXTENSIONS =
        boost::assign::list_of<std::string>(".sketch")(".SKETCH")(".ui_sketch")(".ui-sketch")(".ui")(".UI");
}

GenerateCodeDlg::GenerateCodeDlg(const std::string& open_filename) :
    GG::Wnd(0, 0, 1, 1, GG::CLICKABLE | GG::DRAGABLE | GG::MODAL),
    m_ui(new GenerateCodeSketch(this)),
    m_ended_with_ok(false)
{
    boost::shared_ptr<GG::Font> font = GG::GUI::GetGUI()->GetFont("Vera.ttf", 12);
    PopulateList(m_ui->m_header_ext_list, HEADER_EXTENSIONS, font);
    PopulateList(m_ui->m_impl_ext_list, IMPL_EXTENSIONS, font);
    PopulateList(m_ui->m_sketch_ext_list, SKETCH_EXTENSIONS, font);

    GG::Connect(m_ui->m_base_filename->EditedSignal, &GenerateCodeDlg::BaseFilenameChanged, this);
    GG::Connect(m_ui->m_header_ext_list->SelChangedSignal, &GenerateCodeDlg::HeaderExtSelectionChanged, this);
    GG::Connect(m_ui->m_custom_header_ext_edit->EditedSignal, &GenerateCodeDlg::CustonHeaderExtChanged, this);
    GG::Connect(m_ui->m_impl_ext_list->SelChangedSignal, &GenerateCodeDlg::ImplExtSelectionChanged, this);
    GG::Connect(m_ui->m_custom_impl_ext_edit->EditedSignal, &GenerateCodeDlg::CustonImplExtChanged, this);
    GG::Connect(m_ui->m_sketch_ext_list->SelChangedSignal, &GenerateCodeDlg::SketchExtSelectionChanged, this);
    GG::Connect(m_ui->m_custom_sketch_ext_edit->EditedSignal, &GenerateCodeDlg::CustonSketchExtChanged, this);
    GG::Connect(m_ui->m_export_button->ClickedSignal, &GenerateCodeDlg::OkClicked, this);
    GG::Connect(m_ui->m_cancel_button->ClickedSignal, &GenerateCodeDlg::CancelClicked, this);

    MoveTo(GG::Pt((GG::GUI::GetGUI()->AppWidth() - Width()) / 2, (GG::GUI::GetGUI()->AppHeight() - Height()) / 2));

    std::string open_filename_base = open_filename.substr(0, open_filename.find_last_of("."));
    m_ui->m_base_filename->SetText(open_filename_base);

    m_ui->m_export_button->Disable(!SettingsValid());
}

GenerateCodeDlg::~GenerateCodeDlg()
{
    delete m_ui;
}

bool GenerateCodeDlg::EndedWithOk() const
{
    return m_ended_with_ok;
}

std::string GenerateCodeDlg::BaseFilename() const
{
    return m_ui->m_base_filename->WindowText();
}

GenerateCodeDlg::ExportFiles GenerateCodeDlg::ExportedFiles() const
{
    return ExportFiles(m_ui->m_file_types_button_group->CheckedButton());
}

std::string GenerateCodeDlg::HeaderExt() const
{
    return m_ui->m_custom_header_ext_edit->WindowText().empty() ?
        m_ui->m_header_ext_list->CurrentItem()->at(0)->WindowText() :
        ('.' + m_ui->m_custom_header_ext_edit->WindowText());
}

std::string GenerateCodeDlg::ImplExt() const
{
    return m_ui->m_custom_impl_ext_edit->WindowText().empty() ?
        m_ui->m_impl_ext_list->CurrentItem()->at(0)->WindowText() :
        ('.' + m_ui->m_custom_impl_ext_edit->WindowText());
}

std::string GenerateCodeDlg::SketchExt() const
{
    return m_ui->m_custom_sketch_ext_edit->WindowText().empty() ?
        m_ui->m_sketch_ext_list->CurrentItem()->at(0)->WindowText() :
        ('.' + m_ui->m_custom_sketch_ext_edit->WindowText());
}

void GenerateCodeDlg::Render()
{
    GG::Pt ul = UpperLeft(), lr = LowerRight();
    GG::BeveledRectangle(ul.x, ul.y, lr.x, lr.y, GG::CLR_GRAY, GG::CLR_GRAY, true, 2);
}

bool GenerateCodeDlg::SettingsValid()
{
    return !m_ui->m_base_filename->WindowText().empty() &&
        !ContainsInvalidCharacters(m_ui->m_custom_header_ext_edit->WindowText()) &&
        !ContainsInvalidCharacters(m_ui->m_custom_impl_ext_edit->WindowText()) &&
        !ContainsInvalidCharacters(m_ui->m_custom_sketch_ext_edit->WindowText());
}

void GenerateCodeDlg::BaseFilenameChanged(const std::string&)
{
    m_ui->m_export_button->Disable(!SettingsValid());
}

void GenerateCodeDlg::HeaderExtSelectionChanged(int)
{
}

void GenerateCodeDlg::CustonHeaderExtChanged(const std::string&)
{
    m_ui->m_export_button->Disable(!SettingsValid());
}

void GenerateCodeDlg::ImplExtSelectionChanged(int)
{
}

void GenerateCodeDlg::CustonImplExtChanged(const std::string&)
{
    m_ui->m_export_button->Disable(!SettingsValid());
}

void GenerateCodeDlg::SketchExtSelectionChanged(int)
{
}

void GenerateCodeDlg::CustonSketchExtChanged(const std::string&)
{
    m_ui->m_export_button->Disable(!SettingsValid());
}

void GenerateCodeDlg::OkClicked()
{
    std::string header = BaseFilename() + HeaderExt();
    std::string impl = BaseFilename() + ImplExt();
    std::string sketch = BaseFilename() + SketchExt();
    ExportFiles exported_files = ExportedFiles();
    std::string conflicts;
    namespace fs = boost::filesystem;
    if (fs::exists(fs::path(header)))
        conflicts += header;
    if (exported_files != HEADER_ONLY && fs::exists(fs::path(impl))) {
        if (!conflicts.empty())
            conflicts += ", ";
        conflicts += impl;
    }
    if (exported_files == HEADER_IMPL_AND_SKETCH && fs::exists(fs::path(sketch))) {
        if (!conflicts.empty())
            conflicts += ", ";
        conflicts += sketch;
    }
    if (!conflicts.empty()) {
        boost::shared_ptr<GG::Font> font = GG::GUI::GetGUI()->GetFont("Vera.ttf", 12);
        GG::ThreeButtonDlg dlg(300, 150, "Ok to owverwrite the follwing file(s)?\n" + conflicts, font, GG::CLR_GRAY, GG::CLR_GRAY, GG::CLR_GRAY, GG::CLR_BLACK, 2, "Overwrite", "Cancel");
        dlg.Run();
        if (dlg.Result() != 0)
            return;
    }
    m_ended_with_ok = true;
    m_done = true;
}

void GenerateCodeDlg::CancelClicked()
{
    m_ended_with_ok = false;
    m_done = true;
}
