#include <iostream>         // cin és cout parancsok
#include <fstream>          // fájlkezelés
#include <vector>           // vector adattípushoz
#include <set>              // halmaz adattípushoz
#include <map>              // szótár adattípushoz
#include <algorithm>        // sort függvény

using namespace std;

class mol                   // objektumterv: aminosav tulajdonságai (adatai) és egy-két metódus
{
    public:
        struct adatok {         // egy aminosav adatai
            string az;
            char betujel;
            int c,h,o,n,s;
            int t;
        };
        adatok aminosav;        // az aminosav egy struktúra a fenti mezőkkel
        map<char, int> atom;    // 4. feladatban lesz szerepe - C, H, O, N, S darabszáma egy aminosavban, maga a vegyjel lesz a kulcs
        int tomeg(adatok aminosav)      // legyen egy ilyen is... egy aminosav molekulatömege
        {
            return aminosav.c*12 + aminosav.h*1 + aminosav.o*16 + aminosav.n*14 + aminosav.s*32;
        }
        map<char, int> feltolt()    // minden objektum (aminosav) esetén feltöltjük ezt a szótárt az objektum (aminosav) adatai alapján
        {
            atom['C']=aminosav.c;
            atom['H']=aminosav.h;
            atom['O']=aminosav.o;
            atom['N']=aminosav.n;
            atom['S']=aminosav.s;
            return atom;            // ez a metódus ezt a szótárt "szolgáltatja"
        }
};

ofstream fki;       // globális fájlváltozó az egyszerűség kedvéért...

void kiir(int ssz, string sz)
{
    cout << "-------------------------------------------------------------------" << endl;
    cout << ssz << ". feladat - " << sz << endl;
    cout << "-------------------------------------------------------------------" << endl;
}

void F1_2(vector<mol> &m)
{
    kiir(1,"Adatok beolvasása");
    kiir(2,"Aminosavak relatív molekulatömegének meghatározása");
    ifstream fbe;
    fbe.open("aminosav.txt");
    mol tmp;    // tmp - átmentileg szükséges az adatok beolvasásához - mol objektum
    while(fbe>>tmp.aminosav.az&&fbe>>tmp.aminosav.betujel&&fbe>>tmp.aminosav.c&&fbe>>tmp.aminosav.h&&fbe>>tmp.aminosav.o&&fbe>>tmp.aminosav.n&&fbe>>tmp.aminosav.s)
    {
        tmp.aminosav.t=tmp.tomeg(tmp.aminosav);     // alkalmazzuk az objektumunk tomeg metódusát
        m.push_back(tmp);                           // m-ben objektumokat tárolunk
    }
    fbe.close();
}

bool tomeg_szerint(mol a, mol b)
{
    return a.aminosav.t < b.aminosav.t; // tömeg szerint növekvő sorrendbe rendezés
}

void F3(vector<mol> m)
{
    kiir(3,"Aminosavak relatív molekulatömegének rendezett kiírása");
    fki << "3. feladat" << endl;
    vector<mol> tmp;    // mol objektumok átmenetileg szükséges vektora
    tmp=m;              // tmp-t fogjuk rendezni, hogy az eredeti vektorunk megmaradjon
    sort(tmp.begin(),tmp.end(),tomeg_szerint);      // rendezés
    for(auto amin:tmp)  // vektorunk bejárása objektumról objektumra
    {
        cout << amin.aminosav.az << " " << amin.aminosav.t << endl;     // 3 betűs azonosító és a tömeg kiírása
        fki << amin.aminosav.az << " " << amin.aminosav.t << endl;      // fájlba is...
    }

}

