// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

#include <Expression.h>
#include <DataNode.h>

//
// Enum conversion methods for Expression::ExprType
//

static const char *ExprType_strings[] = {
"Unknown", "ScalarMeshVar", "VectorMeshVar",
"TensorMeshVar", "SymmetricTensorMeshVar", "ArrayMeshVar",
"CurveMeshVar", "Mesh", "Material",
"Species"};

std::string
Expression::ExprType_ToString(Expression::ExprType t)
{
    int index = int(t);
    if(index < 0 || index >= 10) index = 0;
    return ExprType_strings[index];
}

std::string
Expression::ExprType_ToString(int t)
{
    int index = (t < 0 || t >= 10) ? 0 : t;
    return ExprType_strings[index];
}

bool
Expression::ExprType_FromString(const std::string &s, Expression::ExprType &val)
{
    val = Expression::Unknown;
    for(int i = 0; i < 10; ++i)
    {
        if(s == ExprType_strings[i])
        {
            val = (ExprType)i;
            return true;
        }
    }
    return false;
}

// ****************************************************************************
// Method: Expression::Expression
//
// Purpose:
//   Init utility for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void Expression::Init()
{
    name = "notset";
    definition = "notset";
    hidden = false;
    type = ScalarMeshVar;
    fromDB = false;
    fromOperator = false;
    operatorName = "__none__";
    dbName = "__none__";
    autoExpression = false;

    Expression::SelectAll();
}

// ****************************************************************************
// Method: Expression::Expression
//
// Purpose:
//   Copy utility for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void Expression::Copy(const Expression &obj)
{
    name = obj.name;
    definition = obj.definition;
    hidden = obj.hidden;
    type = obj.type;
    fromDB = obj.fromDB;
    fromOperator = obj.fromOperator;
    operatorName = obj.operatorName;
    meshName = obj.meshName;
    dbName = obj.dbName;
    autoExpression = obj.autoExpression;

    Expression::SelectAll();
}

// Type map format string
const char *Expression::TypeMapFormatString = EXPRESSION_TMFS;
const AttributeGroup::private_tmfs_t Expression::TmfsStruct = {EXPRESSION_TMFS};


// ****************************************************************************
// Method: Expression::Expression
//
// Purpose:
//   Default constructor for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

Expression::Expression() :
    AttributeSubject(Expression::TypeMapFormatString)
{
    Expression::Init();
}

// ****************************************************************************
// Method: Expression::Expression
//
// Purpose:
//   Constructor for the derived classes of Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

Expression::Expression(private_tmfs_t tmfs) :
    AttributeSubject(tmfs.tmfs)
{
    Expression::Init();
}

// ****************************************************************************
// Method: Expression::Expression
//
// Purpose:
//   Copy constructor for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

Expression::Expression(const Expression &obj) :
    AttributeSubject(Expression::TypeMapFormatString)
{
    Expression::Copy(obj);
}

// ****************************************************************************
// Method: Expression::Expression
//
// Purpose:
//   Copy constructor for derived classes of the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

Expression::Expression(const Expression &obj, private_tmfs_t tmfs) :
    AttributeSubject(tmfs.tmfs)
{
    Expression::Copy(obj);
}

// ****************************************************************************
// Method: Expression::~Expression
//
// Purpose:
//   Destructor for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

Expression::~Expression()
{
    // nothing here
}

// ****************************************************************************
// Method: Expression::operator =
//
// Purpose:
//   Assignment operator for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

Expression&
Expression::operator = (const Expression &obj)
{
    if (this == &obj) return *this;

    Expression::Copy(obj);

    return *this;
}

// ****************************************************************************
// Method: Expression::operator ==
//
// Purpose:
//   Comparison operator == for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
Expression::operator == (const Expression &obj) const
{
    // Create the return value
    return ((name == obj.name) &&
            (definition == obj.definition) &&
            (hidden == obj.hidden) &&
            (type == obj.type) &&
            (fromDB == obj.fromDB) &&
            (fromOperator == obj.fromOperator) &&
            (operatorName == obj.operatorName) &&
            (meshName == obj.meshName) &&
            (dbName == obj.dbName) &&
            (autoExpression == obj.autoExpression));
}

