// 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 <FileOpenOptions.h>
#include <DataNode.h>
#include <DBOptionsAttributes.h>

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

void FileOpenOptions::Init()
{
    preferredIDs.push_back("Silo_1.0");

    FileOpenOptions::SelectAll();
}

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

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

    typeNames = obj.typeNames;
    typeIDs = obj.typeIDs;
    // *** Copy the openOptions field ***
    // Delete the AttributeGroup objects and clear the vector.
    for(pos = openOptions.begin(); pos != openOptions.end(); ++pos)
        delete *pos;
    openOptions.clear();
    if(obj.openOptions.size() > 0)
        openOptions.reserve(obj.openOptions.size());
    // Duplicate the openOptions from obj.
    for(pos = obj.openOptions.begin(); pos != obj.openOptions.end(); ++pos)
    {
        DBOptionsAttributes *oldDBOptionsAttributes = (DBOptionsAttributes *)(*pos);
        DBOptionsAttributes *newDBOptionsAttributes = new DBOptionsAttributes(*oldDBOptionsAttributes);
        openOptions.push_back(newDBOptionsAttributes);
    }

    Enabled = obj.Enabled;
    preferredIDs = obj.preferredIDs;

    FileOpenOptions::SelectAll();
}

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


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

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

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

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

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

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

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

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

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

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

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

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

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

    FileOpenOptions::Copy(obj);

    return *this;
}

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

bool
FileOpenOptions::operator == (const FileOpenOptions &obj) const
{
    bool openOptions_equal = (obj.openOptions.size() == openOptions.size());
    for(size_t i = 0; (i < openOptions.size()) && openOptions_equal; ++i)
    {
        // Make references to DBOptionsAttributes from AttributeGroup *.
        const DBOptionsAttributes &openOptions1 = *((const DBOptionsAttributes *)(openOptions[i]));
        const DBOptionsAttributes &openOptions2 = *((const DBOptionsAttributes *)(obj.openOptions[i]));
        openOptions_equal = (openOptions1 == openOptions2);
    }

    // Create the return value
    return ((typeNames == obj.typeNames) &&
            (typeIDs == obj.typeIDs) &&
            openOptions_equal &&
            (Enabled == obj.Enabled) &&
            (preferredIDs == obj.preferredIDs));
}

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

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

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

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

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

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

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

    return true;
}

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

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

    return retval;
}

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

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

    return retval;
}

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

void
FileOpenOptions::SelectAll()
{
    Select(ID_typeNames,    (void *)&typeNames);
    Select(ID_typeIDs,      (void *)&typeIDs);
    Select(ID_openOptions,  (void *)&openOptions);
    Select(ID_Enabled,      (void *)&Enabled);
    Select(ID_preferredIDs, (void *)&preferredIDs);
}

// ****************************************************************************
// Method: FileOpenOptions::CreateSubAttributeGroup
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeGroup *
FileOpenOptions::CreateSubAttributeGroup(int)
{
    return new DBOptionsAttributes;
}

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

// ****************************************************************************
// Method: FileOpenOptions::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
FileOpenOptions::CreateNode(DataNode *parentNode, bool completeSave, bool forceAdd)
{
    if(parentNode == 0)
        return false;

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

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

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

    if(completeSave || !FieldsEqual(ID_openOptions, &defaultObject))
    {
        addToParent = true;
        for(size_t i = 0; i < openOptions.size(); ++i)
            openOptions[i]->CreateNode(node, completeSave, true);
    }

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

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


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

    return (addToParent || forceAdd);
}

