/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _LOG4CXX_HELPERS_OBJECT_H
#define _LOG4CXX_HELPERS_OBJECT_H

#include <log4cxx/logstring.h>
#include <log4cxx/helpers/class.h>
#include <log4cxx/helpers/objectptr.h>
#include <log4cxx/helpers/classregistration.h>


#define DECLARE_ABSTRACT_LOG4CXX_OBJECT(object)\
public:\
class Clazz##object : public helpers::Class\
{\
public:\
        Clazz##object() : helpers::Class() {}\
        virtual ~Clazz##object() {}\
        virtual log4cxx::LogString getName() const { return LOG4CXX_STR(#object); } \
};\
virtual const helpers::Class& getClass() const;\
static const helpers::Class& getStaticClass(); \
static const log4cxx::helpers::ClassRegistration& registerClass();

#define DECLARE_LOG4CXX_OBJECT(object)\
public:\
class Clazz##object : public helpers::Class\
{\
public:\
        Clazz##object() : helpers::Class() {}\
        virtual ~Clazz##object() {}\
        virtual log4cxx::LogString getName() const { return LOG4CXX_STR(#object); } \
        virtual helpers::ObjectPtr newInstance() const\
        {\
                return new object();\
        }\
};\
virtual const helpers::Class& getClass() const;\
static const helpers::Class& getStaticClass(); \
static const log4cxx::helpers::ClassRegistration& registerClass();

#define DECLARE_LOG4CXX_OBJECT_WITH_CUSTOM_CLASS(object, class)\
public:\
virtual const helpers::Class& getClass() const;\
static const helpers::Class& getStaticClass();\
static const log4cxx::helpers::ClassRegistration&  registerClass();

#define IMPLEMENT_LOG4CXX_OBJECT(object)\
const ::log4cxx::helpers::Class& object::getClass() const { return getStaticClass(); }\
const ::log4cxx::helpers::Class& object::getStaticClass() { \
   static Clazz##object theClass;                         \
   return theClass;                                       \
}                                                                      \
const log4cxx::helpers::ClassRegistration& object::registerClass() {   \
    static log4cxx::helpers::ClassRegistration classReg(object::getStaticClass); \
    return classReg; \
}\
namespace log4cxx { namespace classes { \
const ::log4cxx::helpers::ClassRegistration& object##Registration = object::registerClass(); \
} }


#define IMPLEMENT_LOG4CXX_OBJECT_WITH_CUSTOM_CLASS(object, class)\
const log4cxx::helpers::Class& object::getClass() const { return getStaticClass(); }\
const log4cxx::helpers::Class& object::getStaticClass() { \
   static class theClass;                                 \
   return theClass;                                       \
}                                                         \
const log4cxx::helpers::ClassRegistration& object::registerClass() {   \
    static log4cxx::helpers::ClassRegistration classReg(object::getStaticClass); \
    return classReg; \
}\
namespace log4cxx { namespace classes { \
const log4cxx::helpers::ClassRegistration& object##Registration = object::registerClass(); \
} }

namespace log4cxx
{
        class AppenderSkeleton;
        class Logger;

        namespace helpers
        {
            class Pool;

                /** base class for java-like objects.*/
                class LOG4CXX_EXPORT Object
                {
                public:
                        DECLARE_ABSTRACT_LOG4CXX_OBJECT(Object)
                        virtual ~Object() {}
                        virtual void addRef() const = 0;
                        virtual void releaseRef() const = 0;
                        virtual bool instanceof(const Class& clazz) const = 0;
                        virtual const void * cast(const Class& clazz) const = 0;
                };
            LOG4CXX_PTR_DEF(Object);
        }
}

#define BEGIN_LOG4CXX_CAST_MAP()\
const void * cast(const helpers::Class& clazz) const\
{\
        const void * object = 0;\
        if (&clazz == &helpers::Object::getStaticClass()) return (const helpers::Object *)this;

#define END_LOG4CXX_CAST_MAP()\
        return object;\
}\
bool instanceof(const helpers::Class& clazz) const\
{ return cast(clazz) != 0; }

#define LOG4CXX_CAST_ENTRY(Interface)\
if (&clazz == &Interface::getStaticClass()) return (const Interface *)this;

#define LOG4CXX_CAST_ENTRY2(Interface, interface2)\
if (&clazz == &Interface::getStaticClass()) return (Interface *)(interface2 *)this;

#define LOG4CXX_CAST_ENTRY_CHAIN(Interface)\
object = Interface::cast(clazz);\
if (object != 0) return object;

#endif //_LOG4CXX_HELPERS_OBJECT_H
