/***************************************************************
 * Name:      wxkitMain.cpp
 * Purpose:   Drónútvolnal-tervező >> 1.beadandó
 * Author:    Hakkel Tamás
 * Created:   2015-10-28
 **************************************************************/

#include "wxkitMain.h"
#include <wx/msgdlg.h>
#include <sstream>
#include <vector>
#include <utility>
#include <algorithm>
#include <fstream>
#include <wx/dcclient.h>

//(*InternalHeaders(wxkitFrame)
#include <wx/artprov.h>
#include <wx/bitmap.h>
#include <wx/icon.h>
#include <wx/intl.h>
#include <wx/image.h>
#include <wx/string.h>
//*)

//helper functions
enum wxbuildinfoformat {
    short_f, long_f };

wxString wxbuildinfo(wxbuildinfoformat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == long_f )
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE
    }

    return wxbuild;
}

//(*IdInit(wxkitFrame)
const long wxkitFrame::ID_ABSOLUTE = wxNewId();
const long wxkitFrame::ID_RELATIVE = wxNewId();
const long wxkitFrame::ID_STATICTEXT1 = wxNewId();
const long wxkitFrame::ID_STATICTEXT2 = wxNewId();
const long wxkitFrame::ID_STATICTEXT3 = wxNewId();
const long wxkitFrame::ID_SPINCTRL1 = wxNewId();
const long wxkitFrame::ID_STATICTEXT4 = wxNewId();
const long wxkitFrame::ID_SPINCTRL2 = wxNewId();
const long wxkitFrame::ID_BUTTON1 = wxNewId();
const long wxkitFrame::ID_BUTTON2 = wxNewId();
const long wxkitFrame::ID_STATICTEXT5 = wxNewId();
const long wxkitFrame::ID_SLIDER1 = wxNewId();
const long wxkitFrame::ID_SLIDER2 = wxNewId();
const long wxkitFrame::ID_STATICTEXT6 = wxNewId();
const long wxkitFrame::ID_STATICTEXT7 = wxNewId();
const long wxkitFrame::ID_STATICTEXT8 = wxNewId();
const long wxkitFrame::ID_PANEL1 = wxNewId();
const long wxkitFrame::idMenuSave = wxNewId();
const long wxkitFrame::idMenuOpen = wxNewId();
const long wxkitFrame::idMenuQuit = wxNewId();
const long wxkitFrame::idMenuAbout = wxNewId();
//*)

BEGIN_EVENT_TABLE(wxkitFrame,wxFrame)
    EVT_LIST_ITEM_SELECTED(ID_ABSOLUTE, wxkitFrame::OnAbsoluteListSelection)
    EVT_LIST_ITEM_SELECTED(ID_RELATIVE, wxkitFrame::OnRelativeListSelection)
    EVT_LIST_COL_CLICK(ID_ABSOLUTE, wxkitFrame::OnAbsoluteListColClick)
    EVT_LIST_COL_CLICK(ID_RELATIVE, wxkitFrame::OnRelativeListColClick)
    EVT_COMMAND_SCROLL(ID_SLIDER1, wxkitFrame::OnrelXCmdScroll)
    EVT_COMMAND_SCROLL(ID_SLIDER2, wxkitFrame::OnrelYCmdScroll)
    EVT_MENU(idMenuSave, wxkitFrame::OnSave)
    EVT_MENU(idMenuOpen, wxkitFrame::OnOpen)
    EVT_PAINT(wxkitFrame::OnPaint)
END_EVENT_TABLE()