// ****************************************************************************
// Method: FileOpenOptions::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
FileOpenOptions::SetFromNode(DataNode *parentNode)
{
    if(parentNode == 0)
        return;

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

    DataNode *node;
    DataNode **children;
    if((node = searchNode->GetNode("typeNames")) != 0)
        SetTypeNames(node->AsStringVector());
    if((node = searchNode->GetNode("typeIDs")) != 0)
        SetTypeIDs(node->AsStringVector());

    // Clear all the DBOptionsAttributess if we got any.
    bool clearedOpenOptions = false;
    // Go through all of the children and construct a new
    // DBOptionsAttributes for each one of them.
    children = searchNode->GetChildren();
    if(children != 0)
    {
        for(int i = 0; i < searchNode->GetNumChildren(); ++i)
        {
            if(children[i]->GetKey() == std::string("DBOptionsAttributes"))
            {
                if (!clearedOpenOptions)
                {
                    ClearOpenOptions();
                    clearedOpenOptions = true;
                }
                DBOptionsAttributes temp;
                temp.SetFromNode(children[i]);
                AddOpenOptions(temp);
            }
        }
    }

    if((node = searchNode->GetNode("Enabled")) != 0)
        SetEnabled(node->AsIntVector());
    if((node = searchNode->GetNode("preferredIDs")) != 0)
        SetPreferredIDs(node->AsStringVector());
}

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

void
FileOpenOptions::SetTypeNames(const stringVector &typeNames_)
{
    typeNames = typeNames_;
    Select(ID_typeNames, (void *)&typeNames);
}

void
FileOpenOptions::SetTypeIDs(const stringVector &typeIDs_)
{
    typeIDs = typeIDs_;
    Select(ID_typeIDs, (void *)&typeIDs);
}

void
FileOpenOptions::SetEnabled(const intVector &Enabled_)
{
    Enabled = Enabled_;
    Select(ID_Enabled, (void *)&Enabled);
}

void
FileOpenOptions::SetPreferredIDs(const stringVector &preferredIDs_)
{
    preferredIDs = preferredIDs_;
    Select(ID_preferredIDs, (void *)&preferredIDs);
}

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

const stringVector &
FileOpenOptions::GetTypeNames() const
{
    return typeNames;
}

stringVector &
FileOpenOptions::GetTypeNames()
{
    return typeNames;
}

const stringVector &
FileOpenOptions::GetTypeIDs() const
{
    return typeIDs;
}

stringVector &
FileOpenOptions::GetTypeIDs()
{
    return typeIDs;
}

const AttributeGroupVector &
FileOpenOptions::GetOpenOptions() const
{
    return openOptions;
}

AttributeGroupVector &
FileOpenOptions::GetOpenOptions()
{
    return openOptions;
}

const intVector &
FileOpenOptions::GetEnabled() const
{
    return Enabled;
}

intVector &
FileOpenOptions::GetEnabled()
{
    return Enabled;
}

const stringVector &
FileOpenOptions::GetPreferredIDs() const
{
    return preferredIDs;
}

stringVector &
FileOpenOptions::GetPreferredIDs()
{
    return preferredIDs;
}

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

void
FileOpenOptions::SelectTypeNames()
{
    Select(ID_typeNames, (void *)&typeNames);
}

void
FileOpenOptions::SelectTypeIDs()
{
    Select(ID_typeIDs, (void *)&typeIDs);
}

void
FileOpenOptions::SelectOpenOptions()
{
    Select(ID_openOptions, (void *)&openOptions);
}

void
FileOpenOptions::SelectEnabled()
{
    Select(ID_Enabled, (void *)&Enabled);
}

void
FileOpenOptions::SelectPreferredIDs()
{
    Select(ID_preferredIDs, (void *)&preferredIDs);
}

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

