#include "graphics.hpp"// Grafikus könyvtár
#include <time.h>      // Randomszámgenerátor inicializálásához + késleltetés
#include <stdlib.h>    // Rand() függvény miatt
#include "vektor.h"    // saját készítésű 2D vektor, ami támogatja az alapvető vektorműveleteket
#include <sstream>     // float >> string konverzióhoz kell
#include <vector>      // Bolygók adatai, gombok
#include <fstream>     // Bolygók adatainak beolvasása

using namespace std;
using namespace genv;

string convert (float number){
    ostringstream buff;
    buff<<number;
    return buff.str();
}

float convert (string szoveg){
    stringstream buff;
    buff << szoveg;
    float temp;
    buff >> temp;
    return temp;
}

canvas* betolt(string fileName, int &szelesseg, int &magassag, bool trans = true)
{
    ifstream f("kepek/" + fileName + ".kep");
    int x,y;
    f >> x >> y;
    int R,G,B;
    canvas* temp = new canvas(x,y);
    *temp << move_to(0,0);
    for (int i = 0; i < y; i++)
    {
        for (int j = 0; j < x; j++)
        {
            f >> R >> G >> B;
            if (R != 96 || G != 96 || B != 128)
            {
                *temp << move_to(j,i);
                *temp << color(R,G,B) << dot;
            }

        }
    }
    temp->transparent(trans);
    szelesseg = x;
    magassag = y;
    f.close();
    return temp;
}

canvas* betolt(string fileName, bool trans = true)
{
    event ev;
    gin.timer(10);
    ifstream f("kepek/" + fileName + ".kep");
    int x,y;
    f >> x >> y;
    int R,G,B;
    canvas* temp = new canvas(x,y);
    *temp << move_to(0,0);
    for (int i = 0; i < y; i++)
    {
        if (i%2 && gin >> ev && ev.type == ev_key && ev.keycode == key_escape) exit(0);
        for (int j = 0; j < x; j++)
        {
            f >> R >> G >> B;
            if (R != 96 || G != 96 || B != 128)
            {
                *temp << move_to(j,i);
                *temp << color(R,G,B) << dot;
            }

        }
    }
    temp->transparent(trans);
    f.close();
    return temp;
}

// Rajzvászon mérete
const unsigned int X = 800;
const unsigned int Y = 600;

// maximális leszállási sebesség
float vLimit = 0.03;

// Mozgatás idõköze - a mozgásegyenletekhez kell
const int t = 10;

// **********   Leszállópálya   ************
// -----------------------------------------
struct leszallopalya
{
    int szelesseg, magassag;
    int x;
    const int y = Y-60;
    canvas* kep;

    leszallopalya ()
    {
        kep = betolt("leszallopalya",szelesseg,magassag);
        random();
    }

    void random() {x = (rand() % (int)((X-szelesseg)*0.8)) + (X-szelesseg)*0.1;}

    void rajzol()
    {
        gout << stamp(*kep,x,y);
        gout << color(150,150,150);
        for (unsigned int i = 0; i < X; i+=16) gout << move_to(i,y+magassag+10) << line(8,0);
    }
};

// **************   Bolygó   ***************
// -----------------------------------------
struct bolygo
{
    leszallopalya leszallopalyam;
    vector<float> gravitacio;
    vector<string> nev;
    vector<float> kezdoTomeg;
    vector<float> hajtomu;
    vector<canvas*> kep;
    int index = 0;

