﻿#include <iostream>
#include <vector>
#include <map>
#include <sstream>
#include <cstdlib>
#include <fstream>
#include <iterator>
#include <algorithm>
using namespace std;

struct Film {
    string title, language;
    vector<string> genres, companies, countries;
    long long profit;
    unsigned duration, year, voters;
    float rate;

    vector<string> darabol(string adat) {
        stringstream ss;
        ss << adat;
        string temp;
        vector<string> eredmeny;
        while(getline(ss, temp, ','))
            eredmeny.push_back(temp.substr(temp.find_first_not_of(' ')));
        return eredmeny;
    }

    Film(string sor) {
        stringstream ss;
        ss << sor;
        string adat;
        getline(ss, adat, ';'); // ID
        getline(ss, adat, ';'); // Original title
        getline(ss, adat, ';'); // Genres
        genres = darabol(adat);
        getline(ss, language, ';'); // Language
        getline(ss, adat, ';'); // Budget
        long long budget = atoll(adat.c_str());
        getline(ss, adat, ';'); // Production companies
        companies = darabol(adat);
        getline(ss, adat, ';'); // Production countires
        countries = darabol(adat);
        getline(ss, adat, '.'); // Year
        year = atoi(adat.c_str());
        getline(ss, adat, ';'); // Rest of date
        getline(ss, adat, ';'); // Runtime
        duration = atoi(adat.c_str());
        getline(ss, adat, ';'); // Revenue
        profit = atoll(adat.c_str()) - budget;
        getline(ss, title, ';'); // Title
        getline(ss, adat, ';'); // Vote average
        rate = atof(adat.c_str());
        getline(ss, adat); // Vote count
        voters = atoi(adat.c_str());
    }
};

ostream& operator<<(ostream& out, Film film) {
    out << "Title: " << film.title << endl
        << "Language: " << film.language << endl
        << "Genres: ";
    copy (film.genres.begin(), film.genres.end(), ostream_iterator<string>(out, ", "));
    out << endl << "Profit: " << film.profit << endl
        << "# of companies: " << film.companies.size() << endl
        << "# of countries: " << film.countries.size() << endl
        << "Year of release: " << film.year << endl
        << "Vote averate: " << film.rate << endl
        << "Vote count: " << film.voters << endl;
}

unsigned count_comma(string text) {
    unsigned counter = 0;
    for (char c : text)
        if (c == ',') counter++;
    return counter;
}

struct DB {
    vector<Film> filmek;
    DB(string fname) {
        ifstream f(fname);
        if (f.fail()) {
            cerr << "A(z) " << fname << " fájl megnyitása nem sikerült!\n";
            return;
        }
        string sor;
        getline(f, sor); // Címsor kiolvasása
        while(getline(f, sor))
            filmek.push_back(Film(sor));
        cout << "Adatok beolvasása megtörtént.\n\n";
    }

    void ellenoriz() {
        for (size_t i = 0; i < 5; i++)
            cout << filmek[i] << endl;
    }

    // A csoport
    void feladat1_A() {
        auto it = max_element(filmek.begin(), filmek.end(), [] (const Film& f1, const Film& f2)
                              { return f1.rate < f2.rate and f2.year == 2010; });
        cout << "2010 legjobb filmje: " << it->title << endl;
    }

    void feladat2_A() {
        int db = count_if(filmek.begin(), filmek.end(), [](const Film& f)
                  { return f.companies.size() > 0; });
        float sum = accumulate(filmek.begin(), filmek.end(),0,[](float partial, const Film& f)
                       { return (f.companies.size() > 0 ? float(f.profit) / f.companies.size() : 0); });
        cout << sum  << " " << db << endl;
        cout << "Az egész adatbázis tekintve egy filmek a cégenkénti átlagos nyeresége: " << sum / db << endl;
    }

    void feladat3_A() {
        map<string, unsigned> genres;
        for (Film film : filmek)
            for (string genre : film.genres)
                genres[genre]++;
        auto it = max_element(genres.begin(), genres.end(),
                      [](const pair<string, unsigned>& g1, const pair<string, unsigned>& g2)
                              { return g1.second < g2.second; });
        cout << "A leggyakoribb mufaj: " << it->first << endl;
    }

    // B csoport
    void feladat1_B() {
        auto it = max_element(filmek.begin(), filmek.end(), [] (const Film& f1, const Film& f2)
                      { return f1.duration < f2.duration and
                            find(f2.companies.begin(), f2.companies.end(), "Walt Disney Pictures") != f2.companies.end(); });
        cout << "A Walt Disney Pictures leghosszabb filmje: " << it->title << " (" << it->duration << " perc)" << endl;
    }

