#ifndef ANY_H
#define ANY_H

#ifndef FLAW_H
#include "Flaw.h"
#endif

#ifndef INCLUDED_TYPEINFO
#include <typeinfo>
#define INCLUDED_TYPEINFO
#endif

namespace MM
{

class Any
{
public:
    Any () : holder_(0) { }

    template <typename T>
    Any (const T & value) : holder_ (new Holder <T> (value)) {}

    Any (const Any & other) 
        : holder_ (other.holder_ != 0 ? other.holder_->clone() : 0) {} 

    ~Any()  {delete holder_;}

    void swap (Any & other)
    {
        Placeholder * tmp = holder_;
        holder_       = other.holder_;
        other.holder_ = tmp;
    }

    template <typename T>
    Any & operator = (const T & value)
    {
        Any (value). swap (*this);
        return *this;
    }

    Any & operator = (const Any & other)
    {
        Any (other). swap (*this);
        return *this;
    }

    bool is_empty () const      {return holder_ == 0;}

    const std::type_info & type() const
    {
        return holder_ != 0  ? holder_->type() : typeid (void);
    }

    bool destroy () {return holder_->destroy();}


protected:
    template <typename T> friend       T * any_cast (Any *);
    template <typename T> friend const T * any_cast (const Any *);
    template <typename T> friend       T & any_cast (Any &);
    template <typename T> friend const T & any_cast (const Any &);
    
    struct Placeholder
    {
        virtual                         ~Placeholder () {}
        virtual Placeholder *           clone () const = 0;
        virtual const std::type_info &  type  () const = 0;
        virtual bool                    destroy () =0; 
    };

    template <typename T>
    struct Holder : public Placeholder
    {
                                Holder (const T & value) : value_ (value) {}
        Placeholder *           clone () const {return new Holder (value_);}
        const std::type_info &  type  () const {return typeid (T);}

        bool                    destroy ()      {return  false;} 
    
        T                       value_;
    };

    template <typename T>
    struct Adopt_holder : public Holder<T>
    {
                            Adopt_holder (const T & value) : Holder<T> (value){}
        Placeholder *       clone() const {return new Adopt_holder (this->value_);}
        bool                destroy ()    {delete this->value_; return true;}
    };

    Placeholder *           holder_;

public:
    class Adopt
    {
        friend class Any;
        Placeholder *       holder_;

    public:
        template <typename T>
        Adopt (const T & value) : holder_ (new Adopt_holder <T> (value)) { }
        ~Adopt () {delete holder_; holder_ = 0;}

    private:
        Adopt (const Adopt &);
        void operator = (const Adopt &);
    };

    //Any (const Ptr & any_ptr) : holder_ (any_ptr.holder_->clone()) { } 
    Any (const Adopt & any_ptr) : holder_ (any_ptr.holder_)
    {
        const_cast <Adopt&> (any_ptr).holder_ = 0;
    } 
};

template <typename T>
T * any_cast (Any * operand)
{
    return operand && operand->type() == typeid (T)
        ? &static_cast <Any::Holder <T> *> (operand->holder_)->value_
        : 0;
}

template <typename T>
const T * any_cast (const Any * operand)
{
    return any_cast <T> (const_cast <Any *> (operand));
}

template <typename T>
T & any_cast (Any & operand)
{
    T * result = any_cast <T> (&operand);
    if (!result)
        FLAW (Text ("'") +
              Text (typeid(T).name()) + "' and '" + 
              Text (operand.type().name()) + 
              "' are different types.");
    return *result;
}

template <typename T>
T const& any_cast (Any const& operand)
{
    T const* result = any_cast <T> (&operand);
    if (!result)
        FLAW (Text ("'") +
              Text (typeid(T).name()) + "' and '" + 
              Text (operand.type().name()) + 
              "' are different types.");
    return *result;
}

/*template <typename T>
const T & any_cast (const Any & operand)
{
    const T * result = any_cast <T> (&operand);
    if (!result)
        FLAW ("Incompatible type.");
    return *result;
}//*/

}//MM



// Class MM::Any is a modufication of boost::any class.



// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#endif //ANY_H