    bolygo()
    {
        ifstream f("bolygok.txt");
        string temp;
        int szam, i = 0;
        getline(f,temp); szam = convert(temp) + 1;

        gout << color (250, 230, 200) << move_to(X/2 - szam*6 + 15, Y/2 ) << box(szam*12 + 10, 20) << color(180,180,220);
        while (f.good())
        {
            gout << move_to(X/2 - szam*6 + 18 + 12*i++, Y/2 + 2) << box(10, 15) << refresh;
            getline(f,temp,',');
                nev.push_back(temp);
            getline(f,temp,',');
                gravitacio.push_back(convert(temp));
            getline(f,temp,',');
                kezdoTomeg.push_back(convert(temp));
            getline(f,temp,',');
                hajtomu.push_back(convert(temp));
            getline(f,temp);
                kep.push_back(betolt(temp.substr(1,temp.length()-1), false));
        }
        gout << move_to(X/2 - szam*6 + 18 + 12*i++, Y/2 + 2) << box(10, 15) << refresh;
        f.close();
    }

    float g() {return gravitacio[index];}
    float F() {return hajtomu[index];}
    float m() {return kezdoTomeg[index];}

    void elsoBolygo()
    {
        torol(true);
        gout << color(100,100,100) << move_to(X/2-220,Y/2-35) << box(450,80);  // Árnyék
        gout << color(250,230,200) << move_to(X/2-225, Y/2-40) << box(450,80);
        gout << color(0,0,0) << move_to(X/2-215, Y/2-20) << text("Az elso bolygo, ahol feladatot kell teljesitened: " + nev[index]);
        gout << move_to(X/2-120, Y/2) << text("Gravitacioja: " + convert(g()*10000) + " m/(s*s)");
        gout << move_to(X/2-120, Y/2 + 20) << text("Urhajod hatomuvenek ereje: " + convert(F()*1000000) + " N") << refresh;
    }

    void kovBolygo()
    {
        index++;
        torol(true);
        gout << color(100,100,100) << move_to(X/2-210,Y/2-45) << box(450,140);  // Árnyék
        gout << color(250,230,200) << move_to(X/2-215, Y/2-50) << box(450,140);
        gout << color(0,0,0) << move_to(X/2-200, Y/2-30) << text("Gratulalok, teljesitetted a szintet,");
        gout << move_to(X/2-180, Y/2-10) << text("ezert tovabbmehetsz a kovetkezo bolygora!");
        gout << move_to(X/2-100, Y/2+10) << text("Kovetkezo bolygo: " + nev[index]);
        gout << move_to(X/2-100, Y/2+30) << text("Gravitacioja: " + convert(g()*100000) + " m/(s*s)");
        gout << move_to(X/2-180, Y/2+60) << text("A feladat teljesitesehez erosebb hajtomuvet kapsz.");
        gout << move_to(X/2-100, Y/2+80) << text("Ereje: " + convert(F()*1000000) + " N") << refresh;
    }

    void torol(bool leszallopalyaNelkul = false)
    {
        gout << stamp(*kep[index],0,0);
        //gout << move_to(0,0) << color(0,0,0) << box(X,Y);
        if (!leszallopalyaNelkul) leszallopalyam.rajzol();
    }

    ~bolygo()
    {
        for (unsigned int i = 0; i < kep.size(); i++) delete kep[i];
    }
};

// **************   Gomb   *****************
// -----------------------------------------
struct gomb
{
private:
    int x, y, sz, m;
    string szoveg;
    bool egerfelette = false;
public:
    bool aktiv;

    gomb(int X, int Y, int szelesseg, int magassag, string felirat, bool AktivKezdeti)
    {
        x = X;
        y = Y;
        sz = szelesseg;
        m = magassag;
        szoveg = felirat;
        aktiv = AktivKezdeti;
    }

    void mozgat(int xUj, int yUj) { x = xUj; y = yUj;}

