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

#include "assignment.h"
#include "state.h"
#include "variable.h"

#include "common/helper.h"
#include "common/message.h"

#include <cassert>
#include <inttypes.h>
#include <ostream>

using namespace std;

varset_t IntAssignment::writeVars() const {
    return lhs;
}

////////////////////////////////////////////////////////////////////

VarAssignment::VarAssignment(Integer* lhs, Integer* rhs, int32_t id) : 
    IntAssignment(lhs, id),
    rhs(rhs)
{
    assert(lhs && rhs);
}

varset_t VarAssignment::readVars() const {
    return rhs;
}

bool VarAssignment::operator==(const VarAssignment& v) const { 
    return lhs->id == v.lhs->id && rhs->id == v.rhs->id; 
}

bool VarAssignment::operator==(const ValueAssignment&) const { 
    return false; 
}

void VarAssignment::apply(State* state) const {
    /// @todo check if the assigned value is in lhs's domain
    state->var(lhs->id) = state->var(rhs->id);
}

ostream& VarAssignment::display(ostream& o) const {
    return o << lhs->name << " := " << rhs->name; 
}

////////////////////////////////////////////////////////////////////

ValueAssignment::ValueAssignment(Integer* lhs, int32_t rhs, int32_t id) :
    IntAssignment(lhs, id),
    rhs(rhs)
{
    init();
}

ValueAssignment::ValueAssignment(Integer* lhs, const Constant* rhs, int32_t id) :
    IntAssignment(lhs, id),
    rhs(rhs->value)
{
    init();
}

void ValueAssignment::init() const {
    assert(lhs);
    if (rhs > lhs->upper || rhs < lhs->lower) {
	error() << rhs << " is outside " << lhs->name << "'s domain" << endl;
    }
}

bool ValueAssignment::operator==(const VarAssignment&) const { 
    return false; 
}

bool ValueAssignment::operator==(const ValueAssignment& v) const { 
    return lhs->id == v.lhs->id && rhs == v.rhs; 
}

void ValueAssignment::apply(State* state) const {
    state->var(lhs->id) = rhs;
}

ostream& ValueAssignment::display(ostream& o) const {
    return o << lhs->name << " := " << rhs; 
}

////////////////////////////////////////////////////////////////////

ClockReset::ClockReset(Clock* lhs, int32_t rhs, int32_t id) :
    Assignment(id),
    lhs(lhs),
    rhs(rhs)
{
    assert(lhs && rhs == 0);
}

varset_t ClockReset::writeVars() const {
    return lhs;
}

ClockReset::ClockReset(Clock* lhs, const Constant* rhs, int32_t id) :
    Assignment(id),
    lhs(lhs),
    rhs(rhs->value)
{
    assert(lhs && rhs == 0);
}

bool ClockReset::operator==(const ClockReset& cr) const {
    return lhs->id == cr.lhs->id;
}

void ClockReset::apply(State* state) const {
    state->zone()(lhs->id) = 0;
}

ostream& ClockReset::display(ostream& o) const {
    return o << lhs->name << " := " << rhs; 
}

////////////////////////////////////////////////////////////////////

ClockReset* AssignmentFactory::create(Clock* lhs, int32_t rhs) {
    assert(rhs == 0);
    return clocks.insert(new ClockReset(lhs, 0, clocks.size())).first;
}

ClockReset* AssignmentFactory::create(Clock* lhs, const Constant* rhs) {
    return create(lhs, rhs->value);
}

IntAssignment* AssignmentFactory::create(Integer* lhs, int32_t rhs) {
    return ints.insert(new ValueAssignment(lhs, rhs, ints.size())).first;
}

IntAssignment* AssignmentFactory::create(Integer* lhs, const Constant* rhs) {
    return create(lhs, rhs->value);
}

IntAssignment* AssignmentFactory::create(Integer* lhs, Integer* rhs) {  
    return ints.insert(new VarAssignment(lhs, rhs, ints.size())).first;
}