wxkitFrame::wxkitFrame(wxWindow* parent,wxWindowID WXUNUSED(id))
{
    //(*Initialize(wxkitFrame)
    wxMenuItem* MenuItem2;
    wxMenuItem* MenuItem1;
    wxMenu* Menu1;
    wxMenuBar* MenuBar1;
    wxMenu* Menu2;

    Create(parent, wxID_ANY, _("Drone path planner"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("wxID_ANY"));
    SetClientSize(wxSize(730,519));
    {
    	wxIcon FrameIcon;
    	FrameIcon.CopyFromBitmap(wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(_T("wxART_GO_UP")),wxART_OTHER));
    	SetIcon(FrameIcon);
    }
    Panel1 = new wxPanel(this, ID_PANEL1, wxPoint(488,144), wxSize(650,519), wxTAB_TRAVERSAL, _T("ID_PANEL1"));
    AbsoluteList = new wxListCtrl(Panel1, ID_ABSOLUTE, wxPoint(25,40), wxSize(150,300), wxLC_REPORT, wxDefaultValidator, _T("ID_ABSOLUTE"));
    AbsoluteList->AppendColumn("x");
    AbsoluteList->AppendColumn("y");
    AbsoluteList->SetColumnWidth(0, 75);
    AbsoluteList->SetColumnWidth(1, 75);
    RelativeList = new wxListCtrl(Panel1, ID_RELATIVE, wxPoint(200,40), wxSize(150,300), wxLC_REPORT, wxDefaultValidator, _T("ID_RELATIVE"));
    RelativeList->AppendColumn("x");
    RelativeList->AppendColumn("y");
    RelativeList->SetColumnWidth(0, 75);
    RelativeList->SetColumnWidth(1, 75);
    StaticText1 = new wxStaticText(Panel1, ID_STATICTEXT1, _("Absolute coord.:"), wxPoint(24,10), wxDefaultSize, 0, _T("ID_STATICTEXT1"));
    StaticText2 = new wxStaticText(Panel1, ID_STATICTEXT2, _("Relative coord.:"), wxPoint(200,10), wxDefaultSize, 0, _T("ID_STATICTEXT2"));
    StaticText3 = new wxStaticText(Panel1, ID_STATICTEXT3, _("x:"), wxPoint(30,370), wxDefaultSize, 0, _T("ID_STATICTEXT3"));
    xKoord = new wxSpinCtrl(Panel1, ID_SPINCTRL1, _T("0"), wxPoint(55,365), wxSize(120,27), 0, 0, 300, 0, _T("ID_SPINCTRL1"));
    xKoord->SetValue(_T("0"));
    StaticText4 = new wxStaticText(Panel1, ID_STATICTEXT4, _("y:"), wxPoint(30,415), wxDefaultSize, 0, _T("ID_STATICTEXT4"));
    yKoord = new wxSpinCtrl(Panel1, ID_SPINCTRL2, _T("0"), wxPoint(55,410), wxSize(120,27), 0, 0, 300, 0, _T("ID_SPINCTRL2"));
    yKoord->SetValue(_T("0"));
    Button1 = new wxButton(Panel1, ID_BUTTON1, _("Update"), wxPoint(224,355), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1"));
    Button2 = new wxButton(Panel1, ID_BUTTON2, _("Add"), wxPoint(224,400), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON2"));
    StaticText5 = new wxStaticText(Panel1, ID_STATICTEXT5, _("...to absolute coordinates."), wxPoint(192,445), wxDefaultSize, 0, _T("ID_STATICTEXT5"));
    relX = new wxSlider(Panel1, ID_SLIDER1, 0, 0, 300, wxPoint(393,15), wxSize(315,24), wxSL_HORIZONTAL, wxDefaultValidator, _T("ID_SLIDER1"));
    relY = new wxSlider(Panel1, ID_SLIDER2, 0, 0, 300, wxPoint(370,33), wxSize(24,315), wxSL_VERTICAL, wxDefaultValidator, _T("ID_SLIDER2"));
    StaticText6 = new wxStaticText(Panel1, ID_STATICTEXT6, _("Size of field: 300x300"), wxPoint(430,370), wxDefaultSize, 0, _T("ID_STATICTEXT6"));
    StaticText7 = new wxStaticText(Panel1, ID_STATICTEXT7, _("Reference point:"), wxPoint(430,415), wxDefaultSize, 0, _T("ID_STATICTEXT7"));
    relPoint = new wxStaticText(Panel1, ID_STATICTEXT8, _("(0, 0)"), wxPoint(560,416), wxDefaultSize, 0, _T("ID_STATICTEXT8"));
    MenuBar1 = new wxMenuBar();
    Menu1 = new wxMenu();
    MenuItem3 = new wxMenuItem(Menu1, idMenuSave, _("Save\tCtrl-s"), _("Saves absolute coordinates"), wxITEM_NORMAL);
    Menu1->Append(MenuItem3);
    MenuItem4 = new wxMenuItem(Menu1, idMenuOpen, _("Open\tCtrl-o"), _("Read absolute coordinates from text file"), wxITEM_NORMAL);
    Menu1->Append(MenuItem4);
    Menu1->AppendSeparator();
    MenuItem1 = new wxMenuItem(Menu1, idMenuQuit, _("Quit\tAlt-F4"), _("Quit the application"), wxITEM_NORMAL);
    Menu1->Append(MenuItem1);
    MenuBar1->Append(Menu1, _("&File"));
    Menu2 = new wxMenu();
    MenuItem2 = new wxMenuItem(Menu2, idMenuAbout, _("About\tF1"), _("Show info about this application"), wxITEM_NORMAL);
    Menu2->Append(MenuItem2);
    MenuBar1->Append(Menu2, _("Help"));
    SetMenuBar(MenuBar1);
    FDOpen = new wxFileDialog(this, _("Open"), wxEmptyString, wxEmptyString, _("Text files (*.txt)|*.txt"), wxFD_OPEN|wxFD_FILE_MUST_EXIST, wxDefaultPosition, wxDefaultSize, _T("wxFileDialog"));
    FDSave = new wxFileDialog(this, _("Save"), wxEmptyString, wxEmptyString, _("Text files (*.txt)|*.txt"), wxFD_SAVE|wxFD_OVERWRITE_PROMPT, wxDefaultPosition, wxDefaultSize, _T("wxFileDialog"));

    Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkitFrame::OnButton1Click3);
    Connect(ID_BUTTON2,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkitFrame::OnButton2Click);
    Connect(ID_SLIDER1,wxEVT_SCROLL_TOP|wxEVT_SCROLL_BOTTOM|wxEVT_SCROLL_LINEUP|wxEVT_SCROLL_LINEDOWN|wxEVT_SCROLL_PAGEUP|wxEVT_SCROLL_PAGEDOWN|wxEVT_SCROLL_THUMBTRACK|wxEVT_SCROLL_THUMBRELEASE|wxEVT_SCROLL_CHANGED,(wxObjectEventFunction)&wxkitFrame::OnrelXCmdScroll);
    Connect(ID_SLIDER2,wxEVT_SCROLL_TOP|wxEVT_SCROLL_BOTTOM|wxEVT_SCROLL_LINEUP|wxEVT_SCROLL_LINEDOWN|wxEVT_SCROLL_PAGEUP|wxEVT_SCROLL_PAGEDOWN|wxEVT_SCROLL_THUMBTRACK|wxEVT_SCROLL_THUMBRELEASE|wxEVT_SCROLL_CHANGED,(wxObjectEventFunction)&wxkitFrame::OnrelYCmdScroll);
    Connect(idMenuQuit,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxkitFrame::OnQuit);
    Connect(idMenuAbout,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxkitFrame::OnAbout);
    //*)
}

wxString convert(int i)
{
    wxString s;
    s << i;
    return s;
}

int convert(wxString s)
{
    std::stringstream ss;
    int i;
    ss << (std::string)s;
    ss >> i;
    return i;
}

int convert(std::string s)
{
    std::stringstream ss;
    int i;
    ss << s;
    ss >> i;
    return i;
}

long appendItem(wxListCtrl * lista, int x, int y)
{
    wxListItem newItem;
    newItem.SetId(lista->GetItemCount());
    newItem.SetText(convert(x));
    long index = lista->InsertItem(newItem);
    lista->SetItem(index, 1, convert(y));
    return index;
}

void deselect(wxListCtrl * lista)
{
    int n = lista->GetItemCount();
    for (int i = 0; i < n; i++)
        lista->SetItemState(i,0,wxLIST_STATE_SELECTED);
}

void wxkitFrame::deselectAll()
{
    deselect(AbsoluteList);
    deselect(RelativeList);
}

wxString GetContent(wxListCtrl * lista, long row, int column)
{
   wxListItem row_info;

   row_info.m_itemId = row;
   row_info.m_col = column;
   row_info.m_mask = wxLIST_MASK_TEXT;
   lista->GetItem( row_info );

   return row_info.m_text;
}

long GetSelected(wxListCtrl * listControl)
{
    return listControl->GetNextItem(-1,wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
}

bool wxkitFrame::isAbsActive()
{
    return (GetSelected(AbsoluteList) == -1 ? false : true );
}

void wxkitFrame::OnAbsoluteListSelection(wxListEvent& WXUNUSED(event))
{
    deselect(RelativeList);
    xKoord->SetValue(GetContent(AbsoluteList, GetSelected(AbsoluteList), 0));
    yKoord->SetValue(GetContent(AbsoluteList, GetSelected(AbsoluteList), 1));
    xKoord->SetRange(0,300);
    yKoord->SetRange(0,300);
}

void wxkitFrame::OnRelativeListSelection(wxListEvent& WXUNUSED(event))
{
    deselect(AbsoluteList);
    xKoord->SetValue(GetContent(RelativeList, GetSelected(RelativeList), 0));
    yKoord->SetValue(GetContent(RelativeList, GetSelected(RelativeList), 1));
    xKoord->SetRange(-relX->GetValue(), 300 - relX->GetValue());
    yKoord->SetRange(-relY->GetValue(), 300 - relY->GetValue());
}

wxkitFrame::~wxkitFrame()
{
    //(*Destroy(wxkitFrame)
    //*)
}

void wxkitFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close();
}

void wxkitFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
    wxString msg = "Made by Hakkel Tamas\n2015.10.29.";
    wxMessageBox(msg, _("Drone path planner"));
}

