#include <iostream>
#include <sstream>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <map>
#include <cmath>
#include <ctime>
using namespace std;

const double PI = 3.14159265359;

struct coord {
    double x,y,z;
};

struct Csillag {
    string common_name;
    string sibling;
    coord position;
    string color_code;
    double visual_magnitude;
    double absolute_magnitude;
    double parallax;
    double error;
    double distance;
    string gliese;
    string notes;
};

ostream& operator<< (ostream& out, Csillag csillag) {
    out << csillag.common_name << ';'
        << csillag.sibling << ';'
        << '(' << csillag.position.x << ',' << csillag.position.y << ',' << csillag.position.z << ')'
        << csillag.color_code << ';'
        << csillag.visual_magnitude << ';'
        << csillag.absolute_magnitude << ';'
        << csillag.parallax << ';'
        << csillag.error << ';'
        << csillag.distance << ';'
        << csillag.gliese << ';'
        << csillag.notes << endl;
    return out;
}

double szog2rad(string szog_perc) {
    stringstream ss(szog_perc);
    string szam;
    getline(ss, szam, ' ');
    double ora = atof(szam.c_str());
    getline(ss, szam, ' ');
    double perc = atof(szam.c_str());
    return (ora+perc/60)/24*360*PI/180;
}

coord rad2Descartes(double distance, double lambda, double phi) {
    return {
        distance*cos(phi)*cos(lambda),
        distance*cos(phi)*sin(lambda),
        distance*sin(phi)
    };
}

Csillag sor_darabolo(string sor) {
    stringstream ss(sor);
    string konvertalando;
    Csillag csillag;
    getline(ss, csillag.common_name, ';');
    getline(ss, csillag.sibling, ';');
    getline(ss, konvertalando, ';');
    double lambda = szog2rad(konvertalando);
    getline(ss, konvertalando, ';');
    double phi = szog2rad(konvertalando);
    getline(ss, csillag.color_code, ';');
    getline(ss, konvertalando, ';');
    csillag.visual_magnitude = atof(konvertalando.c_str());
    getline(ss, konvertalando, ';');
    csillag.absolute_magnitude = atof(konvertalando.c_str());
    getline(ss, konvertalando, ';');
    csillag.parallax = atof(konvertalando.c_str());
    getline(ss, konvertalando, ';');
    csillag.error = atof(konvertalando.c_str());
    getline(ss, konvertalando, ';');
    csillag.distance = atof(konvertalando.c_str());
    getline(ss, csillag.gliese, ';');
    getline(ss, csillag.notes);

    csillag.position = rad2Descartes(csillag.distance, lambda, phi);
    return csillag;
}

struct Adatok {
    vector<Csillag> csillagok;

    void beolvas(string fname) {
        ifstream f(fname);
        if (f.fail())
            cerr << "A fajl megnyitasa nem sikerult!\n";
        string sor;
        getline(f, sor); // Elso sor nem erdekel
        while(getline(f, sor))
            csillagok.push_back(sor_darabolo(sor));
        cout << "Adatok beolvasasa sikeresen megtortent!\n\n";
    }

    void ellenoriz() {
        cout << "Elso 3 sor:\n";
        for (size_t i = 0; i < 3; i++)
            cout << "\t" << csillagok[i];
        cout << "Utolso 3 sor:\n";
        for (size_t i = csillagok.size()-4; i < csillagok.size(); i++)
            cout << "\t" << csillagok[i];
    }

    void A_csop_1 () {
        double resz_osszeg = 0;
        unsigned db = 0;
        for (auto csillag : csillagok) {
            if (csillag.visual_magnitude <= 6 and csillag.visual_magnitude != 0) {
                resz_osszeg += csillag.distance;
                db++;
            }
        }
        cout << "\tA szabad szemmel lathato csillagok atlagos tavolsaga a Foldtol: " << resz_osszeg / db << endl;
    }

