#pragma once

#include "Text.h"
#include "Array.h"
#include "ReferenceCounter.h"

namespace Framework
{
    namespace JSON
    {
        enum JSONType
        {
            NULL_,
            BOOLEAN,
            NUMBER,
            STRING,
            ARRAY,
            OBJECT
        };

        class JSONArray;
        class JSONObject;

        class JSONValue : public virtual ReferenceCounter
        {
        private:
            JSONType type;

        protected:
            __declspec( dllexport ) JSONValue( JSONType type );

        public:
            __declspec( dllexport ) JSONValue();
            __declspec( dllexport ) virtual ~JSONValue();
            __declspec( dllexport ) JSONType getType() const;
            __declspec( dllexport ) virtual Text toString() const;
        };

        class JSONBool : public JSONValue
        {
        private:
            bool b;

        public: 
            __declspec( dllexport ) JSONBool( bool b );

            __declspec( dllexport ) bool getBool() const;
            __declspec( dllexport ) Text toString() const override;
        };

        class JSONNumber : public JSONValue
        {
        private:
            double number;

        public:
            __declspec( dllexport ) JSONNumber( double num );

            __declspec( dllexport ) double getNumber() const;
            __declspec( dllexport ) Text toString() const override;
        };

        class JSONString : public JSONValue
        {
        private:
            Text string;

        public:
            __declspec( dllexport ) JSONString( Text string );

            __declspec( dllexport ) Text getString() const;
            __declspec( dllexport ) Text toString() const override;
        };

        class JSONArray : public JSONValue
        {
        private:
            RCArray< JSONValue > *array;

        public:
            __declspec( dllexport ) JSONArray();
            __declspec( dllexport ) JSONArray( Text string );
            __declspec( dllexport ) JSONArray( const JSONArray &arr );
            __declspec( dllexport ) ~JSONArray();

            __declspec( dllexport ) JSONArray &operator=( const JSONArray &arr );

            __declspec( dllexport ) void addValue( JSONValue *value );
            __declspec( dllexport ) JSONValue *getValue( int i ) const;
            __declspec( dllexport ) int getLength() const;

            __declspec( dllexport ) Text toString() const override;
        };

        class JSONObject : public JSONValue
        {
        private:
            Array< Text > *fields;
            RCArray< JSONValue > *values;

        public:
            __declspec( dllexport ) JSONObject();
            __declspec( dllexport ) JSONObject( Text string );
            __declspec( dllexport ) JSONObject( const JSONObject &obj );
            __declspec( dllexport ) ~JSONObject();

            __declspec( dllexport ) JSONObject &operator=( const JSONObject &obj );

            __declspec( dllexport ) bool addValue( Text field, JSONValue *value );
            __declspec( dllexport ) bool removeValue( Text field );
            __declspec( dllexport ) bool hasValue( Text field );
            __declspec( dllexport ) JSONValue *getValue( Text field );
            __declspec( dllexport ) Iterator< Text > getFields();
            __declspec( dllexport ) Iterator< JSONValue* > getValues();
            __declspec( dllexport ) int getFieldCount() const;

            __declspec( dllexport ) Text toString() const override;
        };

        __declspec( dllexport ) JSONValue *loadJSONFromFile( Text path );

        namespace Parser
        {
            __declspec( dllexport ) int findObjectEndInArray( const char *str );
            __declspec( dllexport ) Text removeWhitespace( const char *str );
            __declspec( dllexport ) JSONValue *getValue( const char *str );
            __declspec( dllexport ) int findFieldEndInObject( const char *str );
            __declspec( dllexport ) int findValueEndInObject( const char *str );
        };
    }
}