void wxkitFrame::OnButton1Click3(wxCommandEvent& WXUNUSED(event))
{
    if (isAbsActive())
    {
        AbsoluteList->SetItem(GetSelected(AbsoluteList),0, convert(xKoord->GetValue()));
        AbsoluteList->SetItem(GetSelected(AbsoluteList),1, convert(yKoord->GetValue()));
        RelativeList->SetItem(GetSelected(AbsoluteList),0, convert(xKoord->GetValue() - relX->GetValue()));
        RelativeList->SetItem(GetSelected(AbsoluteList),1, convert(yKoord->GetValue() - relY->GetValue()));
    }
    else if (GetSelected(RelativeList) != -1)
    {
        RelativeList->SetItem(GetSelected(RelativeList),0, convert(xKoord->GetValue()));
        RelativeList->SetItem(GetSelected(RelativeList),1, convert(yKoord->GetValue()));
        AbsoluteList->SetItem(GetSelected(RelativeList),0, convert(xKoord->GetValue() + relX->GetValue()));
        AbsoluteList->SetItem(GetSelected(RelativeList),1, convert(yKoord->GetValue() + relY->GetValue()));
    }
    Refresh();
}

void wxkitFrame::OnButton2Click(wxCommandEvent& WXUNUSED(event))
{
    long index = appendItem(AbsoluteList, xKoord->GetValue(), yKoord->GetValue());
    appendItem(RelativeList, xKoord->GetValue() - relX->GetValue(), yKoord->GetValue() - relY->GetValue());

    deselectAll();
    AbsoluteList->SetItemState(index, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
    Refresh();
}

void wxkitFrame::UpdateRelPoint()
{
    relPoint->SetLabel("(" + convert(relX->GetValue()) + ", " + convert(relY->GetValue()) + ")");
    Refresh();
}

void wxkitFrame::OnrelXCmdScroll(wxScrollEvent& WXUNUSED(event))
{
    UpdateRelPoint();
    for (int i = 0; i < RelativeList->GetItemCount(); i++)
    {
        int newVal = convert(GetContent(AbsoluteList,i,0)) - relX->GetValue();
        RelativeList->SetItem(i, 0, convert(newVal));
    }
}

void wxkitFrame::OnrelYCmdScroll(wxScrollEvent& WXUNUSED(event))
{
    UpdateRelPoint();
    for (int i = 0; i < RelativeList->GetItemCount(); i++)
    {
        int newVal = convert(GetContent(AbsoluteList,i,1)) - relY->GetValue();
        RelativeList->SetItem(i, 1, convert(newVal));
    }
}

bool pairCompare1(const std::pair<int, int>& firstElem, const std::pair<int, int>& secondElem) {
  return firstElem.first < secondElem.first;
}

bool pairCompare2(const std::pair<int, int>& firstElem, const std::pair<int, int>& secondElem) {
  return firstElem.second < secondElem.second;
}

void wxkitFrame::sortList(char col)
{
    std::vector<std::pair<int, int>> v;
    for (int i = 0; i < AbsoluteList->GetItemCount(); i++)
    {
        int x = convert(GetContent(AbsoluteList,i,0));
        int y = convert(GetContent(AbsoluteList,i,1));
        v.push_back(std::make_pair(x,y));
    }

    std::sort(v.begin(), v.end(), (col == 0 ? pairCompare1 : pairCompare2) );

    AbsoluteList->DeleteAllItems();
    RelativeList->DeleteAllItems();
    for (auto it = v.begin(); it != v.end(); it++)
    {
        appendItem(AbsoluteList, it->first, it->second);
        appendItem(RelativeList, it->first - relX->GetValue(), it->second - relY->GetValue());
    }
    Refresh();
}

void wxkitFrame::OnAbsoluteListColClick(wxListEvent& event)
{
    sortList(event.GetColumn());
}

void wxkitFrame::OnRelativeListColClick(wxListEvent& event)
{
    sortList(event.GetColumn());
}

void wxkitFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
{
    if (FDOpen->ShowModal() == wxID_CANCEL) return;

    std::ifstream f(FDOpen->GetPath());
    if (!f.good())
    {
        wxMessageBox(_("Input file is invalid."), _("Open"));
        return;
    }

    AbsoluteList->DeleteAllItems();
    RelativeList->DeleteAllItems();

    while (f.good())
    {
        std::string x, y;
        std::getline(f, x,',');
        std::getline(f, y);
        if (x == "" || y == "") break;
        appendItem(AbsoluteList, convert(x), convert(y));
        appendItem(RelativeList, convert(x) - relX->GetValue(), convert(y) - relY->GetValue());
    }
    Refresh();
}

void wxkitFrame::OnSave(wxCommandEvent& WXUNUSED(event))
{
    if (FDSave->ShowModal() == wxID_CANCEL) return;

    std::ofstream f(FDSave->GetPath());
    for (int i = 0; i < AbsoluteList->GetItemCount(); i++)
        f << GetContent(AbsoluteList, i, 0) << "," << GetContent(AbsoluteList, i, 1) << std::endl;
}

void wxkitFrame::draw(wxDC & dc)
{
    dc.Clear();
    // Befoglaló téglalap
    dc.SetPen(*wxBLACK_PEN);
    dc.SetBrush(*wxWHITE_BRUSH);
    dc.DrawRectangle(400, 40, 300, 300);
    // Megfigyellő helye (referenciapont)
    dc.SetPen(*wxRED_PEN);
    dc.DrawLine(395 + relX->GetValue(), 35 + relY->GetValue(), 405 + relX->GetValue(), 45 + relY->GetValue());
    dc.DrawLine(405 + relX->GetValue(), 35 + relY->GetValue(), 395 + relX->GetValue(), 45 + relY->GetValue());
    // Pontok
    dc.SetPen(*wxBLUE_PEN);
    int px, py;
    for (int i = 0; i < AbsoluteList->GetItemCount(); i++)
    {
        int x = convert(GetContent(AbsoluteList,i,0));
        int y = convert(GetContent(AbsoluteList,i,1));
        if (i) dc.DrawLine(400 + px, 40 + py, 400 + x, 40 + y);
        dc.DrawCircle(400 + x, 40 + y,5);
        px = x; py = y;
    }
}

void wxkitFrame::Refresh()
{
    wxClientDC dc(Panel1);
	draw(dc);
}

void wxkitFrame::OnPaint(wxPaintEvent & event)
{
    wxPaintDC dc(Panel1);
	draw(dc);
	event.Skip();
}
