// 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 <avtSpeciesMetaData.h>
#include <DataNode.h>
#include <avtMatSpeciesMetaData.h>

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

void avtSpeciesMetaData::Init()
{
    name = "Species";
    originalName = "Species";
    validVariable = true;
    meshName = "mesh";
    materialName = "material";
    numMaterials = 0;

    avtSpeciesMetaData::SelectAll();
}

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

void avtSpeciesMetaData::Copy(const avtSpeciesMetaData &obj)
{
    AttributeGroupVector::const_iterator pos;

    name = obj.name;
    originalName = obj.originalName;
    validVariable = obj.validVariable;
    meshName = obj.meshName;
    materialName = obj.materialName;
    numMaterials = obj.numMaterials;
    // *** Copy the species field ***
    // Delete the AttributeGroup objects and clear the vector.
    for(pos = species.begin(); pos != species.end(); ++pos)
        delete *pos;
    species.clear();
    if(obj.species.size() > 0)
        species.reserve(obj.species.size());
    // Duplicate the species from obj.
    for(pos = obj.species.begin(); pos != obj.species.end(); ++pos)
    {
        avtMatSpeciesMetaData *oldavtMatSpeciesMetaData = (avtMatSpeciesMetaData *)(*pos);
        avtMatSpeciesMetaData *newavtMatSpeciesMetaData = new avtMatSpeciesMetaData(*oldavtMatSpeciesMetaData);
        species.push_back(newavtMatSpeciesMetaData);
    }


    avtSpeciesMetaData::SelectAll();
}

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


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

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

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

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

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

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

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

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

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

avtSpeciesMetaData::~avtSpeciesMetaData()
{
    AttributeGroupVector::iterator pos;

    // Destroy the species field.
    for(pos = species.begin(); pos != species.end(); ++pos)
        delete *pos;
}

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

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

    avtSpeciesMetaData::Copy(obj);

    return *this;
}

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

bool
avtSpeciesMetaData::operator == (const avtSpeciesMetaData &obj) const
{
    bool species_equal = (obj.species.size() == species.size());
    for(size_t i = 0; (i < species.size()) && species_equal; ++i)
    {
        // Make references to avtMatSpeciesMetaData from AttributeGroup *.
        const avtMatSpeciesMetaData &species1 = *((const avtMatSpeciesMetaData *)(species[i]));
        const avtMatSpeciesMetaData &species2 = *((const avtMatSpeciesMetaData *)(obj.species[i]));
        species_equal = (species1 == species2);
    }

    // Create the return value
    return ((name == obj.name) &&
            (originalName == obj.originalName) &&
            (validVariable == obj.validVariable) &&
            (meshName == obj.meshName) &&
            (materialName == obj.materialName) &&
            (numMaterials == obj.numMaterials) &&
            species_equal);
}

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

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

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

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

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

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

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

    return true;
}

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

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

    return retval;
}

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

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

    return retval;
}

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

void
avtSpeciesMetaData::SelectAll()
{
    Select(ID_name,          (void *)&name);
    Select(ID_originalName,  (void *)&originalName);
    Select(ID_validVariable, (void *)&validVariable);
    Select(ID_meshName,      (void *)&meshName);
    Select(ID_materialName,  (void *)&materialName);
    Select(ID_numMaterials,  (void *)&numMaterials);
    Select(ID_species,       (void *)&species);
}

// ****************************************************************************
// Method: avtSpeciesMetaData::CreateSubAttributeGroup
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeGroup *
avtSpeciesMetaData::CreateSubAttributeGroup(int)
{
    return new avtMatSpeciesMetaData;
}

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

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

const AttributeGroupVector &
avtSpeciesMetaData::GetSpecies() const
{
    return species;
}

AttributeGroupVector &
avtSpeciesMetaData::GetSpecies()
{
    return species;
}

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

void
avtSpeciesMetaData::SelectSpecies()
{
    Select(ID_species, (void *)&species);
}

///////////////////////////////////////////////////////////////////////////////
// AttributeGroupVector convenience methods.
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: avtSpeciesMetaData::AddSpecies
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
avtSpeciesMetaData::AddSpecies(const avtMatSpeciesMetaData &obj)
{
    avtMatSpeciesMetaData *newavtMatSpeciesMetaData = new avtMatSpeciesMetaData(obj);
    species.push_back(newavtMatSpeciesMetaData);

    // Indicate that things have changed by selecting it.
    Select(ID_species, (void *)&species);
}

