#include "functionInst.h"
#include "functionUser.h"
#include "graph.h"
#include "tools.h"

#include <iostream>
using namespace std;

// ------
// Class functionInst
// ------

functionInst::functionInst(operation *op_){
	op = op_;
	if(op){
		op->fun = this;
	}
}

functionInst::~functionInst(){
	if(op){
		op->fun = 0;
		// We do not destroy op
	}
}

void functionInst::SetOp(operation *op_){
	op = op_;
	if(op){
		op->fun = this;
	}
}

// ------
// Class functionUserInst
// ------

functionUserInst::functionUserInst(functionUser *fun_, operation *op, bool copyRegisters) :
	functionInst(op){

	fun = fun_;

	// We copy all registers
	if(copyRegisters){
        for(vector<registerV *>::iterator it = fun->registers.begin() ; it != fun->registers.end() ; it++){
            registers.push_back(new registerV(**it));
        }
	}
}

functionUserInst::~functionUserInst(){
	// These registers are only copy of registers of functionUser
	// We do not need them...
	VectorDeleteAll<registerV>(registers);
}

bool functionUserInst::VerifyNumberOfInputs(){
	return (op && fun->GetNumberOfInputs()==op->GetNumberOfInputs());
}

bool functionUserInst::VerifyNumberOfOutputs(){
	return (op && fun->GetNumberOfOutputs()==op->GetNumberOfOutputs());
}

void functionUserInst::Eval(){
	vector<variable *>::iterator it1,it2;

	// Copy inputs to inputs
	it1 = fun->inputs.begin();
	it2 = op->inputs.begin();
	for( ; it1!=fun->inputs.end() && it2!=op->inputs.end() ; it1++, it2++){
		(*it1)->SetValue((*it2)->GetValue());
	}

	NextClockEdge();

	fun->Eval();

	SaveRegisters();

	// Copy outputs to outputs
	it1 = op->outputs.begin();
	it2 = fun->outputs.begin();
	for( ; it1!=op->outputs.end() && it2!=fun->outputs.end() ; it1++, it2++){
		(*it1)->SetValue((*it2)->GetValue());
	}
}

// C program

void functionUserInst::CPutDeclarations(ostream &f, const string newPrefix){
	fun->CPutDeclarations(f,newPrefix);
}

void functionUserInst::CPutCommands(ostream &f, const string prefix, const string newPrefix){
	vector<variable *>::iterator it1,it2;

	// Copy inputs to inputs
	it1 = fun->inputs.begin();
	it2 = op->inputs.begin();
	for( ; it1!=fun->inputs.end() && it2!=op->inputs.end() ; it1++, it2++){
		f << "\t\t" << newPrefix << "_" << (*it1)->id << "=" << prefix << "_" << (*it2)->id << ";" << endl;
	}

	fun->CPutCommands(f,newPrefix);

	// Copy outputs to outputs
	it1 = op->outputs.begin();
	it2 = fun->outputs.begin();
	for( ; it1!=op->outputs.end() && it2!=fun->outputs.end() ; it1++, it2++){
		f << "\t\t" << prefix << "_" << (*it1)->id << "=" << newPrefix << "_" << (*it2)->id << ";" << endl;
	}
}

void functionUserInst::CPutRegistersSave(ostream &f, const string newPrefix){
	for(vector<registerV *>::iterator it=registers.begin() ; it!=registers.end() ; it++){
		f << "\t\t" << newPrefix << "_" << (*it)->input->id << "r=" << newPrefix << "_" << (*it)->input->id  << ";" << endl;
	}
}

void functionUserInst::CPutRegistersNext(ostream &f, const string newPrefix){
	for(vector<registerV *>::iterator it=registers.begin() ; it!=registers.end() ; it++){
		f << "\t\t" << newPrefix << "_" << (*it)->output->id << "=" << newPrefix << "_" << (*it)->input->id  << "r;" << endl;
	}
}

// Protected functions (private use only)

void functionUserInst::SaveRegisters(){
	for(vector<registerV *>::iterator it=registers.begin() ; it!=registers.end() ; it++){
		(*it)->SaveRegister();
	}
}

void functionUserInst::NextClockEdge(){
	for(vector<registerV *>::iterator it=registers.begin() ; it!=registers.end() ; it++){
		(*it)->NextClockEdge();
	}
}

// ------
// Other class
// ------

void functionAnd::Eval(){
	op->outputs[0]->SetValue(op->inputs[0]->GetValue() & op->inputs[1]->GetValue() );
}

void functionAnd::CPutCommands(ostream &f, const string prefix, const string newPrefix){
	f << "\t\t" << prefix << "_" << op->outputs[0]->id << "=" << prefix << "_" << op->inputs[0]->id << " & " << prefix << "_" << op->inputs[1]->id << ";" << endl;
}

void functionOr::Eval(){
	op->outputs[0]->SetValue(op->inputs[0]->GetValue()  | op->inputs[1]->GetValue() );
}

void functionOr::CPutCommands(ostream &f, const string prefix, const string newPrefix){
	f << "\t\t" << prefix << "_" << op->outputs[0]->id << "=" << prefix << "_" << op->inputs[0]->id << " | " << prefix << "_" << op->inputs[1]->id << ";" << endl;
}

void functionXor::Eval(){
	op->outputs[0]->SetValue(op->inputs[0]->GetValue()  ^ op->inputs[1]->GetValue() );
}

void functionXor::CPutCommands(ostream &f, const string prefix, const string newPrefix){
	f << "\t\t" << prefix << "_" << op->outputs[0]->id << "=" << prefix << "_" << op->inputs[0]->id << " ^ " << prefix << "_" << op->inputs[1]->id << ";" << endl;
}

void functionNot::Eval(){
	op->outputs[0]->SetValue(! op->inputs[0]->GetValue() );
}

void functionNot::CPutCommands(ostream &f, const string prefix, const string newPrefix){
	f << "\t\t" << prefix << "_" << op->outputs[0]->id << "= ~" << prefix << "_" << op->inputs[0]->id << ";" << endl;
}

void functionEqual::Eval(){
	op->outputs[0]->SetValue(op->inputs[0]->GetValue() );
}

void functionEqual::CPutCommands(ostream &f, const string prefix, const string newPrefix){
	f << "\t\t" << prefix << "_" << op->outputs[0]->id << "=" << prefix << "_" << op->inputs[0]->id << ";" << endl;
}
