/*
 * 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.
 */

#include "apache/das/RefCountingPointer.h"
#include "apache/das/rdb/Statement.h"
#include "apache/das/rdb/Connection.h"
#include "apache/das/rdb/ReadCommandImpl.h"
#include "apache/das/Command.h"
#include "apache/das/CommandPtr.h"

namespace apache {
	namespace das {

template<class T>
void RefCountingPointer<T>::init()
{
    if (pointee == 0) return;
    pointee->addRef(this);
}

template<class T>
/*SDO_API*/ RefCountingPointer<T>::RefCountingPointer(T* realPtr, bool objectOwner)
:pointee(realPtr)
{
	this->objectOwner = objectOwner;
    init();
}

template<class T>
/*SDO_API*/ RefCountingPointer<T>::RefCountingPointer(T& realPtr, bool objectOwner)
:pointee(&realPtr)
{
	this->objectOwner = objectOwner;
    init();
}

template<class T>
RefCountingPointer<T>::RefCountingPointer(const RefCountingPointer<T>& rhs, bool objectOwner)
: pointee(rhs.pointee)
{
	this->objectOwner = objectOwner;
    init();
}

template<class T>
/*SDO_API*/ RefCountingPointer<T>::~RefCountingPointer(void)
{
    if (pointee)pointee->releaseRef(this);
}

template<class T>
/*SDO_API*/ RefCountingPointer<T>& RefCountingPointer<T>::operator=(const RefCountingPointer<T>& rhs)
{
    if (pointee != rhs.pointee)
    {
        T *oldP = pointee;
        pointee = rhs.pointee;
        init();
        if (oldP) oldP->releaseRef(this);
    }
    return *this;
}

//RefCountingPointer& operator=(const RefCountingObject<T>& rhs)
//{
//    if (pointee != &rhs)
//    {
//        T *oldP = pointee;
//        pointee = &pointee;
//        init();
//        if (oldP) oldP->releaseRef(this);
//    }
//    return *this;
//}
//
//RefCountingPointer& operator=(const RefCountingObject<T>* rhs)
//{
//    if (pointee != rhs)
//    {
//        T *oldP = pointee;
//        pointee = rhs;
//        init();
//        if (oldP) oldP->releaseRef(this);
//    }
//    return *this;
//}

template<class T>
/*SDO_API*/ bool RefCountingPointer<T>::operator!() const
{
    return (pointee == 0);
}

template<class T>
/*SDO_API*/ bool RefCountingPointer<T>::operator==(RefCountingPointer<T>& test) const
{
    return (pointee == test.pointee);
}

template<class T>
/*SDO_API*/ T* RefCountingPointer<T>::operator->() const 
{
    if (pointee == 0)
        throw DASNullPointerException();
    return pointee;
}

template<class T>
/*SDO_API*/ T& RefCountingPointer<T>::operator*() const
{
    return *pointee;
}

template<class T>
bool RefCountingPointer<T>::isObjectOwner(void) const {
	return objectOwner;
}

       
        // officially, there is nothing here- but if I dont use the overrides in
        // the templates, then they dont get generated.
        void Test2()
        {
            
#if defined(WIN32) || defined (_WINDOWS)
			{
            /* 1) construct */
			rdb::Connection* conn = new rdb::Connection("","","");
            rdb::StatementPtr fptr = conn->createStatement();
			rdb::StatementPtr a(new rdb::Statement(*conn, 0));
			rdb::Statement& st = *(new rdb::Statement(*conn, 0));
			rdb::StatementPtr* c = new rdb::StatementPtr(st);
			c->isObjectOwner();
            
            /* 2) use the & operator= */
            fptr = conn->createStatement();
            
            /* 3) copy */
            rdb::StatementPtr fptr2 = fptr;
            
            /* 4) use the == and ! */
            if (fptr2 == fptr || !fptr){}
            
            /* 5) Use the T*  and  * */
            rdb::Statement* dmsf = fptr;
            rdb::Statement& dmsr = *fptr;
            
            /* 1) construct */
            rdb::StatementPtr dfptr(fptr);
            
            /* 3) copy */
            rdb::StatementPtr dfptr2 = dfptr;
            
            /* 2) use the & operator= */
            dfptr = dfptr2;
            
            /* 4) use the == and ! */
            if (dfptr2 == dfptr || !dfptr){}
            
            /* 5) Use the T*  and  * */
            rdb::Statement* ddmsf = dfptr;
            rdb::Statement& ddmsr = *dfptr;
            
            /* 6) Use the -> */
			dfptr->close(); 
            
            /* and again to catch the = */
			fptr = conn->createStatement();
			delete fptr2;

		}
			{
			/* 1) construct */
			rdb::Connection* conn = new rdb::Connection("","","");
            rdb::StatementPtr fptr = conn->createStatement();
			rdb::ResultSetPtr a(new rdb::ResultSet(fptr));
			rdb::ResultSetPtr b(new rdb::ResultSet(fptr));
			rdb::ResultSet& st = *(new rdb::ResultSet(fptr));
			rdb::ResultSetPtr* c = new rdb::ResultSetPtr(st);
			c->isObjectOwner();
            /* 2) use the & operator= */
            a = b;
            
            /* 3) copy */
            rdb::ResultSetPtr d = a;

			a = new rdb::ResultSet(fptr);
			a = *(new rdb::ResultSet(fptr));
            
            /* 4) use the == and ! */
            if (a == b || !b){}
            
            /* 5) Use the T*  and  * */
            rdb::ResultSet* dmsf = a;
            rdb::ResultSet& dmsr = *b;

			/* 6) Use the -> */
			a->getStatement(); 
            
            /* and again to catch the = */
			delete c;
            
         
			}
        
			{
			/* 1) construct */
			rdb::Connection* conn = new rdb::Connection("","","");
            CommandPtr fptr = *(new CommandPtr());
			CommandPtr a(*(new rdb::ReadCommandImpl(*(new rdb::DASImpl(*conn)), "")));
			CommandPtr b(*(new rdb::ReadCommandImpl(*(new rdb::DASImpl(*conn)), "")));
			Command& st = *(new rdb::ReadCommandImpl(*(new rdb::DASImpl(*conn)), ""));
			CommandPtr* c = new CommandPtr(st);
			c->isObjectOwner();
            /* 2) use the & operator= */
            a = b;
            
            /* 3) copy */
            CommandPtr d = a;

			a = new rdb::ReadCommandImpl(*(new rdb::DASImpl(*conn)), "");
			a = *(new rdb::ReadCommandImpl(*(new rdb::DASImpl(*conn)), ""));
            
            /* 4) use the == and ! */
            if (a == b || !b){}
            
            /* 5) Use the T*  and  * */
            CommandObject* dmsf = a;
            CommandObject& dmsr = *b;

			/* 6) Use the -> */
			a->executeQuery(); 
            
            /* and again to catch the = */
			delete c;
            
         
			}
            
#endif
            
        }

	};
};