// ****************************************************************************
// Method: avtSpeciesMetaData::ClearSpecies
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
avtSpeciesMetaData::ClearSpecies()
{
    AttributeGroupVector::iterator pos;

    for(pos = species.begin(); pos != species.end(); ++pos)
        delete *pos;
    species.clear();

    // Indicate that things have changed by selecting the list.
    Select(ID_species, (void *)&species);
}

// ****************************************************************************
// Method: avtSpeciesMetaData::RemoveSpecies
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
avtSpeciesMetaData::RemoveSpecies(int index)
{
    AttributeGroupVector::iterator pos = species.begin();

    // Iterate through the vector "index" times.
    for(int i = 0; i < index; ++i)
        if(pos != species.end()) ++pos;

    // If pos is still a valid iterator, remove that element.
    if(pos != species.end())
    {
        delete *pos;
        species.erase(pos);
    }

    // Indicate that things have changed by selecting the list.
    Select(ID_species, (void *)&species);
}

// ****************************************************************************
// Method: avtSpeciesMetaData::GetNumSpecies
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

int
avtSpeciesMetaData::GetNumSpecies() const
{
    return (int)species.size();
}

// ****************************************************************************
// Method: avtSpeciesMetaData::GetSpecies
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

avtMatSpeciesMetaData &
avtSpeciesMetaData::GetSpecies(int i)
{
    return *((avtMatSpeciesMetaData *)species[i]);
}

// ****************************************************************************
// Method: avtSpeciesMetaData::GetSpecies
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const avtMatSpeciesMetaData &
avtSpeciesMetaData::GetSpecies(int i) const
{
    return *((avtMatSpeciesMetaData *)species[i]);
}

// ****************************************************************************
// Method: avtSpeciesMetaData::operator []
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

avtMatSpeciesMetaData &
avtSpeciesMetaData::operator [] (int i)
{
    return *((avtMatSpeciesMetaData *)species[i]);
}

// ****************************************************************************
// Method: avtSpeciesMetaData::operator []
//
// Purpose:
//   Contains species metadata attributes
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const avtMatSpeciesMetaData &
avtSpeciesMetaData::operator [] (int i) const
{
    return *((avtMatSpeciesMetaData *)species[i]);
}

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

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

std::string
avtSpeciesMetaData::GetFieldName(int index) const
{
    switch (index)
    {
    case ID_name:          return "name";
    case ID_originalName:  return "originalName";
    case ID_validVariable: return "validVariable";
    case ID_meshName:      return "meshName";
    case ID_materialName:  return "materialName";
    case ID_numMaterials:  return "numMaterials";
    case ID_species:       return "species";
    default:  return "invalid index";
    }
}

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

AttributeGroup::FieldType
avtSpeciesMetaData::GetFieldType(int index) const
{
    switch (index)
    {
    case ID_name:          return FieldType_string;
    case ID_originalName:  return FieldType_string;
    case ID_validVariable: return FieldType_bool;
    case ID_meshName:      return FieldType_string;
    case ID_materialName:  return FieldType_string;
    case ID_numMaterials:  return FieldType_int;
    case ID_species:       return FieldType_attVector;
    default:  return FieldType_unknown;
    }
}

// ****************************************************************************
// Method: avtSpeciesMetaData::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
avtSpeciesMetaData::GetFieldTypeName(int index) const
{
    switch (index)
    {
    case ID_name:          return "string";
    case ID_originalName:  return "string";
    case ID_validVariable: return "bool";
    case ID_meshName:      return "string";
    case ID_materialName:  return "string";
    case ID_numMaterials:  return "int";
    case ID_species:       return "attVector";
    default:  return "invalid index";
    }
}

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