    void A_csop_2 () {
        map<string,unsigned> szamlalo;
        for (auto csillag : csillagok)
            szamlalo[csillag.color_code]++;
        map<unsigned,string> rendezo;
        for (auto elem : szamlalo)
            if (rendezo.count(elem.second) == 0)
                rendezo[elem.second] = elem.first;
            else
                rendezo[elem.second] += ", " + elem.first;
        auto utolso_elotti = --rendezo.rbegin();
        cout << "\tA masodik leggyakoribb csillag szin kod: " << utolso_elotti->second
            << " (" << utolso_elotti->first << "x fordul elo)." << endl;
    }

    double tavolsag_negyzet(Csillag cs1, Csillag cs2) {
        return
            (cs1.position.x-cs2.position.x)*(cs1.position.x-cs2.position.y)+
            (cs1.position.y-cs2.position.y)*(cs1.position.y-cs2.position.y)+
            (cs1.position.y-cs2.position.y)*(cs1.position.y-cs2.position.y);
    }

    void A_csop_3() {
        double max_tavolsag = 0;
        size_t egyik, masik;
        for (size_t i = 0; i < csillagok.size() - 1; i++)
            for (size_t j = i + 1; j < csillagok.size(); j++)
                if (tavolsag_negyzet(csillagok[i],csillagok[j]) > max_tavolsag) {
                    max_tavolsag = tavolsag_negyzet(csillagok[i],csillagok[j]);
                    egyik = i;
                    masik = j;
                }
        cout << "\tA ket egymastol legtavolabb levo csillag: "
            << csillagok[egyik].common_name << " es " << csillagok[masik].common_name
            << " (tavolsaguk: " << sqrt(max_tavolsag) << " fenyev)" << endl;
    }

    void B_csop_1() {
        map<string,unsigned> szamlalo;
        for (auto csillag : csillagok)
            szamlalo[csillag.sibling]++;
        cout << "\tMono naprendszerek: " << szamlalo[""] << endl
             << "\tBinaris naprendszerek: " << szamlalo["B"] - szamlalo["C"] - szamlalo["D"] << endl
             << "\tTrinaris naprendszerek: " << szamlalo["C"] - szamlalo["D"] << endl
             << "\tKvadralis naprendszerek: " << szamlalo["D"] << endl;
    }

    double relativ_hiba(Csillag cs) {
        return cs.error/cs.parallax*100;
    }

    void B_csop_2() {
        double resz_osszeg = 0;
        for (size_t i = 1; i < csillagok.size(); i++)
            resz_osszeg += relativ_hiba(csillagok[i]);
        double atlag = resz_osszeg/(csillagok.size()-1);
        cout << "\tA relativ hiba nagysaga az adatbazison: " << atlag << endl;
        Csillag legtavolabbi = csillagok[1];
        for (size_t i = 2; i < csillagok.size(); i++)
            if (relativ_hiba(csillagok[i]) < atlag and csillagok[i].distance > legtavolabbi.distance)
                legtavolabbi = csillagok[i];
        cout << "\tAz atlagnal kisebb relativ hibaju csillagok kozul a legtavolabbi: " << legtavolabbi.common_name
            << " (" << legtavolabbi.distance << " fenyev)." << endl;
    }

    void B_csop_3() {
        A_csop_3();
    }
};

int main() {
    Adatok adatok;
    adatok.beolvas("NearStars.csv");
    //adatok.ellenoriz();
    cout << " -------- A csoport --------- \n";
    cout << "1. feladat\n";
    adatok.A_csop_1();
    cout << "2. feladat\n";
    adatok.A_csop_2();
    cout << "3. feladat\n";
    adatok.A_csop_3();
    cout << "\n -------- B csoport --------- \n";
    cout << "1. feladat\n";
    adatok.B_csop_1();
    cout << "2. feladat\n";
    adatok.B_csop_2();
    cout << "3. feladat\n";
    adatok.B_csop_3();
}