// ****************************************************************************
// Method: Expression::operator !=
//
// Purpose:
//   Comparison operator != for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
Expression::operator != (const Expression &obj) const
{
    return !(this->operator == (obj));
}

// ****************************************************************************
// Method: Expression::TypeName
//
// Purpose:
//   Type name method for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const std::string
Expression::TypeName() const
{
    return "Expression";
}

// ****************************************************************************
// Method: Expression::CopyAttributes
//
// Purpose:
//   CopyAttributes method for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
Expression::CopyAttributes(const AttributeGroup *atts)
{
    if(TypeName() != atts->TypeName())
        return false;

    // Call assignment operator.
    const Expression *tmp = (const Expression *)atts;
    *this = *tmp;

    return true;
}

// ****************************************************************************
// Method: Expression::CreateCompatible
//
// Purpose:
//   CreateCompatible method for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
Expression::CreateCompatible(const std::string &tname) const
{
    AttributeSubject *retval = 0;
    if(TypeName() == tname)
        retval = new Expression(*this);
    // Other cases could go here too.

    return retval;
}

// ****************************************************************************
// Method: Expression::NewInstance
//
// Purpose:
//   NewInstance method for the Expression class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
Expression::NewInstance(bool copy) const
{
    AttributeSubject *retval = 0;
    if(copy)
        retval = new Expression(*this);
    else
        retval = new Expression;

    return retval;
}

// ****************************************************************************
// Method: Expression::SelectAll
//
// Purpose:
//   Selects all attributes.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
Expression::SelectAll()
{
    Select(ID_name,           (void *)&name);
    Select(ID_definition,     (void *)&definition);
    Select(ID_hidden,         (void *)&hidden);
    Select(ID_type,           (void *)&type);
    Select(ID_fromDB,         (void *)&fromDB);
    Select(ID_fromOperator,   (void *)&fromOperator);
    Select(ID_operatorName,   (void *)&operatorName);
    Select(ID_meshName,       (void *)&meshName);
    Select(ID_dbName,         (void *)&dbName);
    Select(ID_autoExpression, (void *)&autoExpression);
}

///////////////////////////////////////////////////////////////////////////////
// Persistence methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: Expression::CreateNode
//
// Purpose:
//   This method creates a DataNode representation of the object so it can be saved to a config file.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
Expression::CreateNode(DataNode *parentNode, bool completeSave, bool forceAdd)
{
    if(parentNode == 0)
        return false;

    Expression defaultObject;
    bool addToParent = false;
    // Create a node for Expression.
    DataNode *node = new DataNode("Expression");

    if(completeSave || !FieldsEqual(ID_name, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("name", name));
    }

    if(completeSave || !FieldsEqual(ID_definition, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("definition", definition));
    }

    if(completeSave || !FieldsEqual(ID_hidden, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("hidden", hidden));
    }

    if(completeSave || !FieldsEqual(ID_type, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("type", ExprType_ToString(type)));
    }

    if(completeSave || !FieldsEqual(ID_fromDB, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("fromDB", fromDB));
    }

    if(completeSave || !FieldsEqual(ID_fromOperator, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("fromOperator", fromOperator));
    }

    if(completeSave || !FieldsEqual(ID_operatorName, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("operatorName", operatorName));
    }

    if(completeSave || !FieldsEqual(ID_meshName, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("meshName", meshName));
    }

    if(completeSave || !FieldsEqual(ID_dbName, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("dbName", dbName));
    }

    if(completeSave || !FieldsEqual(ID_autoExpression, &defaultObject))
    {
        addToParent = true;
        node->AddNode(new DataNode("autoExpression", autoExpression));
    }


    // Add the node to the parent node.
    if(addToParent || forceAdd)
        parentNode->AddNode(node);
    else
        delete node;

    return (addToParent || forceAdd);
}