bool
avtSpeciesMetaData::FieldsEqual(int index_, const AttributeGroup *rhs) const
{
    const avtSpeciesMetaData &obj = *((const avtSpeciesMetaData*)rhs);
    bool retval = false;
    switch (index_)
    {
    case ID_name:
        {  // new scope
        retval = (name == obj.name);
        }
        break;
    case ID_originalName:
        {  // new scope
        retval = (originalName == obj.originalName);
        }
        break;
    case ID_validVariable:
        {  // new scope
        retval = (validVariable == obj.validVariable);
        }
        break;
    case ID_meshName:
        {  // new scope
        retval = (meshName == obj.meshName);
        }
        break;
    case ID_materialName:
        {  // new scope
        retval = (materialName == obj.materialName);
        }
        break;
    case ID_numMaterials:
        {  // new scope
        retval = (numMaterials == obj.numMaterials);
        }
        break;
    case ID_species:
        {  // new scope
        bool species_equal = (obj.species.size() == species.size());
        for(size_t i = 0; (i < species.size()) && species_equal; ++i)
        {
            // Make references to avtMatSpeciesMetaData from AttributeGroup *.
            const avtMatSpeciesMetaData &species1 = *((const avtMatSpeciesMetaData *)(species[i]));
            const avtMatSpeciesMetaData &species2 = *((const avtMatSpeciesMetaData *)(obj.species[i]));
            species_equal = (species1 == species2);
        }

        retval = species_equal;
        }
        break;
    default: retval = false;
    }

    return retval;
}

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

// ****************************************************************************
//  Method: avtSpeciesMetaData constructor
//
//  Arguments:
//      n            The name of the species
//      meshn        The name of the mesh the species is defined on.
//      matn         The name of the material the species is defined on.
//      nummat       The number of materials in matn.
//      ns           The number of species for each material.
//      sn           The name of each species for each material.
//
//  Programmer: Hank Childs
//  Creation:   August 28, 2000
//
//  Modifications:
//    Hank Childs, Fri Feb 23 13:30:13 PST 2001
//    Added nummat argument.
//
//    Hank Childs, Mon Dec  9 17:04:39 PST 2002
//    Initialized validVariable.
//
//    Hank Childs, Mon Feb 14 14:16:49 PST 2005
//    Added original name.
//
// ****************************************************************************

avtSpeciesMetaData::avtSpeciesMetaData(const std::string &n,
    const std::string &meshn, const std::string &matn,
    int nummat, const intVector &ns, const std::vector<stringVector> &sn)
    : AttributeSubject(avtSpeciesMetaData::TypeMapFormatString)
{
    // Initialize all.
    *this = avtSpeciesMetaData();

    // Override members
    name         = n;
    originalName = name;
    meshName     = meshn;
    materialName = matn;
    numMaterials = nummat;

    ClearSpecies();
    for (size_t i=0; i<ns.size(); i++)
        AddSpecies(avtMatSpeciesMetaData(ns[i], sn[i]));
    validVariable = true;
}

// ****************************************************************************
//  Method: avtSpeciesMetaData::Print
//
//  Purpose:
//      Print statement for debugging.
//
//  Arguments:
//      out      The stream to output to.
//      indent   The number of tabs to indent each line with.
//
//  Programmer:  Hank Childs
//  Creation:    August 28, 2000
//
//  Modifications:
//    Brad Whitlock, Tue Aug 20 16:10:53 PST 2002
//    I changed the printing a little bit.
//
//    Hank Childs, Mon Dec  9 17:04:39 PST 2002
//    Added validVariable.
//
//    Hank Childs, Mon Feb 14 14:16:49 PST 2005
//    Added original name.
//
// ****************************************************************************
inline void
Indent(ostream &out, int indent)
{
    for (int i = 0 ; i < indent ; i++)
    {
        out << "\t";
    }
}
void
avtSpeciesMetaData::Print(ostream &out, int indent) const
{
    Indent(out, indent);
    out << "Name = " << name.c_str() << endl;
    if (name != originalName)
    {
        Indent(out, indent);
        out << "Original Name = " << originalName.c_str() << endl;
    }

    Indent(out, indent);
    out << "Mesh Name = " << meshName.c_str() << endl;
    Indent(out, indent);
    out << "Material Name = " << materialName.c_str() << endl;
    Indent(out, indent);
    out << "Number of materials = " << numMaterials << endl;
    for (int i = 0 ; i < GetNumSpecies() ; i++)
    {
        Indent(out, indent);
        const avtMatSpeciesMetaData &s = GetSpecies(i);
        out << "Material " << i << ", number of species = "
            << s.numSpecies << endl;
        Indent(out, indent);
        out << "Species names are: ";
        for (int j = 0 ; j < s.numSpecies ; j++)
        {
            out << "\"" << s.speciesNames[j].c_str() << "\"";
            if(j < s.numSpecies - 1)
                out << ", ";
        }
        out << endl;
    }

    if (!validVariable)
    {
        Indent(out, indent);
        out << "THIS IS NOT A VALID VARIABLE." << endl;
    }
}