    bool esemeny(event &ev)
    {
        //gout << color(0,0,0) << move_to(x,y) << box(sz+5,m+5);        // Törlés
        gout << color(100,100,100) << move_to(x+5,y+5) << box(sz,m);  // Árnyék

        // Billentyűzetről való vezérléshez aktív gombot zöldre festi
            if (aktiv) gout << color(180,220,180);
            else gout << color(180,180,220);
        // Felette van-e az egér
            if (x < ev.pos_x && ev.pos_x < x+sz && y < ev.pos_y && ev.pos_y < y+m)
                egerfelette = true;
            else if (ev.type == ev_mouse && !(x < ev.pos_x && ev.pos_x < x+sz && y < ev.pos_y && ev.pos_y < y+m))
                egerfelette = false;

        // Gomb kirajzolása
        gout << move_to(x + egerfelette,y + egerfelette) << box(sz,m);

        // Szöveg kiírása
        gout << color(0,0,0) << move_to(x + sz/2 - szoveg.length()*4 + egerfelette,y + m/2 + 3 + egerfelette) << text(szoveg);

        if (egerfelette && ev.type == ev_mouse && ev.button == 1) return true;
        if (aktiv && ev.type == ev_key && ev.keycode == key_enter) return true;
        return false;
    }
};

// *************   Főmenü   ****************
// -----------------------------------------
struct fomenu
{
private:
    vector <gomb> gombok;
    char aktiv = 0;
    bool sugo = false;
    string sugoSzoveg;
    canvas* kep;
    void sugoRajzol()
    {
        gout << color(100,100,100) << move_to(50,200) << box(400,370);  // Árnyék
        gout << color(250,230,200) << move_to(45, 195) << box(400,370);
        gout << color(0,0,0) << move_to(60,220) << text(sugoSzoveg) << refresh;
    }
public:
    fomenu ()
    {
        {gomb g(550, 130, 120,40, "Jatek inditasa", true);
        gombok.push_back(g);}
        {gomb g(550, 190, 120,40, "Sugo", false);
        gombok.push_back(g);}
        {gomb g(550, 250, 120,40, "Kilepes", false);
        gombok.push_back(g);}
        kep = betolt("fomenu", false);
        ifstream f("sugo.txt");
        getline(f, sugoSzoveg, char(-1));
    }
    char esemeny(event &ev)
    {
        gout << stamp(*kep,0,0);
        if (ev.type == ev_key && ev.keycode == key_up)
        {
            gombok[aktiv].aktiv = false;
            aktiv = (aktiv + 2) % 3;
            gombok[aktiv].aktiv = true;
        }
        else if (ev.type == ev_key && ev.keycode == key_down)
        {
            gombok[aktiv].aktiv = false;
            aktiv = (aktiv + 1) % 3;
            gombok[aktiv].aktiv = true;
        }
        if (gombok[0].esemeny(ev)) return 1;
        if (gombok[1].esemeny(ev))
        {
            sugo = !sugo;
            gombok[aktiv].aktiv = false;
            aktiv = 1;
            gombok[1].aktiv = true;
        }
        if (gombok[2].esemeny(ev)) return 0;
        if (sugo) sugoRajzol();
        gout << refresh;
        return 2;
    }
    ~fomenu() { delete kep; }
};