// ****************************************************************************
// Method: FileOpenOptions::AddOpenOptions
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
FileOpenOptions::AddOpenOptions(const DBOptionsAttributes &obj)
{
    DBOptionsAttributes *newDBOptionsAttributes = new DBOptionsAttributes(obj);
    openOptions.push_back(newDBOptionsAttributes);

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

// ****************************************************************************
// Method: FileOpenOptions::ClearOpenOptions
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
FileOpenOptions::ClearOpenOptions()
{
    AttributeGroupVector::iterator pos;

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

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

// ****************************************************************************
// Method: FileOpenOptions::RemoveOpenOptions
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
FileOpenOptions::RemoveOpenOptions(int index)
{
    AttributeGroupVector::iterator pos = openOptions.begin();

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

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

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

// ****************************************************************************
// Method: FileOpenOptions::GetNumOpenOptions
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

int
FileOpenOptions::GetNumOpenOptions() const
{
    return (int)openOptions.size();
}

// ****************************************************************************
// Method: FileOpenOptions::GetOpenOptions
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DBOptionsAttributes &
FileOpenOptions::GetOpenOptions(int i)
{
    return *((DBOptionsAttributes *)openOptions[i]);
}

// ****************************************************************************
// Method: FileOpenOptions::GetOpenOptions
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const DBOptionsAttributes &
FileOpenOptions::GetOpenOptions(int i) const
{
    return *((DBOptionsAttributes *)openOptions[i]);
}

// ****************************************************************************
// Method: FileOpenOptions::operator []
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

DBOptionsAttributes &
FileOpenOptions::operator [] (int i)
{
    return *((DBOptionsAttributes *)openOptions[i]);
}

// ****************************************************************************
// Method: FileOpenOptions::operator []
//
// Purpose:
//   This class contains the file opening options for all the database plugins.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const DBOptionsAttributes &
FileOpenOptions::operator [] (int i) const
{
    return *((DBOptionsAttributes *)openOptions[i]);
}

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

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

std::string
FileOpenOptions::GetFieldName(int index) const
{
    switch (index)
    {
    case ID_typeNames:    return "typeNames";
    case ID_typeIDs:      return "typeIDs";
    case ID_openOptions:  return "openOptions";
    case ID_Enabled:      return "Enabled";
    case ID_preferredIDs: return "preferredIDs";
    default:  return "invalid index";
    }
}

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

AttributeGroup::FieldType
FileOpenOptions::GetFieldType(int index) const
{
    switch (index)
    {
    case ID_typeNames:    return FieldType_stringVector;
    case ID_typeIDs:      return FieldType_stringVector;
    case ID_openOptions:  return FieldType_attVector;
    case ID_Enabled:      return FieldType_intVector;
    case ID_preferredIDs: return FieldType_stringVector;
    default:  return FieldType_unknown;
    }
}

// ****************************************************************************
// Method: FileOpenOptions::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
FileOpenOptions::GetFieldTypeName(int index) const
{
    switch (index)
    {
    case ID_typeNames:    return "stringVector";
    case ID_typeIDs:      return "stringVector";
    case ID_openOptions:  return "attVector";
    case ID_Enabled:      return "intVector";
    case ID_preferredIDs: return "stringVector";
    default:  return "invalid index";
    }
}

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

bool
FileOpenOptions::FieldsEqual(int index_, const AttributeGroup *rhs) const
{
    const FileOpenOptions &obj = *((const FileOpenOptions*)rhs);
    bool retval = false;
    switch (index_)
    {
    case ID_typeNames:
        {  // new scope
        retval = (typeNames == obj.typeNames);
        }
        break;
    case ID_typeIDs:
        {  // new scope
        retval = (typeIDs == obj.typeIDs);
        }
        break;
    case ID_openOptions:
        {  // new scope
        bool openOptions_equal = (obj.openOptions.size() == openOptions.size());
        for(size_t i = 0; (i < openOptions.size()) && openOptions_equal; ++i)
        {
            // Make references to DBOptionsAttributes from AttributeGroup *.
            const DBOptionsAttributes &openOptions1 = *((const DBOptionsAttributes *)(openOptions[i]));
            const DBOptionsAttributes &openOptions2 = *((const DBOptionsAttributes *)(obj.openOptions[i]));
            openOptions_equal = (openOptions1 == openOptions2);
        }

        retval = openOptions_equal;
        }
        break;
    case ID_Enabled:
        {  // new scope
        retval = (Enabled == obj.Enabled);
        }
        break;
    case ID_preferredIDs:
        {  // new scope
        retval = (preferredIDs == obj.preferredIDs);
        }
        break;
    default: retval = false;
    }

    return retval;
}

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

#include <DebugStream.h> // needed for debug output in this function

// ****************************************************************************
//  Method: FileOpenOptions::MergeFromPluginInfo
//
//  Purpose: Merge options defined from config file with options defined by
//  plugins. The net effect of calling this function is to change the options
//  associated with 'this' object.
//
//  Programmer: Unknown
//  Creation:   Unknown
//
//  Modifications:
//    Mark C. Miller, Mon Mar 16 22:55:44 PDT 2009
//    Re-structured to make it clearer what was getting merged with
//    what. The options defined by the plugins are coming in via the
//    dbinfo function argument while the options read from the config file
//    are basically part of 'this' object. Adjusted logic to deal with
//    options that have been made obsolete.
//
//    Mark C. Miller, Tue May 19 20:53:25 PDT 2009
//    Terminate for loop searching for matching typeID early.
// ****************************************************************************

void
FileOpenOptions::MergeNewFromPluginInfo(const DBPluginInfoAttributes *dbinfo)
{
    int n = dbinfo->GetNumDbReadOptions();
    for (int i=0; i<n; i++)
    {
        DBOptionsAttributes plugin_opts = dbinfo->GetDbReadOptions(i);
        const std::string &id = dbinfo->GetTypesFullNames()[i];
        const std::string &name = dbinfo->GetTypes()[i];
        int index = -1;
        for (size_t j=0; index==-1 && j<typeIDs.size(); j++)
        {
            if (typeIDs[j] == id)
                index = j;
        }
        if (index == -1)
        {
            typeNames.push_back(name);
            typeIDs.push_back(id);
            Enabled.push_back(true);
            AddOpenOptions(plugin_opts);
        }
        else
        {
            //
            // Get the options that are part of this object, make a
            // copy of them and then over-write 'this' with the options
            // defined by the plugins.
            //
            DBOptionsAttributes &this_opts = GetOpenOptions(index);
            DBOptionsAttributes config_opts = this_opts; // copy
            this_opts = plugin_opts; // overwrite 'this'

            //
            // Ok, now this loop basically iterates over options defined
            // in the config file, checking them against those defined by
            // the plugin. When it finds a match, it overwrites it with
            // whatever value it found in the config file. When it does NOT
            // find a match, that means that the config file defines an
            // option that the plugin is no longer coded to know about. This
            // most likely indicates an obsolete option.
            //
            int n_config  = config_opts.GetNumberOfOptions();
            int n_this = this_opts.GetNumberOfOptions();
            for (int j=0; j<n_config; j++)
            {
                std::string optname = config_opts.GetName(j);
                int match = -1;
                for (int k=0; k<n_this; k++)
                {
                    if (this_opts.GetName(k) == optname)
                    {
                        match = k;
                        break;
                    }
                }
                if (match < 0 && !this_opts.IsObsolete(optname))
                {
                    //
                    // If we get here, it means the option is defined
                    // in the config file but is NOT defined by the plugin.
                    // and probably never has been defined by the plugin at
                    // any time in the past.
                    //
                    debug1 << "Got unknown option \"" << optname
                           << "\" from config file for plugin \"" << id
                           << "\"" << endl;
                }
                else
                {
                    //
                    // If we get here, the config file defines a value for an
                    // option. So, overwrite whatever we have stored in 'this'
                    // object (which because of the copy, this_opts=plugin_opts,
                    // above is currently set to whatever the plugin defines as
                    // the default value) with whatever the config file says.
                    // If the option was obsolete, the succeeding calls will
                    // define create it and that is fine because 'this_opts'
                    // already knows its obsolete and now only needs to obtain
                    // the value for it from the config file. Otherwise, the
                    // succeeding calls just overwrite the default value with
                    // the value from the config file.
                    //
                    switch (config_opts.GetType(j))
                    {
                      case DBOptionsAttributes::Bool:
                        this_opts.SetBool(optname, config_opts.GetBool(optname));
                        break;
                      case DBOptionsAttributes::Int:
                        this_opts.SetInt(optname, config_opts.GetInt(optname));
                        break;
                      case DBOptionsAttributes::Float:
                        this_opts.SetFloat(optname, config_opts.GetFloat(optname));
                        break;
                      case DBOptionsAttributes::Double:
                        this_opts.SetDouble(optname, config_opts.GetDouble(optname));
                        break;
                      case DBOptionsAttributes::String:
                        this_opts.SetString(optname, config_opts.GetString(optname));
                        break;
                      case DBOptionsAttributes::Enum:
                        this_opts.SetEnum(optname, config_opts.GetEnum(optname));
                        this_opts.SetEnumStrings(optname, config_opts.GetEnumStrings(optname));
                        break;
                    }
                }
            }
        }
    }
}

// ****************************************************************************
// Method:  FileOpenOptions::AddAssumedFormatsToPreferred
//
// Purpose:
//   Adds any given formats to the *beginning* of the preferred list, moving
//   their position to the front if they were already in the list.
//
// Arguments:
//   given    the list of formats labeled as "assumed"
//
// Programmer:  Jeremy Meredith
// Creation:    March 26, 2010
//
// ****************************************************************************
void
FileOpenOptions::AddAssumedFormatsToPreferred(const stringVector &given)
{
    // for each format, prepend it; visit them in reverse order
    // so the first one given winds up first in the new list
    for (int i=(int)given.size()-1; i>=0; i--)
    {
        // get its actual ID
        std::string id = "";
        for (size_t j=0; j<typeIDs.size(); j++)
        {
            if (given[i] == typeIDs[j] ||
                given[i] == typeNames[j])
            {
                id = typeIDs[j];
                break;
            }
        }
        // if no id, we don't have that plugin, so skip this one
        if (id == "")
            continue;

        // make a new list with this given one at the front
        stringVector newPreferredIDs;
        newPreferredIDs.push_back(id);
        for (size_t j=0; j<preferredIDs.size(); j++)
        {
            if (preferredIDs[j] != id)
                newPreferredIDs.push_back(preferredIDs[j]);
        }
        preferredIDs = newPreferredIDs;
    }
    SelectPreferredIDs();
}

// ****************************************************************************
// Method:  FileOpenOptions::AddFallbackFormatsToPreferred
//
// Purpose:
//   Adds any given formats to the *end* of the preferred list, moving
//   their position to the back if they were already in the list.
//
// Arguments:
//   given    the list of formats labeled as "fallback"
//
// Programmer:  Jeremy Meredith
// Creation:    March 26, 2010
//
// ****************************************************************************
void
FileOpenOptions::AddFallbackFormatsToPreferred(const stringVector &given)
{
    // for each format, append it
    for (size_t i=0; i<given.size(); i++)
    {
        // get its actual ID
        std::string id = "";
        for (size_t j=0; j<typeIDs.size(); j++)
        {
            if (given[i] == typeIDs[j] ||
                given[i] == typeNames[j])
            {
                id = typeIDs[j];
                break;
            }
        }
        // if no id, we don't have that plugin, so skip this one
        if (id == "")
            continue;

        // make a new list with this given one at the back
        stringVector newPreferredIDs;
        for (size_t j=0; j<preferredIDs.size(); j++)
        {
            if (preferredIDs[j] != id)
                newPreferredIDs.push_back(preferredIDs[j]);
        }
        newPreferredIDs.push_back(id);
        preferredIDs = newPreferredIDs;
    }
    SelectPreferredIDs();
}

const DBOptionsAttributes*
FileOpenOptions::GetOpenOptionsForID(const std::string &id)
{
    for (size_t i=0; i<typeIDs.size(); i++)
    {
        if (typeIDs[i] == id)
            return (const DBOptionsAttributes*)(openOptions[i]);
    }
    return NULL;
}

// ****************************************************************************
// Method:  FileOpenOptions::IsIDEnabled
//
// Purpose:
//   Convenience function to find the Enabled value for the given id.
//
// Arguments:
//   id         the id for which to search
//
// Programmer:  Jeremy Meredith
// Creation:    December 30, 2009
//
// ****************************************************************************
bool
FileOpenOptions::IsIDEnabled(const std::string &id)
{
    for (size_t i=0; i<typeIDs.size(); i++)
    {
        if (typeIDs[i] == id)
            return Enabled[i];
    }
    return true; // default is what, true?
}

