/* Theoretic - Graph Theoretic Byte Code Engineering
 * Copyright (C) 2001-2002  Jay Freeman (saurik)
*/

/*
 *        Redistribution and use in source and binary
 * forms, with or without modification, are permitted
 * provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer in the documentation
 *    and/or other materials provided with the
 *    distribution.
 * 3. The name of the author may not be used to endorse
 *    or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef THEORETIC_VOBJECT_H
#define THEORETIC_VOBJECT_H

#if _MSC_VER > 1000
#pragma once

// C4660: template-class specialization '...' is already instantiated
#pragma warning ( disable : 4660 )

#endif // _MSC_VER > 1000

#include "menes-com/Counting.h"

#include "theoretic/theoretic.h"
#include "theoretic/OpList.h"

namespace Theoretic {

    class Operation;

    class THEORETIC_API VObjectInvalidCastException {};

    class THEORETIC_API VObject : public Diapexis::RefCountedObject {
      public:
        virtual bool boolean() const = 0;
        virtual double num() const = 0;
        virtual std::wstring str() const = 0;
        virtual const OpList &opset() const;
    };

    class THEORETIC_API VObjectPtr {
      public:
        inline VObjectPtr() : object(NULL) {}

        inline VObjectPtr(VObject *object) : object(object) {
            if (object != NULL)
                object->AddRef();
        }

        inline VObjectPtr(const VObjectPtr &rhs) : object(rhs.object) {
            if (object != NULL)
                object->AddRef();
        }

        inline ~VObjectPtr() {
            if (object != NULL)
                object->Release();
        }

        VObjectPtr &operator = (VObject *rhs) {
            if (object != NULL)
                object->Release();
            object = rhs;
            object->AddRef();
            return *this;
        }

        inline VObjectPtr &operator = (const VObjectPtr &rhs) {
            return operator = (rhs.object);
        }

        inline bool operator ==(const VObjectPtr &rhs) const {
            return object == rhs.object;
        }

        inline bool operator < (const VObjectPtr &rhs) const {
            return object < rhs.object;
        }

        inline const VObject *operator ->() const {
            return object;
        }

        inline VObject *operator ->() {
            return object;
        }

        inline const VObject &operator * () const {
            return *object;
        }

        inline VObject &operator * () {
            return *object;
        }

      private:
        VObject *object;
    };

    extern const VObjectPtr THEORETIC_API VNullObject;

    DIAPEXIS_DLL_MAP(THEORETIC_EXT, THEORETIC_API, NamedV, std::map, std::wstring, VObjectPtr)

    class THEORETIC_API VBoolean : public VObject {
      public:
        VBoolean(bool value);

        virtual bool boolean() const;
        virtual double num() const;
        virtual std::wstring str() const;

      private:
        bool value;

        static const std::wstring strue;
        static const std::wstring sfalse;
    };

    class THEORETIC_API VNumber : public VObject {
      public:
        VNumber(double value);

        virtual bool boolean() const;
        virtual double num() const;
        virtual std::wstring str() const;

      private:
        double value;
        mutable std::wstring string;
    };

    class THEORETIC_API VString : public VObject {
      public:
        VString(const std::wstring &value);

        virtual bool boolean() const;
        virtual double num() const;
        virtual std::wstring str() const;

      private:
        std::wstring value;
    };

    class THEORETIC_API VOpSet : public VObject {
      public:
        VOpSet(Operation *op);
        VOpSet(OpList &list);

        virtual bool boolean() const;
        virtual double num() const;
        virtual std::wstring str() const;
        virtual const OpList &opset() const;

      private:
        OpList ops;
    };

    inline std::wostream &operator <<(std::wostream &out, const VObjectPtr &object) {
        out << object->str();
        return out;
    }

}

#endif//THEORETIC_VOBJECT_H