/* -*-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_METHODINFO_
#define OSGINTROSPECTION_METHODINFO_

#include <osgIntrospection/Export>
#include <osgIntrospection/CustomAttributeProvider>
#include <osgIntrospection/Value>
#include <osgIntrospection/Exceptions>
#include <osgIntrospection/ParameterInfo>

#include <cstdarg>
#include <string>
#include <vector>

namespace osgIntrospection
{

    class Type;

    /// Class MethodInfo stores information about a class method. It is an
    /// abstract class, so it must be derived to provide the actual 
    /// implementation of isConst() and invoke(). Instances of this class
    /// can't be modified after their creation.
    class OSGINTROSPECTION_EXPORT MethodInfo: public CustomAttributeProvider
    {
    public:
        /// Possible virtual states of the function.
        enum VirtualState
        {
            NON_VIRTUAL         = 0x0,
            VIRTUAL             = 0x1,
            PURE_VIRTUAL        = 0x3
        };

        /// Direct initialization constructor.
        inline MethodInfo(const std::string& qname, const Type& declarationType, const Type& rtype, const ParameterInfoList& plist, VirtualState virtualState, std::string briefHelp = std::string(), std::string detailedHelp = std::string());

        /// Direct initialization constructor for static functions (no virtual specifier).
        inline MethodInfo(const std::string& qname, const Type& declarationType, const Type& rtype, const ParameterInfoList& plist, std::string briefHelp = std::string(), std::string detailedHelp = std::string());

        /// Destructor
        inline ~MethodInfo();

        /// Returns the Type object associated to the type that
        /// declares the reflected method.
        inline virtual const Type& getDeclaringType() const;        

        /// Returns the name of the reflected method.
        inline virtual const std::string& getName() const;

        /// Returns the return type of the reflected method.
        inline const Type& getReturnType() const;

        /// Returns a list of objects that describe the reflected
        /// method's parameters.
        inline const ParameterInfoList& getParameters() const;

        /// Returns the brief help of the reflected method.
        inline virtual const std::string& getBriefHelp() const;

        /// Returns the detailed help of the reflected method.
        inline virtual const std::string& getDetailedHelp() const;

        /// Returns whether the reflected method is const or not.
        virtual bool isConst() const = 0;
        
        /// Returns whether the reflected method is static or not.
        virtual bool isStatic() const = 0;
        
        /// Returns whether the reflected method is virtual or not.
        virtual bool isVirtual() const;
        
        /// Returns whether the reflected method is pure virtual or not.
        virtual bool isPureVirtual() const;
        
        /// Returns whether this method would override the given
        /// method.
        bool overrides(const MethodInfo* other) const;

        /// Invokes the reflected method dynamically on the given const
        /// instance, passing it the arguments as a list of Value objects.
        inline virtual Value invoke(const Value& instance, ValueList& args) const;

        /// Invokes the reflected method dynamically on the given instance,
        /// passing it the arguments as a list of Value objects.
        inline virtual Value invoke(Value& instance, ValueList& args) const;

        /// Invokes the reflected static method dynamically passing it the 
        /// arguments as a list of Value objects.
        inline virtual Value invoke(ValueList& args) const;

        /// Invokes the reflected method dynamically on the given const
        /// instance, without arguments.
        inline Value invoke(const Value& instance) const;

        /// Invokes the reflected method dynamically on the given
        /// instance, without arguments.
        inline Value invoke(Value& instance) const;
        
        /// Invokes the reflected static method without arguments.
        inline Value invoke() const;

    private:

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

        inline std::string strip_namespace(const std::string& s) const;

        virtual void getInheritedProviders(CustomAttributeProviderList& providers) const;

        std::string _name;
        const Type& _declarationType;
        const Type& _rtype;
        ParameterInfoList _params;
        VirtualState _virtualState;
    
        std::string _briefHelp;
        std::string _detailedHelp;
    };

    // INLINE METHODS

    inline MethodInfo::MethodInfo(const std::string& qname, const Type& declarationType, const Type& rtype, const ParameterInfoList& plist, VirtualState virtualState, std::string briefHelp, std::string detailedHelp)
    :   CustomAttributeProvider(),
        _declarationType(declarationType), 
        _rtype(rtype),
        _params(plist),
        _virtualState(virtualState),
        _briefHelp(briefHelp),
        _detailedHelp(detailedHelp)
    {
        _name = strip_namespace(qname);
    }

    inline MethodInfo::MethodInfo(const std::string& qname, const Type& declarationType, const Type& rtype, const ParameterInfoList& plist, std::string briefHelp, std::string detailedHelp)
    :   CustomAttributeProvider(),
        _declarationType(declarationType), 
        _rtype(rtype),
        _params(plist),
        _virtualState(NON_VIRTUAL),
        _briefHelp(briefHelp),
        _detailedHelp(detailedHelp)
    {
        _name = strip_namespace(qname);
    }

    inline std::string MethodInfo::strip_namespace(const std::string& s) const
    {
        std::string::size_type p = s.rfind("::");
        if (p != std::string::npos)
            return s.substr(p+2);
        return s;
    }

    inline const std::string& MethodInfo::getName() const
    {
        return _name;
    }

    inline const Type& MethodInfo::getDeclaringType() const
    {
        return _declarationType;
    }

    inline const Type& MethodInfo::getReturnType() const
    {
        return _rtype;
    }

    inline const ParameterInfoList& MethodInfo::getParameters() const
    {
        return _params;
    }

    inline const std::string& MethodInfo::getBriefHelp() const
    {
        return _briefHelp;
    }

    inline const std::string& MethodInfo::getDetailedHelp() const
    {
        return _detailedHelp;
    }

    inline bool MethodInfo::isVirtual() const
    {
        return (_virtualState & VIRTUAL) == VIRTUAL;
    }

    inline bool MethodInfo::isPureVirtual() const
    {
        return (_virtualState & PURE_VIRTUAL) == PURE_VIRTUAL;
    }

    inline Value MethodInfo::invoke(const Value& , ValueList& ) const
    {
        throw InvokeNotImplementedException();
    }

    inline Value MethodInfo::invoke(Value& , ValueList& ) const
    {
        throw InvokeNotImplementedException();
    }

    inline Value MethodInfo::invoke(ValueList& ) const
    {
        throw InvokeNotImplementedException();
    }

    inline Value MethodInfo::invoke(const Value& instance) const
    {
        ValueList args;
        return invoke(instance, args);
    }

    inline Value MethodInfo::invoke(Value& instance) const
    {
        ValueList args;
        return invoke(instance, args);
    }
    
    inline Value MethodInfo::invoke() const
    {
        ValueList args;
        return invoke(args);
    }
    
    inline MethodInfo::~MethodInfo()
    {
        for (ParameterInfoList::iterator i=_params.begin(); i!=_params.end(); ++i)
            delete *i;
    }

}

#endif