// *************   Kis menü   ****************
// -----------------------------------------
struct kismenu
{
private:
    vector <gomb> gombok;
    char aktiv = 0;
    bool sugo = false;
    string sugoSzoveg;
    void sugoRajzol()
    {
        gout << color(100,100,100) << move_to(50,200) << box(400,370);  // Árnyék
        gout << color(250,230,200) << move_to(45, 195) << box(400,370);
        gout << color(0,0,0) << move_to(60,220) << text(sugoSzoveg);
    }
public:
    kismenu ()
    {
        {gomb g(X/2-60, Y/2+5, 125,40, "Jatek folytatasa", true);
        gombok.push_back(g);}
        {gomb g(X/2-60, Y/2+55, 125,40, "Sugo", false);
        gombok.push_back(g);}
        {gomb g(X/2-60, Y/2+105, 125,40, "Kilepes", false);
        gombok.push_back(g);};
        ifstream f("sugo.txt");
        getline(f, sugoSzoveg, char(-1));
    }
    void aktival (char a)
    {
        gombok[aktiv].aktiv = false;
        aktiv = a;
        gombok[aktiv].aktiv = true;
    }
    char esemeny(event &ev)
    {
        if (sugo)
        {
            sugoRajzol();
            gombok[0].mozgat(X/2+120, Y/2+5);
            gombok[1].mozgat(X/2+120, Y/2+55);
            gombok[2].mozgat(X/2+120, Y/2+105);
        }
        else
        {
            gombok[0].mozgat(X/2-60, Y/2+5);
            gombok[1].mozgat(X/2-60, Y/2+55);
            gombok[2].mozgat(X/2-60, Y/2+105);
        }
        gout << color(100,100,100) << move_to(X/2-75 + sugo*190,Y/2-5) << box(165,165);  // Árnyék
        gout << color(250,230,200) << move_to(X/2-80 + sugo*190, Y/2-10) << box(165,165);
        if (ev.type == ev_key && ev.keycode == key_up) aktival((aktiv + 2) % 3);
        else if (ev.type == ev_key && ev.keycode == key_down) aktival((aktiv + 1) % 3);
        if (gombok[0].esemeny(ev)) return 0;
        if (gombok[1].esemeny(ev))
        {
            sugo = !sugo;
            aktival(1);
        }
        if (gombok[2].esemeny(ev)) return 2;
        return 1;
    }
};

// **************   Ûrhajó   ***************
// -----------------------------------------
struct urhajo
{
private:
    vektor h, v;                       // hely- és sebességvektor

    int szelesseg, magassag;           // Ûrhajó kiterjedése
    float Ffel, Foldalra = 0.0005;     // Ûrhajó hajómûveinek az ereje
    float m;                           // Űrhajó tömege
    canvas *kep;
    canvas *tuz;
    canvas *tuzBalra;
    canvas *tuzJobbra;
    bolygo *bolygom;                   // Bolygóra mutató (g-t kell folyton lekérdezni)
    signed char oldalra; bool fel;     // Űrhajó mozgatása
    bool stop = false;                 // Játék lestoppolása
    kismenu kismenum;

    void rajzol()
    {
        if (oldalra == 1) gout << stamp(*tuzBalra,h.x+szelesseg/2-17,h.y+magassag-20);
        else if (oldalra == -1) gout << stamp(*tuzJobbra,h.x+szelesseg/2-12,h.y+magassag-20);
        else if (fel) gout << stamp(*tuz,h.x+szelesseg/2-9,h.y+magassag-20);

        gout << stamp(*kep,h.x,h.y);
    }

    void adatRajzol()
    {
        gout << color(200,200,220)<< move_to(0,0) << box(X,40);
        gout << color(0,0,0) << move_to(30,15) << text("gravitacio:  ") << text(convert(bolygom->g()*100000)) << text(" m/(s*s)");
        gout << color(0,0,0) << move_to(X/2,15) << text("urhajo tomege:  ") << text(convert(m*10)) << text(" t");
        if (v.hossz() > vLimit) gout << color(255,0,0);
        else gout << color(0,0,0);
        gout << move_to(30,30) << text("sebesseg:  ") << text(convert(v.hossz()*1000))<< text(" m/s");
        gout << color(0,0,0) << move_to(X/2,30) << text("magassag:  ") << text(convert((Y-h.y-20)*10)) << text(" m");
    }

