#include "import.h"

// -----------------------------------------------------------------------
void randomize(void)
{
    time_t t;
    srand((unsigned) time(&t));
}

// -----------------------------------------------------------------------
Import::Import(MStr filename)
{
    try {
//         cout << "Lexical initialization: " << filename.c_str() << endl;
        l = new Lexan();
        l->init(filename.c_str());
        input_num = output_num = 0;
    }
    catch(...) {
        cout << "Cannot open input file.\n";
        exit(2);
    }
}

// -----------------------------------------------------------------------
Import::~Import()
{
    //cout << "destruct" << endl;
}

// -----------------------------------------------------------------------
int Import::get_input_num(void)
{
    return input_num;
}

// -----------------------------------------------------------------------
int Import::get_output_num(void)
{
    return output_num;
}

// -----------------------------------------------------------------------
void Import::print_inputs(void)
{
    for(vector<Input_elem>::iterator it = var_list.begin(); it != var_list.end(); it++){
        if (it->type == T_INPUT)
            cout << it->name << " ";
    }
    cout << endl;
}

// -----------------------------------------------------------------------
vector<Input_elem>& Import::get_var_list(void)
{
    return var_list;
}

// -----------------------------------------------------------------------
bool Import::import_bench()
{
    token = l->NextToken();
    randomize();

    try {
        inputs();
//         random_shuffle(var_list.begin(), var_list.end());
//         sort(var_list.begin(), var_list.end());
//         print_inputs();
//         var_list.sort();
//         print_inputs();
        outputs();
        assigns();
    }
    catch(std::runtime_error &e){
        cout << "error occured: " << e.what() << endl;
        return false;
    }
    catch(std::exception &e){
        cout << "unknown error: " << e.what() << endl;
        return false;
    }

    delete l;

    if (token != LEX_NULL)
        error();

    return true;
}

// -----------------------------------------------------------------------
// int Input_elem::operator==(const Input_elem& comp) const
// {
//     if (this->name == comp.name) return 1;
//
//     // pro testovani vhodnosti poradi promennych - generovani nahodneho poradi
// //     if (rand()%10 >= 5) return 1;
//     return 0;
// }
//
// // -----------------------------------------------------------------------
int Input_elem::operator<(const Input_elem& comp) const
{
    if (this->name < comp.name) return 1;
//
//     // pro testovani vhodnosti poradi promennych - generovani nahodneho poradi
// //     if (rand()%10 >= 5) return 1;
    return 0;
}

// -----------------------------------------------------------------------
void Import::inputs()
{
    Input_elem i_el;

    if(token==LEX_INPUT) {
        token=l->NextToken();
        if(token==LEX_LPA) {
            token=l->NextToken();
            if(token==LEX_IDENT){
//                 cout << "vytvarim novy strom pro promennou " << l->Lex_AStr << endl;
//                 bdd.push_back(f_ins);
                i_el.name = l->Lex_AStr;
                i_el.type = T_INPUT;
                i_el.in_vars.clear();

                var_list.push_back(i_el);
                input_num++;

                token=l->NextToken();
                if(token==LEX_RPA){
                    token=l->NextToken();
                    inputs();
                }
                else {
                    error();
                }
            }
            else {
                error();
            }
        }
        else {
            error();
        }
    }
    else return;
}

// -----------------------------------------------------------------------
void Import::outputs()
{
    Input_elem i_el;

    if(token==LEX_OUTPUT) {
        token=l->NextToken();
        if(token==LEX_LPA) {
            token=l->NextToken();
            if(token==LEX_IDENT) {
//                 out.push_back(l->Lex_AStr);
//                 cout << l->Lex_AStr << endl;

                i_el.name = l->Lex_AStr;
                i_el.type = T_OUTPUT;
                i_el.in_vars.clear();

                var_list.push_back(i_el);
                output_num++;

                token=l->NextToken();
                if(token==LEX_RPA) {
                    token=l->NextToken();
                    outputs();
                }
                else {
                    error();
                }
            }
            else {
                error();
            }
        }
        else {
            error();
        }
    }
    else return;
}

// -----------------------------------------------------------------------
void Import::assigns()
{
    Input_elem i_el;

    if(token == LEX_IDENT) {
        i_el.name = l->Lex_AStr;
        token=l->NextToken();

        if(token == LEX_ASSIGN) {
            MStr eval_param;
            token = l->NextToken();
            i_el.type = hradlo();
            token = l->NextToken();

            if (token == LEX_LPA){
                while(token != LEX_RPA){
                    token = l->NextToken();

                    if (token == LEX_IDENT){
                        i_el.in_vars.push_back(l->Lex_AStr);

                        token = l->NextToken();
                    }
                    else {
                        error();
                    }
                }
            }
            else {
                error();
            }

            var_list.push_back(i_el);
            token = l->NextToken();
            assigns();
        }
        else {
            error();
        }
    }
    else return;
}

// -----------------------------------------------------------------------
int Import::hradlo(void)
{
    int eval_param=-1;

    switch(token) {
        case LEX_AND:
            eval_param=T_AND;
            break;
        case LEX_NAND:
            eval_param=T_NAND;
            break;
        case LEX_OR:
            eval_param=T_OR;
            break;
        case LEX_NOR:
            eval_param=T_NOR;
            break;
        case LEX_XOR:
            eval_param=T_XOR;
            break;
        case LEX_XNOR:
            eval_param=T_XNOR;
            break;
        case LEX_BUFF:
            eval_param=T_BUF;
            break;
        case LEX_NOT:
            eval_param=T_NOT;
            break;
        default:
            error();
    }

    return eval_param;
}

// -----------------------------------------------------------------------
void Import::error()
{
   throw std::runtime_error(("Error on the line " + MStr(l->rowcount)).c_str());
}