// ****************************************************************************
// Method: Expression::SetFromNode
//
// Purpose:
//   This method sets attributes in this object from values in a DataNode representation of the object.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
Expression::SetFromNode(DataNode *parentNode)
{
    if(parentNode == 0)
        return;

    DataNode *searchNode = parentNode->GetNode("Expression");
    if(searchNode == 0)
        return;

    DataNode *node;
    if((node = searchNode->GetNode("name")) != 0)
        SetName(node->AsString());
    if((node = searchNode->GetNode("definition")) != 0)
        SetDefinition(node->AsString());
    if((node = searchNode->GetNode("hidden")) != 0)
        SetHidden(node->AsBool());
    if((node = searchNode->GetNode("type")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 10)
                SetType(ExprType(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            ExprType value;
            if(ExprType_FromString(node->AsString(), value))
                SetType(value);
        }
    }
    if((node = searchNode->GetNode("fromDB")) != 0)
        SetFromDB(node->AsBool());
    if((node = searchNode->GetNode("fromOperator")) != 0)
        SetFromOperator(node->AsBool());
    if((node = searchNode->GetNode("operatorName")) != 0)
        SetOperatorName(node->AsString());
    if((node = searchNode->GetNode("meshName")) != 0)
        SetMeshName(node->AsString());
    if((node = searchNode->GetNode("dbName")) != 0)
        SetDbName(node->AsString());
    if((node = searchNode->GetNode("autoExpression")) != 0)
        SetAutoExpression(node->AsBool());
}

///////////////////////////////////////////////////////////////////////////////
// Set property methods
///////////////////////////////////////////////////////////////////////////////

void
Expression::SetName(const std::string &name_)
{
    name = name_;
    Select(ID_name, (void *)&name);
}

void
Expression::SetDefinition(const std::string &definition_)
{
    definition = definition_;
    Select(ID_definition, (void *)&definition);
}

void
Expression::SetHidden(bool hidden_)
{
    hidden = hidden_;
    Select(ID_hidden, (void *)&hidden);
}

void
Expression::SetType(Expression::ExprType type_)
{
    type = type_;
    Select(ID_type, (void *)&type);
}

void
Expression::SetFromDB(bool fromDB_)
{
    fromDB = fromDB_;
    Select(ID_fromDB, (void *)&fromDB);
}

void
Expression::SetFromOperator(bool fromOperator_)
{
    fromOperator = fromOperator_;
    Select(ID_fromOperator, (void *)&fromOperator);
}

void
Expression::SetOperatorName(const std::string &operatorName_)
{
    operatorName = operatorName_;
    Select(ID_operatorName, (void *)&operatorName);
}

void
Expression::SetMeshName(const std::string &meshName_)
{
    meshName = meshName_;
    Select(ID_meshName, (void *)&meshName);
}

void
Expression::SetDbName(const std::string &dbName_)
{
    dbName = dbName_;
    Select(ID_dbName, (void *)&dbName);
}

void
Expression::SetAutoExpression(bool autoExpression_)
{
    autoExpression = autoExpression_;
    Select(ID_autoExpression, (void *)&autoExpression);
}

///////////////////////////////////////////////////////////////////////////////
// Get property methods
///////////////////////////////////////////////////////////////////////////////

const std::string &
Expression::GetName() const
{
    return name;
}

std::string &
Expression::GetName()
{
    return name;
}

const std::string &
Expression::GetDefinition() const
{
    return definition;
}

std::string &
Expression::GetDefinition()
{
    return definition;
}

bool
Expression::GetHidden() const
{
    return hidden;
}

Expression::ExprType
Expression::GetType() const
{
    return ExprType(type);
}

bool
Expression::GetFromDB() const
{
    return fromDB;
}

bool
Expression::GetFromOperator() const
{
    return fromOperator;
}

const std::string &
Expression::GetOperatorName() const
{
    return operatorName;
}

std::string &
Expression::GetOperatorName()
{
    return operatorName;
}

const std::string &
Expression::GetMeshName() const
{
    return meshName;
}

std::string &
Expression::GetMeshName()
{
    return meshName;
}

const std::string &
Expression::GetDbName() const
{
    return dbName;
}

std::string &
Expression::GetDbName()
{
    return dbName;
}

bool
Expression::GetAutoExpression() const
{
    return autoExpression;
}

///////////////////////////////////////////////////////////////////////////////
// Select property methods
///////////////////////////////////////////////////////////////////////////////

void
Expression::SelectName()
{
    Select(ID_name, (void *)&name);
}

void
Expression::SelectDefinition()
{
    Select(ID_definition, (void *)&definition);
}

void
Expression::SelectOperatorName()
{
    Select(ID_operatorName, (void *)&operatorName);
}

void
Expression::SelectMeshName()
{
    Select(ID_meshName, (void *)&meshName);
}

void
Expression::SelectDbName()
{
    Select(ID_dbName, (void *)&dbName);
}

///////////////////////////////////////////////////////////////////////////////
// Keyframing methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: Expression::GetFieldName
//
// Purpose:
//   This method returns the name of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

std::string
Expression::GetFieldName(int index) const
{
    switch (index)
    {
    case ID_name:           return "name";
    case ID_definition:     return "definition";
    case ID_hidden:         return "hidden";
    case ID_type:           return "type";
    case ID_fromDB:         return "fromDB";
    case ID_fromOperator:   return "fromOperator";
    case ID_operatorName:   return "operatorName";
    case ID_meshName:       return "meshName";
    case ID_dbName:         return "dbName";
    case ID_autoExpression: return "autoExpression";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: Expression::GetFieldType
//
// Purpose:
//   This method returns the type of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeGroup::FieldType
Expression::GetFieldType(int index) const
{
    switch (index)
    {
    case ID_name:           return FieldType_string;
    case ID_definition:     return FieldType_string;
    case ID_hidden:         return FieldType_bool;
    case ID_type:           return FieldType_enum;
    case ID_fromDB:         return FieldType_bool;
    case ID_fromOperator:   return FieldType_bool;
    case ID_operatorName:   return FieldType_string;
    case ID_meshName:       return FieldType_string;
    case ID_dbName:         return FieldType_string;
    case ID_autoExpression: return FieldType_bool;
    default:  return FieldType_unknown;
    }
}

// ****************************************************************************
// Method: Expression::GetFieldTypeName
//
// Purpose:
//   This method returns the name of a field type given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

std::string
Expression::GetFieldTypeName(int index) const
{
    switch (index)
    {
    case ID_name:           return "string";
    case ID_definition:     return "string";
    case ID_hidden:         return "bool";
    case ID_type:           return "enum";
    case ID_fromDB:         return "bool";
    case ID_fromOperator:   return "bool";
    case ID_operatorName:   return "string";
    case ID_meshName:       return "string";
    case ID_dbName:         return "string";
    case ID_autoExpression: return "bool";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: Expression::FieldsEqual
//
// Purpose:
//   This method compares two fields and return true if they are equal.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
Expression::FieldsEqual(int index_, const AttributeGroup *rhs) const
{
    const Expression &obj = *((const Expression*)rhs);
    bool retval = false;
    switch (index_)
    {
    case ID_name:
        {  // new scope
        retval = (name == obj.name);
        }
        break;
    case ID_definition:
        {  // new scope
        retval = (definition == obj.definition);
        }
        break;
    case ID_hidden:
        {  // new scope
        retval = (hidden == obj.hidden);
        }
        break;
    case ID_type:
        {  // new scope
        retval = (type == obj.type);
        }
        break;
    case ID_fromDB:
        {  // new scope
        retval = (fromDB == obj.fromDB);
        }
        break;
    case ID_fromOperator:
        {  // new scope
        retval = (fromOperator == obj.fromOperator);
        }
        break;
    case ID_operatorName:
        {  // new scope
        retval = (operatorName == obj.operatorName);
        }
        break;
    case ID_meshName:
        {  // new scope
        retval = (meshName == obj.meshName);
        }
        break;
    case ID_dbName:
        {  // new scope
        retval = (dbName == obj.dbName);
        }
        break;
    case ID_autoExpression:
        {  // new scope
        retval = (autoExpression == obj.autoExpression);
        }
        break;
    default: retval = false;
    }

    return retval;
}

///////////////////////////////////////////////////////////////////////////////
// User-defined methods.
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
//  Method:  Expression::GetNumTypes
//
//  Programmer:  ?
//  Creation:    ?
//
//  Modifications:
//    Jeremy Meredith, Sun Oct 10 22:58:21 PDT 2004
//    Changed it to 8 to reflect the current number of actual expressions.
//
//    Hank Childs, Tue Jul 19 13:25:53 PDT 2005
//    Changed it to 9 for Array expressions.
//
//    Kathlen Bonnell, Tue Aug  1 08:26:14 PDT 2006
//    Changed it to 10 for Curve expressions.
//
//    Tom Fogal, Tue Jun 23 20:57:07 MDT 2009
//    Const is ignored on by-value return types.
//
// ****************************************************************************
int
Expression::GetNumTypes()
{
    return 10;
}

// ****************************************************************************
//  Method:  Expression::GetTypeString
//
//  Programmer:  ?
//  Creation:    ?
//
//  Modifications:
//    Kathlen Bonnell, Tue Aug  1 08:26:14 PDT 2006
//    Added CurveMeshVar.
//
//    Kathleen Biagas, Thu Jun  6 16:14:45 PDT 2019
//    Change returned strings to match case-changes in QvisExpressionWindow,
//    the only other place this method is used.
//
// ****************************************************************************

const char *
Expression::GetTypeString(const Expression::ExprType t)
{
    switch(t)
    {
    case ScalarMeshVar:
        return "Scalar mesh variable";
    case VectorMeshVar:
        return "Vector mesh variable";
    case TensorMeshVar:
        return "Tensor mesh variable";
    case SymmetricTensorMeshVar:
        return "Symmetric tensor mesh variable";
    case ArrayMeshVar:
        return "Array mesh variable";
    case CurveMeshVar:
        return "Curve mesh variable";
    case Mesh:
        return "Mesh";
    case Material:
        return "Material";
    case Species:
        return "Species";
    default:
        return "Unknown Type";
    }
}

// ****************************************************************************
//  Method:  Expression::GetTypeId
//
//  Programmer:  ?
//  Creation:    ?
//
//  Modifications:
//    Kathlen Bonnell, Tue Aug  1 08:26:14 PDT 2006
//    Added CurveMeshVar.
//
//    Tom Fogal, Tue Jun 23 20:58:01 MDT 2009
//    Const is ignored on by-value return types.
//
// ****************************************************************************

Expression::ExprType
Expression::GetTypeId(const std::string s)
{
    if (s == "Scalar Mesh Variable")
        return ScalarMeshVar;
    else if (s == "Vector Mesh Variable")
        return VectorMeshVar;
    else if (s == "Tensor Mesh Variable")
        return TensorMeshVar;
    else if (s == "Symmetric Tensor Mesh Variable")
        return SymmetricTensorMeshVar;
    else if (s == "Array Mesh Variable")
        return ArrayMeshVar;
    else if (s == "Curve Mesh Variable")
        return CurveMeshVar;
    else if (s == "Mesh")
        return Mesh;
    else if (s == "Material")
        return Material;
    else if (s == "Species")
        return Species;
    else
        return Unknown;
}