    char mozog()
    {
        vektor F;

        // Ûrhajóra ható erõk eredõje
        F.y = m * bolygom->g();                    // Gravitációs erõ
        if (fel) F.y -= Ffel;                    // Fõhajtómû
        if (oldalra == -1) F.x = -Foldalra;      // Jobboldali hajtómû
        else if (oldalra == 1) F.x = Foldalra;   // Baloldali hajótmû

        h += v*t + 0.5*F/m*t*t;  // mozgatás
        v += F/m*t;              // lendületváltozás

        // Ha kimegy a képernyõrõl oldalt, akkor menjen a másik oldalra
        if (h.x < 0) h.x = X - szelesseg;
        else if (h.x + szelesseg > X) h.x = 0;

        // Ha alul megy ki, akkor GAME OVER
        if (h.y > (Y-magassag-bolygom->leszallopalyam.magassag + 5))
            return 3;

        // Ha a leszállópályán landol, akkor örülünk
        if (bolygom->leszallopalyam.y + 10 - (h.y + magassag) < 1
            && h.x > bolygom->leszallopalyam.x
                && h.x + szelesseg < bolygom->leszallopalyam.x + bolygom->leszallopalyam.szelesseg)
        {
            // Kis késleltetés, hogy ne tűnjön el azonnal
            clock_t start_time = clock();
            while(clock()-start_time < 500);
            // Megvizsgáljuk a lendületét is...
            if (v.hossz() < vLimit) return 2;
            else return 3;
        }

        rajzol();
        adatRajzol();
        return 1;
    }

public:

    urhajo (bolygo *bolygoBe)
    {
        bolygom = bolygoBe;
        srand (time(NULL));
        init();
        kovBolygo();
        kep = betolt("urhajo",szelesseg, magassag);
        tuz = betolt("tuz");
        tuzBalra = betolt("tuzBalra");
        tuzJobbra = betolt("tuzJobbra");
    }

    void init ()
    {
        h.x = (rand() % (int)((X-szelesseg)*0.8)) + (X-szelesseg)*0.1;
        h.y = 45;
        fel = false;
        oldalra = 0;
        v.null();
    }

    char mNovel()
    {
        m+=5;
        init();
        if (m*bolygom->g() > Ffel * 0.2) return 4;
        else return 1;
    }

    float tomeg() {return m;}

    void kovBolygo()
    {
        Ffel = bolygom->F();
        m = bolygom->m();
        init();
    }

    char esemeny(event &ev)
    {
        if (ev.type == ev_key)
        {
            switch (ev.keycode)
            {
                case key_up: fel = true; break;
                case -key_up: fel = false; break;
                case key_left: oldalra = -1; break;
                case -key_left: oldalra = 0; break;
                case key_right: oldalra = 1; break;
                case -key_right: oldalra = 0; break;
                case key_backspace: return 0; break;
                case key_space: stop = !stop; break;
            }
        }
        if (stop)
        {
            bolygom->torol();
            rajzol(); adatRajzol();
            char temp = kismenum.esemeny(ev);
            if (temp == 2) return 255;
            stop = temp;
        }
        if (ev.type == ev_timer && !stop)
        {
            bolygom->torol();
            return mozog();
        }
        return 1;
    }
    ~urhajo()
    {
        delete kep;
        delete tuz;
        delete tuzBalra;
        delete tuzJobbra;
    }
};

