#include "context/VariableDefinition.h"
#include "datatable/TableFormat.h"
#include "datatable/DataTable.h"
#include "security/Permissions.h"

VariableDefinition::VariableDefinition()
    : AbstractEntityDefinition()
{
    localCachingEnabled = true;
    persistent = true;
    hidden = false;
    allowUpdateEvents = false;
    readable = false;
    writable = false;
    hidden = false;
    allowUpdateEvents = false;
}

VariableDefinition::VariableDefinition(const AgString & name, TableFormatPtr format, bool readable, bool writable)
{
    init(name,format,readable,writable,AgString());
}

VariableDefinition::VariableDefinition(const AgString & name, TableFormatPtr format, bool readable, bool writable, const AgString & description)
{
    init(name,format,readable,writable,description);
}

VariableDefinition::VariableDefinition(const AgString & name, TableFormatPtr format, bool readable, bool writable, const AgString & description, const AgString & group)
{
    init(name,format,readable,writable,description);
    setGroup(group);
}

void VariableDefinition::init(const AgString & name, TableFormatPtr format, bool readable, bool writable, const AgString & description)
{
    localCachingEnabled = true;
    persistent = true;
    hidden = false;
    allowUpdateEvents = false;


    setName(name);
    setFormat(format);
    this->readable = readable;
    this->writable = writable;
    setDescription(description.length() > 0 ? description : name);
}

void VariableDefinition::setFormat(TableFormatPtr format)
{
    if (format.get() != NULL)
    {
        format->makeImmutable(NULL);
    }
    this->format = format;
}

void VariableDefinition::setReadable(bool readable)
{
    this->readable = readable;
}

void VariableDefinition::setWritable(bool writable)
{
    this->writable = writable;
}

void VariableDefinition::setHidden(bool hidden)
{
    this->hidden = hidden;
}

void VariableDefinition::setGroup(const AgString & group)
{
    AbstractEntityDefinition::setGroup(group);
    if(group.length() > 0) {
        allowUpdateEvents = true;
    }
}

void VariableDefinition::setReadPermissions(PermissionsPtr readPermissions)
{
    this->readPermissions = readPermissions;
}

void VariableDefinition::setWritePermissions(PermissionsPtr writePermissions)
{
    this->writePermissions = writePermissions;
}

void VariableDefinition::setSetter(VariableSetterPtr setter)
{
    this->setter = setter;
}

void VariableDefinition::setGetter(VariableGetterPtr getter)
{
    this->getter = getter;
}

TableFormatPtr VariableDefinition::getFormat()
{
    return format;
}

bool VariableDefinition::isReadable()
{
    return readable;
}

bool VariableDefinition::isWritable()
{
    return writable;
}

bool VariableDefinition::isHidden()
{
    return hidden;
}

PermissionsPtr VariableDefinition::getReadPermissions()
{
    return readPermissions;
}

PermissionsPtr VariableDefinition::getWritePermissions()
{
    return writePermissions;
}

VariableSetterPtr VariableDefinition::getSetter()
{
    return setter;
}

VariableGetterPtr VariableDefinition::getGetter()
{
    return getter;
}

AgString VariableDefinition::getHelpId()
{
    return helpId;
}

void VariableDefinition::setHelpId(const AgString & helpId)
{
    this->helpId = helpId;
}

std::string VariableDefinition::getValueClass()
{
    return valueClass;
}

void VariableDefinition::setValueClass(const std::string& valueClass)
{
    this->valueClass = valueClass;
}

boost::posix_time::time_duration VariableDefinition::getChangeEventsExpirationPeriod()
{
    return changeEventsExpirationPeriod;
}

void VariableDefinition::setChangeEventsExpirationPeriod(boost::posix_time::time_duration changeEventsExpirationPeriod)
{
    this->changeEventsExpirationPeriod = changeEventsExpirationPeriod;
}

bool VariableDefinition::isLocalCachingEnabled()
{
    return localCachingEnabled;
}

void VariableDefinition::setLocalCachingEnabled(bool valueCachingEnabled)
{
    this->localCachingEnabled = valueCachingEnabled;
}

boost::posix_time::time_duration VariableDefinition::getRemoteCacheTime()
{
    return remoteCacheTime;
}

void VariableDefinition::setRemoteCacheTime(boost::posix_time::time_duration  remoteCacheTime)
{
    this->remoteCacheTime = remoteCacheTime;
}

DataTablePtr VariableDefinition::getDefaultValue()
{
    return defaultValue;
}

void VariableDefinition::setDefaultValue(DataTablePtr defaultValue)
{
    this->defaultValue = defaultValue;
}

bool VariableDefinition::isPersistent()
{
    return persistent;
}

void VariableDefinition::setPersistent(bool persistent)
{
    this->persistent = persistent;
}

