
//File Dictionary.h - contains definition of Dictionary class

#ifndef _dictionary_h
#define _dictionary_h

#include "Category.h"
#include "Key.h"

template <class C, class K, class V> //C=Category, K=Key, V=Value
class Dictionary {

public:
	Dictionary(){
	}
	~Dictionary(void){
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter)
			delete &(*iter);
	}
	Dictionary<C,K,V> & add(C & category, K & key, V & value){
		bool categoryExists = false;

		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			//cout << "Current Category: " << iter->getCategory() << endl;
			if(iter->getCategory() == category){
				iter->addKey(*(new Key<K,V>(key, value)));
				categoryExists = true;
			}
		}

		if(categoryExists == false){
			Category<C,Key<K,V>> * c = new Category<C,Key<K,V>>(category);
			Key<K,V> * aKey = new Key<K,V>(key, value);
			c->addKey(*aKey);
			categorySet.add(*c);
			//cout << "New category created: " << c->getCategory() << endl;
		}

		return *this;
	}
	Dictionary<C,K,V> & removeKey(C & category, K & key){
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			if(iter->getCategory() == category){
				iter->removeKey(key);
				if(iter->isEmpty()){
					categorySet.remove(*iter);
					delete &(*iter);
				}
			}
		}

		return *this;
	}
	bool includesCategory(C & category) const {
		return categorySet.includes(category);		//== operator of category class is used in the Set's includes function
	}
	bool includesKey(C & category, K & key) /*const*/ {		//Had to remove const for categorySet.begin() to work, as 'this' in the Set class
		//would have been const, but the SetIterator constructor can't use the const variable
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			if(iter->getCategory() == category){
				//Set<Key<K,V>> keys = iter->getKeys();
				for(SetIterator<Key<K,V>> keyIter=iter->getKeys().begin(); keyIter!=iter->getKeys().end(); ++keyIter){
					if(key == *(keyIter->getKey()))
						return true;
				}
			}
		}
		return false;
	}
	bool includesValue(V & value) /*const*/ {
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			//if(iter->getCategory() == category){
				//Set<Key<K,V>> keys = iter->getKeys();
				for(SetIterator<Key<K,V>> keyIter=iter->getKeys().begin(); keyIter!=iter->getKeys().end(); ++keyIter){
					if(value == *(keyIter->getValue()))
						return true;
				}
			//}
		}
	}
	V * lookup(C& category, K & key){
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			if(iter->getCategory() == category){
				//Set<Key<K,V>> keys = iter->getKeys();
				for(SetIterator<Key<K,V>> keyIter=iter->getKeys().begin(); keyIter!=iter->getKeys().end(); ++keyIter){
					if(key == *(keyIter->getKey()))
						return keyIter->getValue();
				}
			}
		}
		return NULL;
	}
	int size()const {
		int total = 0;
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter)
			total += iter->size();
		return total;
	}
	Set<C> categories(){
		someCategories.clear();
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter)
			someCategories.add(iter->getCategory());
		return someCategories;
	}
	Set<K> keys(C & category){
		someKeys.clear();
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			if(iter->getCategory() == category){
				for(SetIterator<Key<K,V>> keyIter=iter->getKeys().begin(); keyIter!=iter->getKeys().end(); ++keyIter){
					someKeys.add(*(keyIter->getKey()));
				}
			}
		}
		return someKeys;
	}
	Set<V> values(){
		someValues.clear();
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			for(SetIterator<Key<K,V>> keyIter=iter->getKeys().begin(); keyIter!=iter->getKeys().end(); ++keyIter){
				someValues.add(*(keyIter->getValue()));
			}
		}
		return someValues;
	}
	void printOn(ostream & ostr){
		for(SetIterator<Category<C,Key<K,V>>> iter=categorySet.begin(); iter!=categorySet.end(); ++iter){
			ostr << *iter;
		}
	}

private:
	Set<Category<C,Key<K,V>>> categorySet;
	Set<C> someCategories;
	Set<K> someKeys;
	Set<V> someValues;
};

template <class C, class K, class V>
ostream & operator<<(ostream & ostr, /*const*/ Dictionary<C,K,V> & dic) {
     dic.printOn(ostr);
     return ostr;
}

#endif