/*
WARNING: This header should never be directly included. Include factory.h instead.

Author:		Chris Kaynor (chris@kaynor.net)
Edited By:	

Description:		Provides the code for the template class Factory.
		
Usage:		See factory.h for usage information and function and class comments.

Requirements:	See factory.h for requirements.
		
Last Edited:	May 20th, 2008
*/
/*
Copyright 2008 Chris Kaynor

This file is part of kLibrary.

kLibrary is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or(at your option) any later version.

kLibrary 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License.
*/

#ifndef KLIBRARY_FACTORY_FACTORY_CODE_H
#define KLIBRARY_FACTORY_FACTORY_CODE_H

#include "factory.h"

namespace kLibrary
{
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	inline Factory<itemType, paramType, nameType, removeAutomatically>::Factory(void)
	{
		//Nothing needs to be done to initialize the class. All initialization is taken care of automatically.
	}
	
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	inline Factory<itemType, paramType, nameType, removeAutomatically>::~Factory(void)
	{
		//Remove any and all objects still loaded to avoid memory leaks.
		for (stdext::hash_map<nameType, _storageClass*>::iterator x = _items.begin(); x != _items.end(); x++)
		{
			delete (x->second);
		}
	}
	
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	itemType* Factory<itemType, paramType, nameType, removeAutomatically>::load(const nameType& name, paramType param)
	{
		//Search for the item in our memory.
		stdext::hash_map<nameType, _storageClass*>::iterator found = _items.find(name);
		
		//If it was found
		if (found != _items.end())
		{
			//Increment the usage count
			(*found->second)++;
			
			//and return the copy in memory.
			return *(found->second);
		} //Otherwise,
		
		//create a new instance of the object, passing in the parameter and the name,
		_storageClass *newItem = new _storageClass(name, param);
		
		//Increment the usage count.
		(*newItem)++;
		
		//add it into our array,
		_itemStoragePair tItem(name, newItem);
		_items.insert(tItem);
		
		//and finally return it.
		return *newItem;
	}

	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	inline void Factory<itemType, paramType, nameType, removeAutomatically>::unload(const itemType* object)
	{
		//Convert the object passed in into its name and call the other unload function.
		unload(object->getName());
	}

	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	void Factory<itemType, paramType, nameType, removeAutomatically>::unload(const nameType& name)
	{
		//Search for the item in our memory.
		stdext::hash_map<std::string, _storageClass*>::iterator found = _items.find(name);
		//If it was not found
		if (found == _items.end())
		{
			//do nothing.
			return;
		} //Otherwise,
		
		//get the instance
		_storageClass& tItem = *(found->second);
		
		//and decerment the count.
		tItem--;
		
		//If the class is set to automatically unload
		if (removeAutomatically)
			//and the item is no longer in use
			if (tItem == 0)
			{
				//Clear the memory,
				delete (found->second);
				//clear the pointer,
				found->second = 0;
				//and remove it from the list.
				_items.erase(found);
			}
	}
	
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	inline void Factory<itemType, paramType, nameType, removeAutomatically>::deleteItem(const itemType* object)
	{
		//Convert the object passed in into its name and call the other deleteItem function.
		deleteItem(object->getName());
	}
	
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	void Factory<itemType, paramType, nameType, removeAutomatically>::deleteItem(const nameType& name)
	{
		//Search for the item in our memory.
		stdext::hash_map<std::string, _storageClass*>::iterator found = _items.find(name);
		//If it was not found
		if (found == _items.end())
		{
			//do nothing.
			return;
		} //Otherwise,
		
		//clear the memory,
		delete (found->second);
		//clear the pointer,
		found->second = 0;
		//and remove it from the list.
		_items.erase(found);
	}
	
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	inline void Factory<itemType, paramType, nameType, removeAutomatically>::renameItem(const itemType* object, const nameType& newName)
	{
		//Convert the object passed in into its name and call the other deleteItem function.
		renameItem(object->getName());
	}
	
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	void Factory<itemType, paramType, nameType, removeAutomatically>::renameItem(const nameType& name, const nameType& newName)
	{
		//Search for the item in our memory.
		stdext::hash_map<std::string, _storageClass*>::iterator found = _items.find(name);
		//If it was not found
		if (found == _items.end())
		{
			//do nothing.
			return;
		} //Otherwise,
		
		//Get the item,
		_itemStoragePair newRef = _itemStoragePair(newName, (found->second));
		
		//remove the old reference from the list,
		_items.erase(found);
		
		//and insert the new reference.
		_items.insert(newRef);
	}
		
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	inline int Factory<itemType, paramType, nameType, removeAutomatically>::getUsage(const itemType* object)
	{
		//Convert the object passed in into its name and call the other getUsage function.
		return getUsage(object->getName());
	}
	
	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	int Factory<itemType, paramType, nameType, removeAutomatically>::getUsage(const nameType& name)
	{
		//Search for the item in our memory.
		stdext::hash_map<std::string, _storageClass*>::iterator found = _items.find(name);
		//If it was not found
		if (found == _items.end())
		{
			//do nothing.
			return 0;
		} //Otherwise,
		
		//Get the item,
		_storageClass& tItem = *(found->second);
		
		//and return the usage.
		return tItem;
	}

	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	typename Factory<itemType, paramType, nameType, removeAutomatically>::_itemStorage::iterator Factory<itemType, paramType, nameType, removeAutomatically>::getBegin(void)
	{
		return _items.begin();
	}

	template<class itemType, class paramType, class nameType, bool removeAutomatically>
	typename Factory<itemType, paramType, nameType, removeAutomatically>::_itemStorage::iterator Factory<itemType, paramType, nameType, removeAutomatically>::getEnd(void)
	{
		return _items.end();
	}
}

#endif //KLIBRARY_FACTORY_FACTORY_CODE_H