// **************   Main   *****************
// -----------------------------------------
int main ()
{
    gout.open(X,Y);

    gout << color (255,255,255) << move_to(X/2-25, Y/2-6) << text("betoltes...") << refresh;

    bolygo bolygom;
    fomenu foMenum;
    urhajo urhajom(&bolygom);

    unsigned char STATUS = 0;

    event ev;
    gin.timer(t);
    while(gin >> ev && (ev.keycode != key_escape || STATUS != 255))
    {
        if (ev.keycode == key_escape) break;
        // Főmenü -----------------------------------
        if (STATUS == 0)
        {
            char temp = foMenum.esemeny(ev);
            if (temp == 1) // Játék indítása
            {
                STATUS = 1;
                bolygom.elsoBolygo();

                // 3 mp késleltetés, vagy billentyűzeteseményre várakozás
                clock_t start_time = clock();
                while(gin >> ev && clock()-start_time < 6000)
                {
                   if (ev.type == ev_key)
                      { if(ev.keycode == key_space || ev.keycode == key_enter) break;
                        if(ev.keycode == key_escape) return 0; }
                }
            }
            else if (temp == 0) break;   // Kilépés

        }
        // Játék közben -----------------------------
        else if (STATUS == 1)
        {
            STATUS = urhajom.esemeny(ev);
            gout << refresh;
        }
        // Átvezető képernyők ---------------------------
        // Sikeres *******
        else if (STATUS == 2)
        {
            STATUS = urhajom.mNovel();
            bolygom.leszallopalyam.random();

            if (STATUS == 1)   // Csak akkor, ha még nem túl nagy a tömeg
            {
                bolygom.torol(true);

                gout << color(100,100,100) << move_to(X/2-200,Y/2-30) << box(400,115);  // Árnyék
                gout << color(250,230,200) << move_to(X/2-205, Y/2-35) << box(400,115);
                gout << color(0,0,0) << move_to(X/2-90, Y/2-5) << text("Feladat teljesitve!");
                gout << move_to(X/2-180, Y/2+15) << text("A kovetkezo feladat soran");
                gout << move_to(X/2-150, Y/2+35) << text("nagyobb rakomanyt kell szallitanod");
                gout << move_to(X/2-130, Y/2+60) << text("Az urhajo uj tomege: ") << text(convert(urhajom.tomeg())) << text("t") << refresh;

                // 3 mp késleltetés, vagy billentyűzeteseményre várakozás
                clock_t start_time = clock();
                while(gin >> ev && clock()-start_time < 6000)
                {
                   if (ev.type == ev_key)
                      { if(ev.keycode == key_space || ev.keycode == key_enter) break;
                        if(ev.keycode == key_escape) return 0; }
                }
            }

        }
        // GAME OVER ******
        else if (STATUS == 3)
        {
            bolygom.torol(true);
            if (bolygom.nev[bolygom.index] == "Nap")
            {
                gout << color(100,100,100) << move_to(X/2-70,Y/2-20) << box(180,30);  // Árnyék
                gout << color(250,230,200) << move_to(X/2-75, Y/2-25) << box(180,30);
                gout << color(0,0,0) << move_to(X/2-63, Y/2-5) << text("MISSION IMPOSSIBLE ;)") << refresh;
                STATUS = 0;

                // 3 mp késleltetés, vagy billentyűzeteseményre várakozás
                clock_t start_time = clock();
                while(gin >> ev && clock()-start_time < 5000)
                {
                   if (ev.type == ev_key)
                      { if(ev.keycode == key_space || ev.keycode == key_enter) break;
                        if(ev.keycode == key_escape) return 0; }
                }
            }
            else
            {
                gout << color(100,100,100) << move_to(X/2-40,Y/2-20) << box(110,30);  // Árnyék
                gout << color(250,230,200) << move_to(X/2-45, Y/2-25) << box(110,30);
                gout << color(0,0,0) << move_to(X/2-32, Y/2-8) << text("GAME OVER") << refresh;

                urhajom.init();
                bolygom.leszallopalyam.random();
                STATUS = 1;

                // 3 mp késleltetés, vagy billentyűzeteseményre várakozás
                clock_t start_time = clock();
                while(gin >> ev && clock()-start_time < 3000)
                {
                   if (ev.type == ev_key)
                      { if(ev.keycode == key_space || ev.keycode == key_enter) break;
                        if(ev.keycode == key_escape) return 0; }
                }
            }

        }
        // Következő bolygó ***
        else if (STATUS == 4)
        {
            bolygom.kovBolygo();
            urhajom.kovBolygo();
            STATUS = 1;

            // 3 mp késleltetés, vagy billentyűzeteseményre várakozás
            clock_t start_time = clock();
            while(gin >> ev && clock()-start_time < 5000)
            {
               if (ev.type == ev_key)
                  { if(ev.keycode == key_space || ev.keycode == key_enter) break;
                    if(ev.keycode == key_escape) return 0; }
            }
        }
        if (STATUS == 255) return 0;
    }

    return 0;
}