    void feladat2_B() {
        auto it = max_element(filmek.begin(), filmek.end(), [](const Film& f1, const Film& f2)
                              { return f1.countries.size() < f2.countries.size(); });
        cout << "A következo filmek azok, amik a legtöbb országos érdekeltséggel rendelkeznek ("
                << it->countries.size() << " országban van érdekeltségük):\n";
        for (auto film : filmek)
            if (film.countries.size() == it->countries.size())
                cout << "\t" << film.title << endl;
    }

    void feladat3_B() {
        map<unsigned, float> evek;
        for (Film film : filmek)
            evek[film.year] += film.year;
        auto it = max_element(evek.begin(), evek.end(), [](const pair<unsigned, float>& e1, const pair<unsigned, float>& e2)
                              { return e1.second < e2.second; });
        cout << "A legsikeresebb filmes év (azaz amelyik évben a legnagyobb a megjelent filmek pontjainak összege): "
            << it->first << endl;
    }

    // C csoport
    void feladat1_C() {
        auto it = min_element(filmek.begin(), filmek.end(), [] (const Film& f1, const Film& f2)
                      { return f1.year < f2.year and
                            find(f1.genres.begin(), f1.genres.end(), "Science Fiction") != f1.genres.end(); });
        cout << "A legrégebbi SciFi film: " << it->title << " (" << it->year << ")" << endl;
    }

    void feladat2_C() {
        auto it = max_element(filmek.begin(), filmek.end(), [](const Film& f1, const Film& f2)
                              { return f1.genres.size() < f2.genres.size(); });
        cout << "A filmek, amelyek a legtöbb műfaj besorolást kaptak ("
                << it->genres.size() << " műfaj-besorolásuk van):\n";
        for (auto film : filmek)
            if (film.genres.size() == it->genres.size())
                cout << "\t" << film.title << endl;
    }

    void feladat3_C() {
        map<string, float> nyelvek;
        for (Film film : filmek)
            nyelvek[film.language]++;
        nyelvek["en"] = 0;
        auto it = max_element(nyelvek.begin(), nyelvek.end(), [](const pair<string, float>& e1, const pair<string, float>& e2)
                              { return e1.second < e2.second; });
        cout << "Az angol nyelvet nem számítva a " << it->first << " eredeti filmes nyelv a legelterjedtebb.\n";
    }

    // D csoport
    void feladat1_D() {
        int db = count_if(filmek.begin(), filmek.end(), [](const Film& f)
                          { return f.voters > 0; });
        int sum = accumulate(filmek.begin(), filmek.end(), 0, [](int partial, const Film& f)
                          { return partial + f.voters; });
        float average = float(sum) / db;
        int counter = count_if(filmek.begin(), filmek.end(), [average](const Film& f)
                          { return f.voters > average; });
        cout << "A szavazatot kapott filmek közül, " << counter << " db-nak van átlagon felüli szavazója (az átlag: "
                << average << "):\n";
    }

    void feladat2_D() {
        auto it = max_element(filmek.begin(), filmek.end(), [](const Film& f1, const Film& f2) ->
                 bool { size_t f1_size = f1.companies.size(), f2_size = f2.companies.size();
                        return (f1_size > 0 ? f1.profit / f1_size : 0) < (f2_size > 0 ? f2.profit / f2_size : 0); });
        cout << "A cégekre lebontott nyeresüg a legtöbb a következo filmnél a legtöbb: "
            << it->title << " (" << it->companies.size() << " cég, " << it->profit / it->companies.size() << " $/cég)" << endl;
    }

    void feladat3_D() {
        map<string, unsigned> cegek;
        for (Film film : filmek)
            for (string ceg : film.companies)
                cegek[ceg]++;
        auto it = max_element(cegek.begin(), cegek.end(), [](const pair<string, float>& e1, const pair<string, float>& e2)
                              { return e1.second < e2.second; });
        cout << "A legtöbb filmet jegyzo cég: " << it->first << " (" << it->second << " film)" << endl;
    }
};

int main() {
    setlocale(0, "");
    DB db("movies_tmdb.txt");
    //db.ellenoriz();

    cout << "---- A csoport -----\n";
    db.feladat1_A();
    db.feladat2_A();
    db.feladat3_A();

    cout << "\n---- B csoport -----\n";
    db.feladat1_B();
    db.feladat2_B();
    db.feladat3_B();

    cout << "\n---- C csoport -----\n";
    db.feladat1_C();
    db.feladat2_C();
    db.feladat3_C();

    cout << "\n---- D csoport -----\n";
    db.feladat1_D();
    db.feladat2_D();
    db.feladat3_D();
}
