//---------------------------------------------------------------------------
#include <sstream>
#include "blif_parser.h"
#include "import.h"
using namespace hub;
//---------------------------------------------------------------------------
void BlifParser::run(std::istream& in, const std::string& fi) {
    l.init(in, fi);

    // we need to know the model name from the name of the BLIF file, if .model is not specified
    modelName = ImportLang::bareName(fi);

    token = l.NextToken();
    while( token != LEX_BLIF_NULL ) {
        switch( token ) {
        case LEX_BLIF_MODEL:   model();   break;
        case LEX_BLIF_INPUTS:  inputs();  break;
        case LEX_BLIF_OUTPUTS: outputs(); break;
        case LEX_BLIF_CLOCK:   break;
        case LEX_BLIF_END:     token = l.NextToken();  break;
        default:               command(); break;
        }
    }
    client_->haveSubckt(subcktRecords);
    client_->endModel();
}
//---------------------------------------------------------------------------
void BlifParser::model() {
    token = l.CheckNextToken(LEX_BLIF_DATA);
    modelName = l.Lex_AStr;
    token = l.NextToken();

    client_->haveModel (modelName);
    firstModel=true;
}
//---------------------------------------------------------------------------
void BlifParser::inputs() {
    std::list<std::string> inputNames;
    std::string data;
    std::string is;
    unsigned it = 0;

    //we need to check, if the entity is already created
    if( !firstModel ) {
         // first .model missing, emulate
        client_->haveModel(modelName);
        firstModel = true;
    }

    token = l.CheckNextToken(LEX_BLIF_DATA);
    data = l.Lex_AStr;
    while( true ) {
        is = "";
        while(it < data.length() && data[it] != ' ')
        is += data[it++];
        inputNames.push_back(is);
        if (it == data.length()) break;
        while( data[it] == ' ' ) it++;
    }
    client_->haveInPorts(inputNames);
    token = l.NextToken();
}
//---------------------------------------------------------------------------
void BlifParser::outputs() {
    //we need to check, if the entity is already created
    if( !firstModel ) {
        //this is the first model, it's the one returned to user
        client_->haveModel(modelName);
        firstModel = true;
    }

    std::list<std::string> outputNames;
    std::string data;
    std::string is;
    unsigned it = 0;

    token = l.CheckNextToken(LEX_BLIF_DATA);
    data = l.Lex_AStr;
    while (true) {
        is = "";
        while (it < data.length() && data[it] != ' ')
            is += data[it++];
        outputNames.push_back(is);
        if (it == data.length()) break;
        while (data[it] == ' ') it++;
    }

    client_->haveOutPorts(outputNames);
    token = l.NextToken();
}
//---------------------------------------------------------------------------
void BlifParser::startkiss() {
	int i, o, p, s;
	string resetState;
	StateTableRow stateRow;
	std::list<StateTableRow> stateTable;
	int index1, index2;

	p = -1;
	s = -1;
	token = l.NextToken();
	while( token != LEX_BLIF_END_KISS ) {
        switch( token ) {
        case LEX_BLIF_KISS_INPUT: {
            token = l.NextToken(); 
            istringstream ss(l.Lex_AStr);		
            ss >> i;
            break; }              

        case LEX_BLIF_KISS_OUTPUT: {
		    token = l.NextToken();
		    istringstream ss(l.Lex_AStr);
		    ss >> o;
            break; }
        
        case LEX_BLIF_KISS_TERMS: {
		    token = l.NextToken();
		    istringstream ss(l.Lex_AStr);
		    ss >> p;
            break; }

        case LEX_BLIF_KISS_STATES: {
		    token = l.NextToken();
		    istringstream ss(l.Lex_AStr);
		    ss >> s;
            break; }

        case LEX_BLIF_KISS_RESET:
		    token = l.NextToken();
		    resetState = l.Lex_AStr;
		    break;

	    case LEX_BLIF_DATA:
		    //input
		    std::string row = l.Lex_AStr;

		    index1 = 0;
		    index2 = row.find_first_of(" ");
		    stateRow.input = row.substr(index1, index2);
		    index1 = index2+1;

		    index2 = row.find_first_of(" ", index1);
		    stateRow.currState = row.substr(index1, index2 - index1);
		    index1 = index2+1;

		    index2 = row.find_first_of(" ", index1);
		    stateRow.nextState = row.substr(index1, index2 - index1);
		    index1 = index2+1;

		    stateRow.output = row.substr(index1, row.length() - index1);

		    stateTable.push_back(stateRow);
		    break;
        }
        token = l.NextToken();
    }
	client_->haveKiss(i, o, stateTable, resetState, s, p);
}
//---------------------------------------------------------------------------
void BlifParser::command() {
    //we need to check, if the entity is already created
    if( !firstModel ) {
        //this is the first model, it's the one returned to user
        client_->haveModel(modelName);
        firstModel = true;
    }

    switch( token ) {
    case LEX_BLIF_NAMES:  names();         break;
    case LEX_BLIF_EXDC:   token = l.NextToken(); break;
    case LEX_BLIF_LATCH:  latch();         break;
    case LEX_BLIF_GATE:   gate();          break;
    case LEX_BLIF_MLATCH: mlatch();        break;
    case LEX_BLIF_SUBCKT: subckt();        break;
    case LEX_BLIF_SEARCH: search();        break;
    case LEX_BLIF_START_KISS: startkiss(); break;
    case LEX_BLIF_END_KISS: token = l.NextToken(); break;
    case LEX_BLIF_LATCH_ORDER:             break;
    case LEX_BLIF_CODE:                    break;
/*  case LEX_BLIF_CYCLE                    break;
    case LEX_BLIF_CLOCK_EVENT:             break;
    case LEX_BLIF_AREA:                    break;
    case LEX_BLIF_DELAY:                   break;
    case LEX_BLIF_WIRE_LOAD_SLOPE:         break;
    case LEX_BLIF_WIRE:                    break;
    case LEX_BLIF_INPUT_ARRIVAL:           break;
    case LEX_BLIF_DEFAULT_INPUT_ARRIVAL:   break;
    case LEX_BLIF_OUTPUT_REQUIRED:         break;
    case LEX_BLIF_DEFAULT_OUTPUT_REQUIRED: break;
    case LEX_BLIF_INPUT_DRIVE:             break;
    case LEX_BLIF_DEFAULT_INPUT_DRIVE:     break;
    case LEX_BLIF_OUTPUT_LOAD:             break;
    case LEX_BLIF_DEFAULT_OUTPUT_LOAD:     break;*/
    default: token = l.NextToken();        break;
  }
}
//---------------------------------------------------------------------------
void BlifParser::names() {
    std::list<std::string> ports;
    std::list<std::string> matrix;
    std::string data;
    std::string is;
    unsigned it = 0;

    token = l.CheckNextToken(LEX_BLIF_DATA);
    data = l.Lex_AStr;
    while (true) {
        is = "";
        while(it < data.length() && data[it] != ' ')
            is += data[it++];
        ports.push_back(is);
        if(it == data.length()) break;
        while( data[it] == ' ' ) it++;
    }
    token = l.CheckNextToken(LEX_BLIF_DATA);
    //pla matrix
    while( token == LEX_BLIF_DATA ) {
        matrix.push_back(l.Lex_AStr);
        token = l.NextToken();
    }
    client_->haveNames(ports, matrix);
}
//---------------------------------------------------------------------------
void BlifParser::latch() {
    std::cout << ".latch " << std::endl;
    token = l.CheckNextToken(LEX_BLIF_DATA);
    token = l.NextToken();
}
//---------------------------------------------------------------------------
void BlifParser::gate() {
    token = l.CheckNextToken(LEX_BLIF_DATA);
    token = l.NextToken();
}
//---------------------------------------------------------------------------
void BlifParser::mlatch() {
    token = l.CheckNextToken(LEX_BLIF_DATA);
    token = l.NextToken();
}
//---------------------------------------------------------------------------
void BlifParser::subckt() {
    std::string subcktName;
    std::string assigns;
    std::string data;
    std::string is;
    SubcktRecord* rec = new SubcktRecord;
    unsigned int it = 0;

    token = l.CheckNextToken(LEX_BLIF_DATA);
    data = l.Lex_AStr;

   while( data[it] != ' ') subcktName += data[it++];
   while( data[it] == ' ' ) it++;

   assigns = data.substr(it);
   rec->model = modelName;
   rec->subcktName = subcktName;
   rec->assigns = assigns;

   subcktRecords.push_back(rec);

   token = l.NextToken();
}
//---------------------------------------------------------------------------
void BlifParser::search() {

    std::string data;
    std::string fn;
    unsigned int it = 0;

    token = l.CheckNextToken(LEX_BLIF_DATA);
    data = l.Lex_AStr;

    while (it < data.size() && data[it] != ' ') fn += data[it++];
    client_->haveSearch (fn);
    token = l.NextToken();
}
//---------------------------------------------------------------------------
void BlifParserClient::endModel() {}
void BlifParserClient::haveModel(const std::string& modelName) {}
void BlifParserClient::haveInPorts(const std::list<std::string>& portNames) {}
void BlifParserClient::haveOutPorts(const std::list<std::string>& portNames) {}
void BlifParserClient::haveNames(std::list<std::string>& ports, std::list<std::string>& matrix) {}
void BlifParserClient::haveSubckt(std::list<SubcktRecord*>& subckt) {}
void BlifParserClient::haveKiss(int, int, std::list<hub::StateTableRow>&, std::string& resetState, int stateCount, int productCount) {}
void BlifParserClient::haveSearch (const std::string& fn) {}

//---------------------------------------------------------------------------
