// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: system.cpp 816 2011-09-10 13:19:07Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#include "assignment.h"
#include "constraint.h"
#include "location.h"
#include "process.h"
#include "resolver.h"
#include "state.h"
#include "system.h"
#include "variable.h"

#include <boost/foreach.hpp>
#include <cassert>
#include <ostream>
#define foreach BOOST_FOREACH

using namespace std;

System::System() : 
    Component("SYSTEM", NULL), 
    resolver(new NameResolver),
    builder(NULL) 
{}

void System::prepare() {
    builder = new StateBuilder(this);
}

uint32_t System::getTotalNrClocks() const {
    uint32_t res = clocks.size();
    foreach (const Process* proc, procs) {
	res += proc->clocks.size();
    }
    return res;
}

uint32_t System::getTotalNrChannels() const {
    uint32_t res = getNrChannels();
    foreach (const Process* proc, procs) {
	res += proc->channels.size();
    }
    return res;
}

uint32_t System::getTotalNrIntegers() const {
    uint32_t res = ints.size();
    foreach (const Process* proc, procs) {
	res += proc->ints.size();
    }
    return res;
}

uint32_t System::getTotalNrLocations() const {
    uint32_t res = 0;
    foreach (const Process* proc, procs) {
	res += proc->locs.size();
    }
    return res;
}

uint32_t System::getTotalNrEdges() const {
    uint32_t res = 0;
    foreach (const Process* proc, procs) {
	res += proc->edges.size();
    }
    return res;
}

uint32_t System::getTotalNrIntAssignments() const {
    return AssignmentFactory::getFactory().totalNrIntAssignments();
}

uint32_t System::getTotalNrIntConstraints() const {
    return ConstraintFactory::getFactory().totalNrIntConstraints();
}

uint32_t System::getNrChannels() const {
    uint32_t res = channels.size();
    foreach (const Process* proc, procs) {
	res += proc->channels.size();
    }
    return res;
}

const Integer* System::getInteger(int32_t id) const {
    if (id < ints.size()) {
	return ints[id];
    } else {
	foreach (const Process* proc, procs) {
	    id -= proc->ints.size();
	    assert(id >= 0);
	    if (id < proc->ints.size()) {
		return proc->ints[id];
	    }
	}
    }
    assert(false);
    return NULL;
}

Variable* System::find(const Component* comp, const std::string& name) const {
    return resolver->find(comp, name);
}

const Component* System::getComponent(const string& procname) const {
    foreach (const Process* proc, procs) {
	assert(proc);
	if (proc->name == procname) {
	    return proc;
	}  
    }
    return NULL;
}

bool System::isCommitted(const State* state) const {
    foreach (const Process* proc, procs) {
	if (proc->locs[state->proc(proc->id)]->commit) {
	    return true;
	}
    }
    return false;
}

State* System::createInitial() const {
    State* initial = builder->newState();
    int32_t depth = builder->getField("depth");
    if (depth != -1) {
	initial->extra(depth) = 0;
    }
    int32_t interference_level = builder->getField("interference level");
    if (interference_level != -1) {
	initial->extra(interference_level) = -1;
    }
    
    // init locations
    foreach (const Process* proc, procs) {
	initial->proc(proc->id) = proc->init->idInProcess;	
    }    
    // init variables
    foreach (const Integer* v, ints) {
	initial->var(v->id) = v->initial;
    }
    foreach (const Process* proc, procs) {
	foreach (const Integer* v, proc->ints) {
	    initial->var(v->id) = v->initial;
	}
    }
    return initial;
}

ostream& System::display(ostream& o) const {
    Component::display(o);
    o << endl;
    foreach (const Process* p, procs) {
	o << *p << endl;
    }
    if (!procs.empty()) {
	o << "system ";
	foreach (const Process* p, procs) {
	    o << p->name;
	    if (p == procs.back()) {
		o << ";" << endl; 
	    } else {
		o << ", ";
	    }
	}
    }
    
    return o;
}