bool VariableDefinition::isAllowUpdateEvents()
{
    return allowUpdateEvents;
}

void VariableDefinition::setAllowUpdateEvents(bool allowUpdateEvents)
{
    this->allowUpdateEvents = allowUpdateEvents;
}

void VariableDefinition::addCompatibilityConverter(CompatibilityConverterPtr converter)
{
    compatibilityConverters.push_back(converter);
}

std::list< CompatibilityConverterPtr > VariableDefinition::getCompatibilityConverters()
{
    return compatibilityConverters;
}

VariableDefinition* VariableDefinition::clone()
{
    VariableDefinition *v = new VariableDefinition();
    v->name = name;
    v->description = description;
    v->help = help;
    v->group = group;
    v->index = index;
    v->iconId = iconId;
    v->owner = owner;

    v->format = format;
    v->readable = readable;
    v->writable = writable;
    v->hidden = hidden;

    v->readPermissions = readPermissions;
    v->writePermissions = writePermissions;
    v->helpId = helpId;

    v->getter = getter;
    v->setter = setter;
    v->allowUpdateEvents = allowUpdateEvents;
    v->changeEventsExpirationPeriod = changeEventsExpirationPeriod;
    v->localCachingEnabled = localCachingEnabled;
    v->remoteCacheTime = remoteCacheTime;
    v->valueClass = valueClass;
    v->compatibilityConverters = compatibilityConverters;
    v->persistent = persistent;
    v->defaultValue = defaultValue;
    return v;
}

int VariableDefinition::hashCode()
{
    //int const prime = int(31);
    int result = int(1);
    assert(0);

//    result = prime * result + ((getDescription() == 0) ? int(0) : getDescription())->hashCode());
//    result = prime * result + ((format == 0) ? int(0) : format)->hashCode());
//    result = prime * result + ((getGroup() == 0) ? int(0) : getGroup())->hashCode());
//    result = prime * result + ((getHelp() == 0) ? int(0) : getHelp())->hashCode());
//    result = prime * result + (hidden ? int(1231) : int(1237));
//    result = prime * result + ((getIconId() == 0) ? int(0) : getIconId())->hashCode());
//    result = prime * result + ((helpId == 0) ? int(0) : helpId)->hashCode());
//    result = prime * result + ((getIndex() == 0) ? int(0) : getIndex())->hashCode());
//    result = prime * result + ((getName() == 0) ? int(0) : getName())->hashCode());
//    result = prime * result + (readable ? int(1231) : int(1237));
//    result = prime * result + (writable ? int(1231) : int(1237));
//    result = prime * result + ((changeEventsExpirationPeriod == 0) ? int(0) : changeEventsExpirationPeriod)->hashCode());
//    result = prime * result + ((readPermissions == 0) ? int(0) : readPermissions)->hashCode());
//    result = prime * result + ((writePermissions == 0) ? int(0) : writePermissions)->hashCode());
//    result = prime * result + (persistent ? int(1231) : int(1237));
    return result;
}

bool VariableDefinition::equals(VariableDefinition *other)
{
    if(this == other) {
        return true;
    }

    if(other == 0) {
        return false;
    }

    if (getDescription() == other->getDescription()) {
        return false;
    }

    if(format == 0) {
        if(other->format != 0) {
            return false;
        }
    } else if(format->equals(other->format.get())) {
        return false;
    }

    if (getGroup() != other->getGroup()) {
        return false;
    }

    if (getHelp() != other->getHelp()) {
        return false;
    }

    if(hidden != other->hidden) {
        return false;
    }

    if (getIconId() != other->getIconId()) {
        return false;
    }

    if(helpId != other->helpId) {
        return false;
    }

    if(getIndex() != other->getIndex()) {
        return false;
    }

    if (getName() != other->getName()) {
        return false;
    }

    if (changeEventsExpirationPeriod != other->changeEventsExpirationPeriod) {
        return false;
    }

    if (readable != other->readable) {
        return false;
    }

    if (writable != other->writable) {
        return false;
    }

    if (readPermissions == 0) {
        if(other->readPermissions != 0) {
            return false;
        }
    }else if(!readPermissions->equals(other->readPermissions.get())) {
        return false;
    }
    if (writePermissions == 0) {
        if(other->writePermissions != 0) {
            return false;
        }
    } else if(!writePermissions->equals(other->writePermissions.get())) {
        return false;
    }

    if (persistent != other->persistent) {
        return false;
    }
    return true;
}

int VariableDefinition::compareTo(Comparable *d)
{
    //TODO:
    assert(0);
    if (d != NULL)
    {
        VariableDefinition* vd = static_cast<VariableDefinition*>(d);
        return (getIndex() == vd->getIndex()) ? 1 : 0;
    }

    return 0;
}


