/*
  ==============================================================================

   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-11 by Raw Material Software Ltd.

  ------------------------------------------------------------------------------

   JUCE can be redistributed and/or modified under the terms of the GNU General
   Public License (Version 2), as published by the Free Software Foundation.
   A copy of the license is included in the JUCE distribution, or can be found
   online at www.gnu.org/licenses.

   JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  ------------------------------------------------------------------------------

   To release a closed-source product which uses JUCE, commercial licenses are
   available: visit www.rawmaterialsoftware.com/juce for more information.

  ==============================================================================
*/

NamedValueSet::NamedValue::NamedValue() noexcept
{
}

inline NamedValueSet::NamedValue::NamedValue (const Identifier& name_, const var& value_)
    : name (name_), value (value_)
{
}

NamedValueSet::NamedValue::NamedValue (const NamedValue& other)
    : name (other.name), value (other.value)
{
}

NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (const NamedValueSet::NamedValue& other)
{
    name = other.name;
    value = other.value;
    return *this;
}

#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
    : nextListItem (static_cast <LinkedListPointer<NamedValue>&&> (other.nextListItem)),
      name (static_cast <Identifier&&> (other.name)),
      value (static_cast <var&&> (other.value))
{
}

inline NamedValueSet::NamedValue::NamedValue (const Identifier& name_, var&& value_)
    : name (name_), value (static_cast <var&&> (value_))
{
}

NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
{
    nextListItem = static_cast <LinkedListPointer<NamedValue>&&> (other.nextListItem);
    name = static_cast <Identifier&&> (other.name);
    value = static_cast <var&&> (other.value);
    return *this;
}
#endif

bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const noexcept
{
    return name == other.name && value == other.value;
}

//==============================================================================
NamedValueSet::NamedValueSet() noexcept
{
}

NamedValueSet::NamedValueSet (const NamedValueSet& other)
{
    values.addCopyOfList (other.values);
}

NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
{
    clear();
    values.addCopyOfList (other.values);
    return *this;
}

#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
    : values (static_cast <LinkedListPointer<NamedValue>&&> (other.values))
{
}

NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
{
    other.values.swapWith (values);
    return *this;
}
#endif

NamedValueSet::~NamedValueSet()
{
    clear();
}

void NamedValueSet::clear()
{
    values.deleteAll();
}

bool NamedValueSet::operator== (const NamedValueSet& other) const
{
    const NamedValue* i1 = values;
    const NamedValue* i2 = other.values;

    while (i1 != nullptr && i2 != nullptr)
    {
        if (! (*i1 == *i2))
            return false;

        i1 = i1->nextListItem;
        i2 = i2->nextListItem;
    }

    return true;
}

bool NamedValueSet::operator!= (const NamedValueSet& other) const
{
    return ! operator== (other);
}

int NamedValueSet::size() const noexcept
{
    return values.size();
}

const var& NamedValueSet::operator[] (const Identifier& name) const
{
    for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
        if (i->name == name)
            return i->value;

    return var::null;
}

var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const
{
    const var* const v = getVarPointer (name);
    return v != nullptr ? *v : defaultReturnValue;
}

var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
{
    for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
        if (i->name == name)
            return &(i->value);

    return nullptr;
}

#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
bool NamedValueSet::set (const Identifier& name, var&& newValue)
{
    LinkedListPointer<NamedValue>* i = &values;

    while (i->get() != nullptr)
    {
        NamedValue* const v = i->get();

        if (v->name == name)
        {
            if (v->value.equalsWithSameType (newValue))
                return false;

            v->value = static_cast <var&&> (newValue);
            return true;
        }

        i = &(v->nextListItem);
    }

    i->insertNext (new NamedValue (name, static_cast <var&&> (newValue)));
    return true;
}
#endif

bool NamedValueSet::set (const Identifier& name, const var& newValue)
{
    LinkedListPointer<NamedValue>* i = &values;

    while (i->get() != nullptr)
    {
        NamedValue* const v = i->get();

        if (v->name == name)
        {
            if (v->value.equalsWithSameType (newValue))
                return false;

            v->value = newValue;
            return true;
        }

        i = &(v->nextListItem);
    }

    i->insertNext (new NamedValue (name, newValue));
    return true;
}

bool NamedValueSet::contains (const Identifier& name) const
{
    return getVarPointer (name) != nullptr;
}

bool NamedValueSet::remove (const Identifier& name)
{
    LinkedListPointer<NamedValue>* i = &values;

    for (;;)
    {
        NamedValue* const v = i->get();

        if (v == nullptr)
            break;

        if (v->name == name)
        {
            delete i->removeNext();
            return true;
        }

        i = &(v->nextListItem);
    }

    return false;
}

const Identifier NamedValueSet::getName (const int index) const
{
    const NamedValue* const v = values[index];
    jassert (v != nullptr);
    return v->name;
}

const var& NamedValueSet::getValueAt (const int index) const
{
    const NamedValue* const v = values[index];
    jassert (v != nullptr);
    return v->value;
}

void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
{
    clear();
    LinkedListPointer<NamedValue>::Appender appender (values);

    const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..

    for (int i = 0; i < numAtts; ++i)
        appender.append (new NamedValue (xml.getAttributeName (i), var (xml.getAttributeValue (i))));
}

void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
{
    for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
    {
        jassert (! i->value.isObject()); // DynamicObjects can't be stored as XML!

        xml.setAttribute (i->name.toString(),
                          i->value.toString());
    }
}