void F4(vector<mol> m, vector<char> &bsa)   // bsa vektor címszerinti átadása, hogy feltölthessük a fájl alapján
{
    kiir(4,"BSA fehérje összegképlete");
    fki << "4. feladat" << endl;
    ifstream fbe;
    char tmp;
    // bsa.txt minden sorában egy karakter van
    fbe.open("bsa.txt");
    while(fbe>>tmp) bsa.push_back(tmp);
    // osszesen egy szótár, olyan, mint az objektumoknál leírt szótár, ebben összesítjük
    // az objektumok szótáraiban lévő adatokat (C H O N S kulcsok)
    map<char,int> osszesen;
    string betuk="CHONS";
    for(char b:betuk) osszesen[b]=0;    // osszesen inicializálása, nulla kezdőértékkel

    for(char a:bsa)         // bsa-ból vesszük az egyes aminosavakat (a)
        for(auto amin:m)    // m objektum-vektorunkon is végig megyünk...
            if(amin.aminosav.betujel==a)    // ha az aminosav és az objektum illeszkedik (betűjelek megegyeznek), akkor
                for(auto ok:amin.feltolt()) // az adott objektum (aminosav) szótára alapján összegezzük az adatokat az osszesen szótárban
                {
                    osszesen[ok.first]+=ok.second;  // first - a kulcs, second a kulcshoz tartozó számérték...
                }

    osszesen['H']-=2*(bsa.size()-1);        // minden kapcsolódáskor kilép egy H2O, ezt le kell vonni...
    osszesen['O']-=(bsa.size()-1);
    for(auto ossz:osszesen)
    {
        cout << ossz.first << " " << ossz.second << " ";    // összegek kiírása
        fki << ossz.first << " " << ossz.second << " ";     // fájlba is...
    }
    cout << endl;
    fki << endl;

}
bool hossz_szerint(vector<int> a, vector<int> b)
{
    return a[0] > b[0];     // csökkenő rendezés lánc hossza szerint
}

// Tirozin (Y), Fenilalanin (W) és a Triptofán (F) után hasít
void F5(vector<mol> m, vector<char> bsa)
{
    kiir(5,"BSA hasítása (Y, W, F után) - leghosszabb lánc adatai");
    fki << "5. feladat" << endl;
    vector<vector<int>> infok;      // információk, amiket keresünk: hossz, kezdete és vége - ilyen 3-asokból van vektorunk
    set<char> hasit={'Y','W','F'};  // halmazban lesznek a hasító aminosavak
    int kezdete=1, vege, hossz=0;   // infok "alkotóelemei", a kezdetet 1-re állítjuk
    for(int i=0;i<bsa.size();i++)   // bsa vektor bejárása
    {
        if(hasit.find(bsa[i])!=hasit.end())     // halmazunkban (hasit) megtaláljuk a bsa aktuális karakterét (aminosavát), tehát hasítás van
        {
            vege=i+1;                           // itt a vége a láncnak (index és valódi sorszám, ugye, ezért van a +1)
            hossz=vege-kezdete+1;               // a +1 itt kell
            infok.push_back({hossz,kezdete,vege});      // infok vektorba "pakoljuk" a három adat "kis" vektorát
            kezdete=vege+1;                     // az estelegesen következő lánc kezdete
        }
    }
    sort(infok.begin(),infok.end(),hossz_szerint);      // rendezzük a 3-asokat a hossz adat alapján csökkenő sorrendbe
    cout << "Leghosszabb lánc: " << infok[0][0] << ", kezdete: " << infok[0][1] << " vége: " << infok[0][2] << endl;
    fki << "Leghosszabb lánc: " << infok[0][0] << ", kezdete: " << infok[0][1] << " vége: " << infok[0][2] << endl;
}

void F6(vector<mol> m, vector<char> bsa)
{
    kiir(6,"BSA hasítása (R|A vagy R|V) - első láncban Ciszteinek száma");
    fki << "6. feladat" << endl;

    int vege;       // csak a vége kell, mert az első láncról van szó...
    for(int i=0;i<bsa.size()-1;i++)     // indexeléssel dolgozunk, hogy tudjunk hivatkozni az aktuális és a következő elemre is
    {
        if(bsa[i]=='R'&&(bsa[i+1]=='A'||bsa[i+1]=='V'))     // hasítás, ha R után A vagy V aminosav jön
        {
            vege=i+1;       // végét tároljuk és
            break;          // ki is ugorhatunk a ciklusból (lehetne while-lal is, de most így is jó lesz...
        }
    }
    cout << "A hasítás során keletkező első fehérjelánc részletben" << endl;
    // count függvény: adott vectorban adott értékű elemek darabszámát adja
    // bsa.begin(), azaz kezdettől a vege-ig terjedő részét nézzük a bsa vektornak
    cout << count(bsa.begin(),bsa.begin()+vege,'C') << " Cisztein (C) található" << endl;
    fki << "A hasítás során keletkező első fehérjelánc részletben" << endl;
    fki << count(bsa.begin(),bsa.begin()+vege,'C') << " Cisztein (C) található" << endl;
}

int main()
{
    setlocale(LC_ALL,"");

    vector<mol> molekula;
    vector<char> bsa;   // 4., 5. és 6. feladathoz
    F1_2(molekula);
    fki.open("eredmeny.txt");
    F3(molekula);
    F4(molekula,bsa);
    F5(molekula,bsa);
    F6(molekula,bsa);
    fki.close();

    return 0;
}
