/***************************************************************
 * Name:      wxkit16Main.cpp
 * Purpose:   Code for Application Frame
 * Author:     ()
 * Created:   2016-09-06
 * Copyright:  ()
 * License:
 **************************************************************/

#include "wxkit16Main.h"
#include <wx/msgdlg.h>
#include "operations.h"     ///Az operations fejléc a stringstream-et használó int-string, string-int átalakító függvényeket. A számológép szempontjából nem fontos.
#include "stdlib.h"     ///Ebben van a NULL
//(*InternalHeaders(wxkit16Frame)
#include <wx/intl.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(wxkit16Frame)
const long wxkit16Frame::ID_TEXTCTRL1 = wxNewId();
const long wxkit16Frame::ID_BUTTON1 = wxNewId();
const long wxkit16Frame::ID_BUTTON2 = wxNewId();
const long wxkit16Frame::ID_BUTTON3 = wxNewId();
const long wxkit16Frame::ID_BUTTON4 = wxNewId();
const long wxkit16Frame::ID_BUTTON5 = wxNewId();
const long wxkit16Frame::ID_BUTTON6 = wxNewId();
const long wxkit16Frame::ID_BUTTON7 = wxNewId();
const long wxkit16Frame::ID_BUTTON8 = wxNewId();
const long wxkit16Frame::ID_BUTTON9 = wxNewId();
const long wxkit16Frame::ID_BUTTON0 = wxNewId();
const long wxkit16Frame::ID_BUTTON11 = wxNewId();
const long wxkit16Frame::ID_BUTTON12 = wxNewId();
const long wxkit16Frame::ID_BUTTON13 = wxNewId();
const long wxkit16Frame::ID_BUTTON14 = wxNewId();
const long wxkit16Frame::ID_BUTTON15 = wxNewId();
const long wxkit16Frame::idMenuQuit = wxNewId();
const long wxkit16Frame::idMenuAbout = wxNewId();
const long wxkit16Frame::ID_STATUSBAR1 = wxNewId();
const long wxkit16Frame::ID_MESSAGEDIALOG1 = wxNewId();
//*)

BEGIN_EVENT_TABLE(wxkit16Frame,wxFrame)
    //(*EventTable(wxkit16Frame)
    //*)
END_EVENT_TABLE()

