/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library 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 
 * OpenSceneGraph Public License for more details.
*/
//osgIntrospection - Copyright (C) 2005 Marco Jez

#ifndef OSGINTROSPECTION_ATTRIBUTES_
#define OSGINTROSPECTION_ATTRIBUTES_

#include <osgIntrospection/CustomAttribute>
#include <osgIntrospection/Value>
#include <osgIntrospection/Exceptions>
#include <osgIntrospection/Type>

namespace osgIntrospection
{

    /// By adding this attribute to a PropertyInfo you specify that there
    /// is no default value for that property.
    class NoDefaultValueAttribute: public CustomAttribute {};


    /// By adding this attribute to a PropertyInfo you specify a custom
    /// default value for that property.
    class DefaultValueAttribute: public CustomAttribute
    {
    public:
        DefaultValueAttribute(const Value& v): _v(v) {}
        const Value& getDefaultValue() const { return _v; }
    private:
        Value _v;
    };

    /// Base struct for custom property getters. Descendants may override
    /// one or more of the get() methods to provide the means for retrieving
    /// the value of a property. The first version of get() is used with
    /// indexed properties, the second one serves simple properties and the
    /// last one is used with array properties.
    struct PropertyGetter
    {
        virtual Value get(Value&  /*instance*/, const ValueList&  /*indices*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::IGET); }
        virtual Value get(Value&  /*instance*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::GET); }
        virtual Value get(Value&  /*instance*/, int /*i*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::AGET); }
        virtual Value get(const Value&  /*instance*/, const ValueList&  /*indices*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::IGET); }
        virtual Value get(const Value&  /*instance*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::GET); }
        virtual Value get(const Value&  /*instance*/, int /*i*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::AGET); }
        virtual ~PropertyGetter() {}
    };

    /// By setting an attribute of this class you can specify a custom object
    /// that will be used to retrieve the value of a property instead of the
    /// default getter method.
    class CustomPropertyGetAttribute: public CustomAttribute
    {
    public:
        CustomPropertyGetAttribute(const PropertyGetter* getter)
        :    CustomAttribute(), _getter(getter) {}

        const PropertyGetter* getGetter() const { return _getter; }

        ~CustomPropertyGetAttribute()
        {
            delete _getter;
        }

    private:
        const PropertyGetter* _getter;
    };

    /// Base struct for custom property setters. Descendants may override
    /// one or more of the set() methods to provide the means for setting
    /// the value of a property. The first version of set() is used with
    /// indexed properties, the second one serves simple properties and the
    /// last one is used with array properties.
    struct PropertySetter
    {
        virtual void set(Value&  /*instance*/, ValueList&  /*indices*/, const Value&  /*value*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::ISET); }
        virtual void set(Value&  /*instance*/, const Value&  /*value*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::SET); }
        virtual void set(Value&  /*instance*/, int /*i*/, const Value&  /*value*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::ASET); }
        virtual ~PropertySetter() {}
    };

    /// By setting an attribute of this class you can specify a custom object
    /// that will be used to set the value of a property instead of the
    /// default setter method.
    class CustomPropertySetAttribute: public CustomAttribute
    {
    public:
        CustomPropertySetAttribute(const PropertySetter* setter)
        :    CustomAttribute(), _setter(setter) {}

        const PropertySetter* getSetter() const { return _setter; }

        ~CustomPropertySetAttribute()
        {
            delete _setter;
        }

    private:
        const PropertySetter* _setter;
    };

    /// Base struct for custom array property counters. Descendants should
    /// override the count() method which must return the number of items
    /// in a chosen array property for the given instance.
    struct PropertyCounter
    {
        virtual int count(const Value&  /*instance*/) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::COUNT); }
        virtual ~PropertyCounter() {}
    };

    /// By setting an attribute of this class you can specify a custom object
    /// that will be used to count the number of items in an array property.
    class CustomPropertyCountAttribute: public CustomAttribute
    {
    public:
        CustomPropertyCountAttribute(const PropertyCounter* counter)
        :    CustomAttribute(), _counter(counter) {}

        const PropertyCounter* getCounter() const { return _counter; }

        ~CustomPropertyCountAttribute()
        {
            delete _counter;
        }

    private:
        const PropertyCounter* _counter;
    };

    /// Base struct for custom array property adders. Descendants should
    /// override the add() method whose purpose is to add a new item to
    /// an array property.
    struct PropertyAdder
    {
        virtual void add(Value&, const Value&) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::ADD); }
        virtual ~PropertyAdder() {}
    };

    /// By setting an attribute of this class you can specify a custom object
    /// that will be used to add a new item to an array property.
    class CustomPropertyAddAttribute: public CustomAttribute
    {
    public:
        CustomPropertyAddAttribute(const PropertyAdder* adder)
        :    CustomAttribute(), _adder(adder) {}

        const PropertyAdder* getAdder() const { return _adder; }

        ~CustomPropertyAddAttribute()
        {
            delete _adder;
        }

    private:
        const PropertyAdder* _adder;
    };

    /// Base struct for custom array property inserters. Descendants should
    /// override the insert() method whose purpose is to insert a new item to
    /// an array property.
    struct PropertyInserter
    {
        virtual void insert(Value&, int, const Value&) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::INSERT); }
    virtual void insert(Value&, const ValueList&, const Value&) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::INSERT); }
        virtual ~PropertyInserter() {}
    };

    /// By setting an attribute of this class you can specify a custom object
    /// that will be used to insert a new item to an array property.
    class CustomPropertyInsertAttribute: public CustomAttribute
    {
    public:
        CustomPropertyInsertAttribute(const PropertyInserter* inserter)
        :    CustomAttribute(), _inserter(inserter) {}

        const PropertyInserter* getInserter() const { return _inserter; }

        ~CustomPropertyInsertAttribute()
        {
            delete _inserter;
        }

    private:
        const PropertyInserter* _inserter;
    };

    /// Base struct for custom array property removers. Descendants should
    /// override the remove() method whose purpose is to remove an item from
    /// an array property.
    struct PropertyRemover
    {
        virtual void remove(Value&, int) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::REMOVE); }
        virtual void remove(Value&, ValueList&) const { throw PropertyAccessException("[n/a inside a custom accessor]", PropertyAccessException::REMOVE); }
        virtual ~PropertyRemover() {}
    };
    
    /// By setting an attribute of this class you can specify a custom object
    /// that will be used to remove an item from an array property.
    class CustomPropertyRemoveAttribute: public CustomAttribute
    {
    public:
        CustomPropertyRemoveAttribute(const PropertyRemover* remover)
        :    CustomAttribute(), _remover(remover) {}

        const PropertyRemover* getRemover() const { return _remover; }

        ~CustomPropertyRemoveAttribute()
        {
            delete _remover;
        }

    private:
        const PropertyRemover* _remover;
    };


    /// This struct allows customization of an indexed property's index set.
    /// You must derive from this struct and provide a concrete implementation
    /// of getIndexValueSet(), which must return (in parameter values) a list
    /// of valid values to be used as indices. The whichindex parameter
    /// specifies which index is being queried (0 = first index, 1 = second
    /// index, ...).
    /// See CustomIndexAttribute for details.
    struct IndexInfo
    {
        virtual const ParameterInfoList& getIndexParameters() const = 0;
        virtual void getIndexValueSet(int whichindex, const Value& instance, ValueList& values) const = 0;
        virtual ~IndexInfo() {}
    };


    /// By default each index in an indexed property is assumed to be an
    /// enumeration. When serialization is performed, indices are chosen
    /// from the set of enum labels that were defined for the index type.
    /// With this attribute you can provide custom code to determine the
    /// set of values to be used as indices, instead of the default enum
    /// values. This attribute is required, for example, when the number
    /// and/or value of indices is not constant over time (such as in
    /// associative containers).
    class CustomIndexAttribute: public CustomAttribute
    {
    public:
        CustomIndexAttribute(const IndexInfo* ii)
        :    CustomAttribute(), _ii(ii) {}

        const IndexInfo* getIndexInfo() const
        {
            return _ii;
        }

        ~CustomIndexAttribute()
        {
            delete _ii;
        }

    private:
        const IndexInfo* _ii;
    };

    /// Attribute for overriding the type of a property with a custom
    /// type. If you add this attribute to a PropertyInfo object, then
    /// all subsequent calls to getValue()/getArrayItem()/getIndexedValue()
    /// will perform a conversion from the actual property's type to
    /// the custom type specified through this attribute. Similarly, all
    /// methods in PropertyInfo that alter the property's value will accept
    /// a value of the custom type instead of the actual type. In this
    /// case the conversion is implicit and occurs later within the accessor
    /// methods.
    class PropertyTypeAttribute: public CustomAttribute
    {
    public:
        PropertyTypeAttribute(const Type& type)
        :    CustomAttribute(), _type(type) {}

        const Type& getPropertyType() const
        {
            return _type;
        }

    private:
        const Type& _type;

        PropertyTypeAttribute& operator = (const PropertyTypeAttribute&) { return *this; }
    };

    /// Attribute for overriding the type of an index (of an indexed 
    /// property) with a custom type. Behaves like PropertyTypeAttribute,
    /// but it affects the value of an index instead of the property's
    /// value itself.
    /// NOTE: property with custom indexing attributes are not affected
    ///       by this attribute!
    class IndexTypeAttribute: public CustomAttribute
    {
    public:
        IndexTypeAttribute(int whichindex, const Type& type)
        :    CustomAttribute(), _wi(whichindex), _type(type) {}

        int getWhichIndex() const
        {
            return _wi;
        }

        const Type& getIndexType() const
        {
            return _type;
        }

    private:
    
        IndexTypeAttribute& operator = (const IndexTypeAttribute&) { return *this; }
    
        int _wi;
        const Type& _type;
    };
}

#endif
