/*
 * 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/RefCountingObject.h"
#include "apache/das/rdb/Connection.h"
#include "apache/das/rdb/Statement.h"
#include "apache/das/rdb/ReadCommandImpl.h"
#include "apache/das/Command.h"
#include "apache/das/CommandPtr.h"

namespace apache {
	namespace das {

template <class T>
RefCountingObject<T>::RefCountingObject()
{
	refCount = 0;
	freed = false;
    refPtrs = new std::list<RefCountingPointer<T>*>();
}

template <class T>
RefCountingObject<T>::RefCountingObject(const RefCountingObject<T>& rc)
{
	refCount = 0;
	freed = false;
    refPtrs = new std::list<RefCountingPointer<T>*>();
}
template <class T>
T& RefCountingObject<T>::operator=(const T& rc)
{
    return *this;
}
template <class T>
RefCountingObject<T>::~RefCountingObject()
{
	if (!freed) {
		throw std::logic_error("Function RefCountingObjec<T>::free() must be invoked before deleting this object!");
	}

	delete refPtrs;

}

template <class T>
void RefCountingObject<T>::free(void) {
	std::list<RefCountingPointer<T>*>::iterator it;
	
	while (!refPtrs->empty()) {
		RefCountingPointer<T>* aux = *refPtrs->begin();
		refPtrs->erase(refPtrs->begin());
		*aux = 0;

	}

	freed = true;

}

template <class T>
void RefCountingObject<T>::addRef(RefCountingPointer<T>* refPtr)

{
	if ((*refPtr).isObjectOwner()) {
		refCount++;
	}

	refPtrs->push_front(refPtr);

}
template <class T>
void RefCountingObject<T>::releaseRef(RefCountingPointer<T>* refPtr)
{
	std::list<RefCountingPointer<T>*>::iterator it;
	bool found = false;

	for (it = refPtrs->begin() ; it != refPtrs->end() ; it++) {

		if (refPtr == *it) {
			found = true;
			break;

		}

	}
	
	if (found) {

		if ((*it)->isObjectOwner()) {
			refCount--;
		}

		refPtrs->erase(it);

		if (refCount == 0) {
			delete this;
		}

	}

}

template <class T>
std::ostream& RefCountingObject<T>::printSelf(std::ostream &os) 
{
	os << "RefCountingObject: reference count = " << refPtrs->size() << std::endl;
    return os;
}

        // officially, there is nothing here- but if I dont use the overrides in
        // the templates, then they dont get generated.
        void Test ()
        {
            
#if defined(WIN32) || defined (_WINDOWS)
            /* 1) construct */
			    
			rdb::Connection conn("", "", "");
			/*rdb::Connection* conn1 = new rdb::Connection("", "", "");
			delete conn1;*/
            rdb::StatementObject* fptr = new rdb::StatementObject();
			rdb::StatementObject statement;
			rdb::Statement* s = new rdb::Statement(conn, 0);
			delete s;
			rdb::StatementObject* fptr2 = new rdb::StatementObject(statement);
			fptr->releaseRef(0);
			fptr->addRef(0);
			delete fptr;

			rdb::StatementPtr stmt = conn.createStatement();
			rdb::ResultSetObject* rs1 = new rdb::ResultSetObject();
            rdb::ResultSetObject rs2;
			delete rs1;
			rs2.releaseRef(0);
			rs2.addRef(0);
			{
				CommandPtr stmt = *(new CommandPtr(new rdb::ReadCommandImpl(*(new rdb::DASImpl(conn)), "")));
				CommandObject* rs1 = new CommandObject();
				CommandObject rs2;
				delete rs1;
				rs2.releaseRef(0);
				rs2.addRef(0);
			}
			
            ///* Use the T*  and  * */
            //DataObject* dof = dptr;
            //DataObject& dor = *dptr;
            //
            //if (dptr2 == dptr || !dptr){}
            //
            //
            //ChangeSummaryPtr cptr = dptr->getChangeSummary();
            //cptr = dptr->getChangeSummary();
            //ChangeSummaryPtr cptr2 = cptr;
            //
            //ChangeSummary* cof = cptr;
            //ChangeSummary& cop = *cptr;
            //
            //
            //if (cptr2 == cptr || !cptr){}
            //
            //cptr->endLogging();
            //
            //SequencePtr sptr = dptr->getSequence();
            //sptr = dptr->getSequence();
            //SequencePtr sptr2 = sptr;
            //
            //Sequence* sof = sptr;
            //Sequence& sop = *sptr;
            //
            //
            //if (sptr2 == sptr || !sptr){}
            //
            //sptr->getBooleanValue(0);
            //
            //
            //// Generate code for XMLDocumentPtr
            //XMLDocumentPtr xmldocptr1 = 0;
            //XMLDocumentPtr xmldocptr2 = xmldocptr1;
            //xmldocptr1 = xmldocptr2;
            //if (xmldocptr2 == xmldocptr1 || !xmldocptr1){}
            //XMLDocument* xmldocp = xmldocptr1;
            //XMLDocument& xmldocref = *xmldocptr2;
            //xmldocptr1->getEncoding();

            //// Generate code for XSDHelperPtr
            //XSDHelperPtr xsdhptr1 = 0;
            //XSDHelperPtr xsdhptr2 = xsdhptr1;
            //xsdhptr1 = xsdhptr2;
            //if (xsdhptr2 == xsdhptr1 || !xsdhptr1){}
            //XSDHelper* xsdhp = xsdhptr1;
            //XSDHelper& xsdhref = *xsdhptr2;
            //xsdhptr1->define("dummy");

            //// Generate code for XMLHelperPtr
            //XMLHelperPtr xmlhptr1 = 0;
            //XMLHelperPtr xmlhptr2 = xmlhptr1;
            //xmlhptr1 = xmlhptr2;
            //if (xmlhptr2 == xmlhptr1 || !xmlhptr1){}
            //XMLHelper* xmlhp = xmlhptr1;
            //XMLHelper& xmlhref = *xmlhptr2;
            //xmlhptr1->load("dummy");

            //// Generate code for DataGraphPtr
            //DataGraphPtr dgptr1 = 0;
            //DataGraphPtr dgptr2 = dgptr1;
            //dgptr1 = dgptr2;
            //if (dgptr2 == dgptr1 || !dgptr1){}
            //DataGraph* dghp = dgptr1;
            //DataGraph& dgref = *dgptr2;
            //dgptr1->getRootObject();

#endif
            
        }

	};
};
