//
//   File : kvi_garbage.cpp
//   Creation date : Mon Dec  3 16:49:15 2001 GMT by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net)
//
//   This program is FREE software. You can redistribute it and/or
//   modify it under the terms of the GNU General Public License
//   as published by the Free Software Foundation; either version 2
//   of the License, or (at your opinion) any later version.
//
//   This program is distributed in the HOPE that it will be USEFUL,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//   See the GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#define __KVILIB__



#include "kvi_garbage.h"

#include <tqvariant.h>

KviGarbageCollector::KviGarbageCollector()
: TQObject(0)
{
	m_pGarbageList = 0;
	m_pCleanupTimer = 0;
	m_bForceCleanupNow = false;
}

KviGarbageCollector::~KviGarbageCollector()
{
	m_bForceCleanupNow = true;
	cleanup();
}

void KviGarbageCollector::collect(TQObject * g)
{
	if(!m_pGarbageList)
	{
		m_pGarbageList = new KviPointerList<TQObject>;
		m_pGarbageList->setAutoDelete(true);
	}
	//tqDebug("COLLECTING GARBAGE %s",g->className());
	m_pGarbageList->append(g);
//	tqDebug("Registering garbage object %d (%s:%s)",g,g->className(),g->name());
	connect(g,TQT_SIGNAL(destroyed()),this,TQT_SLOT(garbageSuicide()));
	triggerCleanup(0);
}

void KviGarbageCollector::garbageSuicide()
{
	if(!m_pGarbageList)
	{
		tqDebug("Ops... garbage suicide while no garbage list");
		return;
	}
	int idx = m_pGarbageList->findRef(TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>(sender())));
	if(idx == -1)
	{
		tqDebug("Ops... unregistered garbage suicide");
		return;
	}
	m_pGarbageList->removeRef(TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>(sender())));
	if(m_pGarbageList->isEmpty())
	{
		cleanup();
	}
}

void KviGarbageCollector::triggerCleanup(int iTimeout)
{
	//tqDebug("TRIGGERING CLEANUP AFTER %d msecs",iTimeout);
	if(m_pCleanupTimer)
	{
		m_pCleanupTimer->stop();
	} else {
		m_pCleanupTimer = new TQTimer(this);
		connect(m_pCleanupTimer,TQT_SIGNAL(timeout()),this,TQT_SLOT(cleanup()));
	}
	m_pCleanupTimer->start(iTimeout);
}

void KviGarbageCollector::cleanup()
{
	//tqDebug("CLEANUP CALLED !");
	if(m_pGarbageList)
	{
		//tqDebug("SOME GARBAGE TO DELETE");
		KviPointerList<TQObject> dying;
		dying.setAutoDelete(false);
		for(TQObject * o = m_pGarbageList->first();o;o = m_pGarbageList->next())
		{
			//tqDebug("CHECKING GARBAGE CLASS %s",o->className());
			bool bDeleteIt = m_bForceCleanupNow;
			if(!bDeleteIt)
			{
				//tqDebug("CLEANUP NOT FORCED");
				TQVariant v = o->property("blockingDelete");
				if(v.isValid())
				{
					//tqDebug("HAS A VALID VARIANT!");
//					tqDebug("[Garbage collector]: garbage has a blockingDelete property");
					bDeleteIt = !(v.toBool());
//					if(!bDeleteIt)tqDebug("And doesn't want to be delete now!");
				} else bDeleteIt = true; // must be deleted
			}
			if(bDeleteIt)dying.append(o);
		}

		for(TQObject * o2 = dying.first();o2;o2 = dying.next())
		{
			//tqDebug("KILLING GARBAGE CLASS %s",o2->className());
			disconnect(o2,TQT_SIGNAL(destroyed()),this,TQT_SLOT(garbageSuicide()));
			m_pGarbageList->removeRef(o2);
		}

		if(m_pGarbageList->isEmpty())
		{
			delete m_pGarbageList;
			m_pGarbageList = 0;
		}
	}

	if(m_pGarbageList)
	{
//		tqDebug("[Garbage collector cleanup]: Some stuff left to be deleted, will retry in a while");
		// something left to be destroyed
		if(m_bForceCleanupNow)tqDebug("[Garbage collector]: Ops...I've left some undeleted stuff!");
		triggerCleanup(5000); // retry in 5 sec
	} else {
//		tqDebug("[Garbage collector cleanup]: Completed");
		// nothing left to delete
		if(m_pCleanupTimer)
		{
			delete m_pCleanupTimer;
			m_pCleanupTimer = 0;
		}
	}
}