#include "list.h"
#include "CopyToCout.hpp"
#include <iostream.h>

void main (void)
{
    //Defineste o lista vida de intregi
    list<int> bit_seq;
    //Valoarea care va fi citita de la intrare
    //initializata explicit cu 0. Oricum, ar fi
    //fost initializata si implicit cu zero.
    int input(0);
    //Contor pentru numarul de simboluri 1.
    int count_1(0);

    cout << "Introduceti valori 0 si 1, sau o alta valoare pentru oprire..." << endl;
    while(cin >> input)
    {
        if(!(input == 0 || input == 1))
                break;
        //Se utilizeaza metoda push_bach pentru inserarea
        //valorii la sfarsitul listei. Operatia se face prin copiere.
        bit_seq.push_back (input);
    }

    //Se creaza o noua lista, copie a primeia, care va contine
    //Secventa de biti prelucrata.
    list<int> bit_stuffed_seq(bit_seq);

    //Sunt definiti iteratori pentru parcurgerea unui ciclu.
    list<int>::iterator first(bit_stuffed_seq.begin());
    list<int>::iterator last(bit_stuffed_seq.end());

    //Ciclul in care se realizeaza prelucrarea secventei de biti
    while(first != last)
    {
        if (*first == 0)
                count_1 = 0;
        else
        if(*first == 1)
                count_1++;
        first++;
        if (count_1 == 5)
        {
            bit_stuffed_seq.insert (first, 0);
            count_1 = 0;
        }
    }

    //Ia sa vedem rezultatele ...
    cout << "Secventa de biti originala este :" << endl;
    CopyToCout(bit_seq.begin(), bit_seq.end());

    cout << "Secventa de biti prelucrata este :" << endl;
    CopyToCout(bit_stuffed_seq.begin(), bit_stuffed_seq.end());

    //Crestera relativa a secventei de biti ca rezultat al prelucrarii.
    double rel_exp;

    //Conversia explicita la double este neaparat necesara pentru ca
    //altfel constructia ar implica o conversie de la double (rezultatul
    //impartirii) la int (tipul operanzilor), cu pierderea partii fractionare.
    rel_exp = (double) bit_stuffed_seq.size() / bit_seq.size();
    rel_exp = (rel_exp - 1) * 100;

    cout.precision (4);
    cout << "Cresterea relativa : " << rel_exp << "%..." << endl;
    cout << "Cresterea absoluta : " << (bit_stuffed_seq.size()-bit_seq.size()) << " biti..." << endl;

    //Operatia de decodificare a secventei prelucrate.
    first = bit_stuffed_seq.begin();
    last  = bit_stuffed_seq.end();
    //Iterator utilizat deoarece un iterator la un element
    //extras din lista devine invalid.
    list<int>::iterator erase_it;

    count_1 = 0;

    while(first != last)
    {
        if(*first == 0)
                count_1 = 0;
        else count_1++;

        if (count_1 == 5)
        {
            erase_it = first;
            //Se cauta o eventuala eroare in secventa de biti
            if (*(++erase_it) != 0)
            {
                cerr << "Secventa de biti invalida ..." << endl;
                exit(0);
            }
            //Se elimina zeroul introdus artificial
            bit_stuffed_seq.erase(erase_it);
            count_1 = 0;
        }
        ++first;
    }

    cout << "Dupa decodificare : ";
    //Se compara rezultatul decodificarii...
    bit_stuffed_seq == bit_seq ? cout << "secventele sunt identice" :  \
                                 cout << "secventele difera";
    cout << endl;
}