wxkit16Frame::wxkit16Frame(wxWindow* parent,wxWindowID id)
{
    //(*Initialize(wxkit16Frame)
    wxMenuItem* MenuItem2;
    wxMenuItem* MenuItem1;
    wxMenu* Menu1;
    wxMenuBar* MenuBar1;
    wxMenu* Menu2;

    Create(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("id"));
    TextCtrl1 = new wxTextCtrl(this, ID_TEXTCTRL1, wxEmptyString, wxPoint(72,96), wxSize(248,21), wxTE_READONLY, wxDefaultValidator, _T("ID_TEXTCTRL1"));
    Button1 = new wxButton(this, ID_BUTTON1, _("1"), wxPoint(72,144), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1"));
    Button2 = new wxButton(this, ID_BUTTON2, _("2"), wxPoint(160,144), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON2"));
    Button3 = new wxButton(this, ID_BUTTON3, _("3"), wxPoint(248,144), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON3"));
    Button4 = new wxButton(this, ID_BUTTON4, _("4"), wxPoint(72,176), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON4"));
    Button5 = new wxButton(this, ID_BUTTON5, _("5"), wxPoint(160,176), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON5"));
    Button6 = new wxButton(this, ID_BUTTON6, _("6"), wxPoint(248,176), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON6"));
    Button7 = new wxButton(this, ID_BUTTON7, _("7"), wxPoint(72,208), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON7"));
    Button8 = new wxButton(this, ID_BUTTON8, _("8"), wxPoint(160,208), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON8"));
    Button9 = new wxButton(this, ID_BUTTON9, _("9"), wxPoint(248,208), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON9"));
    Button0 = new wxButton(this, ID_BUTTON0, _("0"), wxPoint(160,240), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON0"));
    Button11 = new wxButton(this, ID_BUTTON11, _("+"), wxPoint(72,240), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON11"));
    Button12 = new wxButton(this, ID_BUTTON12, _("-"), wxPoint(248,240), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON12"));
    Button13 = new wxButton(this, ID_BUTTON13, _("="), wxPoint(160,272), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON13"));
    Button14 = new wxButton(this, ID_BUTTON14, _("Test"), wxPoint(72,272), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON14"));
    Button15 = new wxButton(this, ID_BUTTON15, _("Clear"), wxPoint(248,272), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON15"));
    MenuBar1 = new wxMenuBar();
    Menu1 = new wxMenu();
    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);
    StatusBar1 = new wxStatusBar(this, ID_STATUSBAR1, 0, _T("ID_STATUSBAR1"));
    int __wxStatusBarWidths_1[1] = { -1 };
    int __wxStatusBarStyles_1[1] = { wxSB_NORMAL };
    StatusBar1->SetFieldsCount(1,__wxStatusBarWidths_1);
    StatusBar1->SetStatusStyles(1,__wxStatusBarStyles_1);
    SetStatusBar(StatusBar1);
    NullErrorMessage = new wxMessageDialog(this, _("Hiba: Nullpointer generálva!"), _("Hiba!"), wxOK|wxICON_ERROR, wxDefaultPosition);

    Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON2,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON3,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON4,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON5,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON6,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON7,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON8,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON9,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON0,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnButton1Click);
    Connect(ID_BUTTON11,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnAddClick);
    Connect(ID_BUTTON12,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnSubstractClick);
    Connect(ID_BUTTON13,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnEqualsClick);
    Connect(ID_BUTTON14,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnTestClick);
    Connect(ID_BUTTON15,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxkit16Frame::OnClearClick);
    Connect(idMenuQuit,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxkit16Frame::OnQuit);
    Connect(idMenuAbout,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxkit16Frame::OnAbout);
    //*)
}

wxkit16Frame::~wxkit16Frame()
{
    //(*Destroy(wxkit16Frame)
    //*)
}

void wxkit16Frame::OnQuit(wxCommandEvent& event)
{
    Close();
}

void wxkit16Frame::OnAbout(wxCommandEvent& event)
{
    wxString msg = wxbuildinfo(long_f);
    wxMessageBox(msg, _("Welcome to..."));
}

void wxkit16Frame::OnButton1Click(wxCommandEvent& event)        ///Az itt leírtak az alapfeladatra vonatkoznak, ami csak n szám összeadásából áll. Ha valakit érdekel, a kikommentelt részek a kivonást, a törlést és az ans-t (elõzõ eredményt) tartalmazzák. Ezek egyáltalán nem bonyolultak. (Legalábbis a dinamikus gombkezeléshez képest....)
{
    //if(finished == 1) TextCtrl1->SetValue("Ans"); finished = 0;
    wxButton* generator = dynamic_cast<wxButton*>(event.GetEventObject());
    if(generator == NULL){                                                      ///dynamic_cast után mindig érdemes megnézni, hogy nem csináltál-e Nullpointer-t. Lásd a program alján, hogy miért.
        if(NullErrorMessage->ShowModal() == wxID_OK){
            Close();
        }
    }else{                                                                      ///Sikerült megoldani a dinamikus gombkezelést egy függvényben. Itt a rövid verzió:
        wxString s = generator->GetLabel();                                     ///Az event típus eltárolja azt az objektumot, ami õt generálta. A GetEventObject() visszaad egy wxObject típusú változót. Ezzel még sokra nem megyünk.
        int a = convert(s);                                                     ///A wxObject a wxButton egyik base class-a, ezért dynamic_cast-al át tudjuk alakítani wxButton típusúvá.
        num = (10*num)+a;                                                       ///A wxButton-nak már le tudod kérni a label-jét a GetLabel() függvénnyel, és azt már át tudod konvertálni egy stringstreammel int-be.
        TextCtrl1->SetValue(TextCtrl1->GetValue() + write(a));                  ///Ez valószínûleg nem az optimális megoldás, de *közel* van. Ha valakit érdekel a teljes magyarázat és egy dynamic_cast gyorstalpaló, azt megtaláljátok a program végén.
    }
}

void wxkit16Frame::OnAddClick(wxCommandEvent& event)
{
    //if(finished == 1) TextCtrl1->SetValue("Ans"); finished = 0;
    numbers.push_back(num);             ///Mikor a felhasználó megnyomja a + vagy = gombot, a jelenlegi "ideiglenes" szám elmentõdik a numbers vektorba.
    num = 0;
    operations.push_back("add");        ///Ez a vektor csak a mûveletek számát tárolja. Azért string-ekkel, mert így különbözõ mûveleteket is lehet tárolni, de az alapfeladatban egy sima vector<int> is elég lenne.
    TextCtrl1->SetValue(TextCtrl1->GetValue() + "+");
}

void wxkit16Frame::OnSubstractClick(wxCommandEvent& event)
{
    //if(finished == 1) TextCtrl1->SetValue("Ans"); finished = 0;
    /*numbers.push_back(num);
    num = 0;
    operations.push_back("substract");
    TextCtrl1->SetValue(TextCtrl1->GetValue() + "-");*/
}

void wxkit16Frame::OnTestClick(wxCommandEvent& event)
{
    /*std::string s;
    for(int i = 0; i < numbers.size(); ++i){
        s = s + write(numbers[i]);
        s = s + ",";*/
}

void wxkit16Frame::OnClearClick(wxCommandEvent& event)
{
    /*num = 0;
    sum = 0;
    ans = 0;
    numbers.clear();
    operations.clear();
    TextCtrl1->SetValue("");*/
}

void wxkit16Frame::OnEqualsClick(wxCommandEvent& event)
{
    numbers.push_back(num);     ///A jelenlegi "ideiglenes" számot elmentjük és lenullázzuk
    num = 0;
    if(ans == 0){
       sum = numbers[0];    ///Az összeget az elsõ számmal egyenlõvé tesszük
    }/*else{
        sum = ans;
    }*/
    for(int i = 0; i < operations.size(); ++i){
        if(operations[i] == "add"){
            sum = sum + numbers[i+1];   ///Ahány mûveletünk van, annyiszor hozzáadjuk a következõ számot az összeghez.
            }/*else if(operations[i] == "substract"){
            sum = sum - numbers[i+1];
        }*/
    }
    TextCtrl1->SetValue(TextCtrl1->GetValue() + "=");
    TextCtrl1->SetValue(TextCtrl1->GetValue() + write(sum));
    //ans = sum;
    numbers.clear();    ///A mentett számokat és mûveleteket lenullázzuk.
    operations.clear();
    //finished = 1;
}

/// Akit esetleg érdekel: Itt van a dinamikus gombkezelés és a castolás gyorstalpaló. (Ezt csak mazochistáknak ajánlom, több okból is. Elsősorban azért, mert én sem tudom tökéletesen használni a dynamic_cast-ot. Ezt csak azért írtam le, mert ha valakit éget a kíváncsiság, hogy az mi, akkor itt "konyhanyelven" leírtam, de ez nem azt jelenti, hogy én teljesen tudom, hogy ez hogyan működik.)
/// Ami a dinamikus gombokat illeti, több megoldás is van, de nem mindegyik jó. A legelsõ (és legegyszerûbb), hogy minden gombnak külön függvényt adsz. Mivel véges sok gombod van, ez egyáltalán nem rossz megoldás, és nem kel sokat bajlódni vele.
/// A második lehetõség az, ahogy én órán oldottam meg (van, akinek ezt a módszert mutattam szünetben). A gombok ID-ját átírtam 1, 2, 3, 4, stb.-re. Így egy egyszerû event.GetId() visszaadja a keresett számot. EZ VALÓSZÍNÛLEG EGY NAGYON ROSSZ MEGOLDÁS, ÉS SENKINEK SEM AJÁNLOM!!! (Valószínûleg sok hibát lehetne ezzel okozni)
/// A harmadik lehetõség a fent leírt castolós módszer.

/// Na, akkor mi is az a cast-olás? Nagyon egyszerûen leírva, típusok kozotti átváltás. Ilyet egyébként valószínûleg már mindenki csinált.
/// Pl:
/// double a = 13.0;
/// int b = (int) a;

/// Ez nem nehéz, viszont ezzel nem tudsz például intbõl stringet csinálni. A dynamic_cast-hoz az öröklõdés fogalmát is érteni kell (az sem nehéz), ugyanis a dynamic_cast az öröklődési hierarchián belül castol felfelé, lefelé és oldalra.
/// Tegyük fel, hogy csinálsz egy class-t, aminek vannak mezõi, tagfüggvényi, stb. Aztán akarsz csinálni egy másik, nagyon hasonló class-t, de nem akarod újra leírni azt a sok mezõt meg függvényt: ideje örököltetni.
/// Két classod lesz: Egy base class (amit egyszer megírsz), és egy derived class-od (ami örökli a base class összes public és protected tagját (a protected olyan, mint a private, csak tud öröklõdni is)).
/// Pl:
/// class állat{
/// public:
///     virtual void megetet() {...}
/// protected:
///     string gazda = "Én";
/// private:
///     string titok;
/// };
///
/// class kutya public: állat{
/// public:
///     void ugat() {...}
///      void kiagazda() {cout << gazda;}
/// };
///
/// class macska public: állat{
/// public:
///     void nyávog() {...}
///     void kiagazda() {cout << gazda;}
/// };

/// A "virtual" egy elég bonyolult dolog. Olvassátok el a referencában, ha érdekel. Ami itt fontos, az az, hogy ettől polimorffá változik a kutya és a macsaka class. (dynamic_cast csak polimorf class-okon működik)
/// Ennek az lesz a következménye, hogy ha csinálsz egy kutyát, azt meg fogod tudni etetni (és lesz gazdája is), továbbá fog tudni ugatni is. Ha egy macskát csinálsz, azt is meg fogod tudni etetni, de az csak nyávogni fog tudni.
/// Ez azért hasznos, mert drasztikusan le tudja rövödíteni a kódodat, ha nem ctrl-c, ctrl-v-zel, hanem helyette örököltetsz. (És pár hasznos dolgot is fogsz tudni csinálni, pl. dynamic_cast-olni)
/// Érdemes megfigyelni, hogy a titok egy privát mezõ, tehát NEM ÖRÖKLÕDIK, továbbá, hogy nincs lehetőségünk megtudni, hogy ki egy állat gazdája, csak arra, hogy ki egy kutya vagy macska gazdája.
/// Na, a dynamic_cast arra lesz jó, hogy megtudjuk, hogy egy állatnak ki a gazdája. (A dynamic_cast egy pointer-t ad vissza)
/// Pl:
/// állat a;
/// kutya* buksi = dynamic_cast<kutya*>(a);
/// if(buksi == NULL){
///        if(NullErrorMessage->ShowModal() == wxID_OK){
///            Close();
///        }
/// buksi->kiagazda();

/// Ez kiadja a gazdát. (Elméletileg... Egyelőre még a virtuális tagfüggvények misztériumával próbálok megbirkózni, és a tesztprogramjaim fele lefagy...) Példának azért jó, amit ide leírtam, még ha esetleg nem is működik.

/// A dynamic_cast után azért érdemes megnézni, hogy csináltál-e Nullpointer-t, mert ha egy Nullpointerrel próbálsz csinálni bármit is, akkor egy hatalmasat fogsz crash-elni, és nem lesz egyzserű kitalálni, hogy mi okozta a hibát.
/// Ez akkor történhet meg, ha valamit egy olyan class-á akarsz átcast-olni, ami nem rokona neki, és nem sikerül a cast.
/// (A nullpointer vizsgálatot egyébként Flugi javasolta nekem, úghogy szerintem érdemes így csinálni.)

/// A feladatban azért működik amit odaírtam, mert a wxObject-nek nem tudod lekérni a label-jét. Amikor viszont lecast-olod wxButton-nek, akkor ki tudod kérni tőle a label-t.

/// Ha valakinek van kedve, energiája és mazochizmusa, hogy nálam mélyebben átnézze ezeket, csak nyugodtan. (Így legalább értem, hogy a dynamic_cast miért nem része a tananyagnak :P)

