#include <QApplication>
#include "cdpultwindow.h"

template <typename Key, typename T>
class PIHash {
	//template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIHash<Key1, T1> & v);
	//template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIHash<Key1, T1> & v);
public:
	PIHash() {;}
	PIHash(const PIHash<Key, T> & other) {*this = other;}
	virtual ~PIHash() {;}

	PIHash<Key, T> & operator =(const PIHash<Key, T> & other) {
		if (this == &other) return *this;
		clear();
		pih_content = other.pih_content;
		return *this;
	}

	typedef T mapped_type;
	typedef Key key_type;
	typedef PIPair<Key, T> value_type;
/*
	class iterator {
		friend class PIHash<Key, T>;
	private:
		iterator(const PIHash<Key, T> * v, ssize_t p): parent(v), pos(p) {}
		const PIHash<Key, T> * parent;
		ssize_t pos;
	public:
		iterator(): parent(0), pos(0) {}
		const Key & key() const {return const_cast<PIHash<Key, T> * >(parent)->_key(pos);}
		T & value() {return const_cast<PIHash<Key, T> * >(parent)->_value(pos);}
		void operator ++() {++pos;}
		void operator ++(int) {++pos;}
		void operator --() {--pos;}
		void operator --(int) {--pos;}
		bool operator ==(const iterator & it) const {return (pos == it.pos);}
		bool operator !=(const iterator & it) const {return (pos != it.pos);}
	};

	class reverse_iterator {
		friend class PIHash<Key, T>;
	private:
		reverse_iterator(const PIHash<Key, T> * v, ssize_t p): parent(v), pos(p) {}
		const PIHash<Key, T> * parent;
		ssize_t pos;
	public:
		reverse_iterator(): parent(0), pos(0) {}
		const Key & key() const {return const_cast<PIHash<Key, T> * >(parent)->_key(pos);}
		T & value() const {return const_cast<PIHash<Key, T> * >(parent)->_value(pos);}
		void operator ++() {--pos;}
		void operator ++(int) {--pos;}
		void operator --() {++pos;}
		void operator --(int) {++pos;}
		bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
		bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
	};
*/
	class const_iterator {
		friend class PIHash<Key, T>;
	private:
		const_iterator(const PIHash<Key, T> * v, ssize_t p): parent(v), pos(p), bpos(0) {
			if (pos == 0) {
				pos = -1;
				nextPos();
			}
		}
		void nextPos() {
			while (++pos < parent->pih_content.size_s()) {
				if (!parent->pih_content[pos].isEmpty())
					return;
			}
		}
		const PIHash<Key, T> * parent;
		ssize_t pos, bpos;
	public:
		const_iterator(): parent(0), pos(0) {}
		//const value_type operator *() const {return parent->_pair(pos);}
		//const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
		const Key & key() const {return const_cast<PIHash<Key, T> * >(parent)->pih_content[pos][bpos].key;}
		const T & value() const {return const_cast<PIHash<Key, T> * >(parent)->pih_content[pos][bpos].value;}
		void operator ++() {
			if (pos < parent->pih_content.size_s()) {
				if (bpos >= parent->pih_content[pos].size_s() - 1) {
					bpos = 0;
					nextPos();
				} else
					++bpos;
			} else {
				bpos = 0;
				++pos;
			}
			printf("  ++: %d %d\n", pos, bpos);
		}
		//void operator ++(int) {++pos;}
		void operator --() {
			--pos;
		}
		//void operator --(int) {--pos;}
		bool operator ==(const const_iterator & it) const {return (pos == it.pos && bpos == it.bpos);}
		bool operator !=(const const_iterator & it) const {return !(*this == it);}
		mutable value_type cval;
	};
/*
	class const_reverse_iterator {
		friend class PIHash<Key, T>;
	private:
		const_reverse_iterator(const PIHash<Key, T> * v, ssize_t p): parent(v), pos(p) {}
		const PIHash<Key, T> * parent;
		ssize_t pos;
	public:
		const_reverse_iterator(): parent(0), pos(0) {}
		const value_type operator *() const {return parent->_pair(pos);}
		const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
		void operator ++() {--pos;}
		void operator ++(int) {--pos;}
		void operator --() {++pos;}
		void operator --(int) {++pos;}
		bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
		bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
		mutable value_type cval;
	};
*/
	//iterator begin() {return iterator(this, 0);}
	//iterator end() {return iterator(this, size());}
	const_iterator begin() const {return const_iterator(this, 0);}
	const_iterator end() const {return const_iterator(this, size());}
	const_iterator constBegin() const {return const_iterator(this, 0);}
	const_iterator constEnd() const {return const_iterator(this, size());}
	//reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
	//reverse_iterator rend() {return reverse_iterator(this, -1);}
	//const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
	//const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
	//const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
	//const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}

	size_t size() const {return pih_content.size();}
	int size_s() const {return pih_content.size_s();}
	size_t length() const {return pih_content.size();}
	size_t capacity() const {return pih_content.size();}
	bool isEmpty() const {return (pih_content.size() == 0);}

	T & operator [](const Key & key) {
		if (pih_content.isEmpty()) _rehash(1);
		uint k = piHash(key);
		int i = _index(k);
		if (i < pih_content.size_s()) {
			PIVector<HashEntry> & hv(pih_content[i]);
			if (hv.size_s() == 1) {
				if (hv[0].key == k)
					return hv[0].value;
			}
			for (int j = 0; j < hv.size_s(); ++j)
				if (hv[j].key == k)
					return hv[j].value;
		}
		if (pih_content[i].size_s() >= 4)
			_rehash(pih_content.size_s() * 2);
		i = _index(k);
		pih_content[i] << HashEntry(k);
		return pih_content[i].back().value;
	}
	const T operator [](const Key & key) const {return value(key);}
	T & at(const Key & key) {return (*this)[key];}
	const T at(const Key & key) const {return (*this)[key];}

	PIHash<Key, T> & operator <<(const PIHash<Key, T> & other) {
		if (other.isEmpty()) return *this;
		for (int i = 0; i < other.pih_content.size_s(); ++i)
			for (int j = 0; j < other.pih_content[i].size_s(); ++j)
				insert(other.pih_content[i][j].key, other.pih_content[i][j].value);
		return *this;
	}

	bool operator ==(const PIHash<Key, T> & t) const {return (pih_content == t.pih_content);}
	bool operator !=(const PIHash<Key, T> & t) const {return (pih_content != t.pih_content);}
	bool contains(const Key & key) const {
		bool f(false);
		_find(key, f);
		return f;
	}

	PIHash<Key, T> & reserve(size_t new_size) {_rehash(new_size); return *this;}

	PIHash<Key, T> & remove(const Key & key) {
		uint k = piHash(key);
		int i = _index(k);
		if (i >= pih_content.size_s()) return *this;
		PIVector<HashEntry> & hv(pih_content[i]);
		for (int j = 0; j < hv.size_s(); ++j)
			if (hv[j].key == k) {
				hv.remove(j);
				--j;
			}
		return *this;
	}
	PIHash<Key, T> & erase(const Key & key) {return remove(key);}
	PIHash<Key, T> & clear() {pih_content.clear(); return *this;}

	void swap(PIHash<Key, T> & other) {
		piSwapBinary<PIVector<PIVector<HashEntry> > >(pih_content, other.pih_content);
	}

	PIHash<Key, T> & insert(const Key & key, const T & value) {
		(*this)[key] = value;
		return *this;
	}
	const T value(const Key & key, const T & default_ = T()) const {
		uint k = piHash(key);
		int i = _index(k);
		if (i >= pih_content.size_s()) return default_;
		const PIVector<HashEntry> & hv(pih_content[i]);
		for (int j = 0; j < hv.size_s(); ++j)
			if (hv[j].key == k)
				return hv[j].value;
		return default_;
	}
	PIVector<T> values() const {
		PIVector<T> ret;
		for (int i = 0; i < pih_content.size_s(); ++i)
			for (int j = 0; j < pih_content[i].size_s(); ++j)
				ret << pih_content[i][j].value;
		return ret;
	}
	/*Key key(const T & value_, const Key & default_ = Key()) const {
		for (int i = 0; i < pih_content.size_s(); ++i)
			for (int j = 0; j < pih_content[i].size_s(); ++j)
				if (pih_content[i][j].value == value_)
					return pih_content[i][j].key;
		return default_;
	}
	PIVector<Key> keys() const {
		PIVector<Key> ret;
		for (int i = 0; i < pih_content.size_s(); ++i)
			for (int j = 0; j < pih_content[i].size_s(); ++j)
				ret << pih_content[i][j].key;
		return ret;
	}*/

	/*void dump() {
		piCout << "PIHash" << size() << "entries" << PICoutManipulators::NewLine << "content:";
		for (size_t i = 0; i < pih_content.size(); ++i)
			piCout << PICoutManipulators::Tab << i << ":" << pih_content[i];
		piCout << "index:";
		for (size_t i = 0; i < pim_index.size(); ++i)
			piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
	}*/

protected:
	struct HashEntry {
		HashEntry(uint k = 0, const T & v = T()): key(k), value(v) {;}
		uint key;
		T value;
		bool operator ==(const HashEntry & s) const {return key == s.key;}
		bool operator !=(const HashEntry & s) const {return key != s.key;}
		bool operator <(const HashEntry & s) const {return key < s.key;}
		bool operator >(const HashEntry & s) const {return key > s.key;}
	};
	/*template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIHash<Key1, T1>::HashEntry> & v);
	template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIHash<Key1, T1>::HashEntry> & v);

	const value_type _pair(ssize_t index) const {
		if (index < 0 || index >= pim_index.size_s())
			return value_type();
		//piCout << "_pair" << index << pim_index[index].index;
		return value_type(pim_index[index].key, pih_content[pim_index[index].index]);
	}
	Key & _key(ssize_t index) {return pim_index[index].key;}
	T & _value(ssize_t index) {return pih_content[pim_index[index].index];}*/

	inline size_t asize(size_t s) {
		if (s == 0) return 0;
		if (pih_content.size() + pih_content.size() >= s && pih_content.size() < s)
			return pih_content.size() + pih_content.size();
		ssize_t t = 0, s_ = s - 1;
		while (s_ >> t) ++t;
		return (1 << t);
	}
	int _index(const uint & k) const {
		return k % pih_content.size_s();
	}
	void _rehash(int ns) {
		ns = asize(ns);
		if (pih_content.size_s() == ns) return;
		PIVector<PIVector<HashEntry> > nhc;
		nhc.resize(ns);
		for (int i = 0; i < pih_content.size_s(); ++i) {
			for (int j = 0; j < pih_content[i].size_s(); ++j) {
				HashEntry & e(pih_content[i][j]);
				int ni = e.key % ns;
				nhc[ni] << e;
			}
		}
		pih_content.swap(nhc);
	}

	PIVector<PIVector<HashEntry> > pih_content;
};


uint qHash(const PIString & v, uint seed = 0) {return piHash(v);}


int main(int argc, char *argv[]) {
	QApplication a(argc, argv);
#if QT_VERSION >= 0x050000
	a.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
#endif
	//################################
	/*QHash<PIString, PIString> h2;
	QMap<PIString, PIString> m2;
	PIString prefix = "1234567890";
	PITimeMeasurer tm;
	double el = 0.;

	tm.reset();
	for (int i=0; i<10000; ++i) {
		h2[prefix + PIString::fromNumber(i)+"1234567890"] = PIString::fromNumber(randomi());
	}
	el = tm.elapsed_m(); piCout << el << h2.capacity();

	tm.reset();
	for (int i=0; i<10000; ++i) {
		m2[prefix + PIString::fromNumber(i)+"1234567890"] = PIString::fromNumber(randomi());
	}
	el = tm.elapsed_m(); piCout << el;
	piCout << "*********";

	PIString _s;
	tm.reset();
	for (int i=0; i<10000; ++i) {
		_s = h2.value(prefix + PIString::fromNumber(i)+"1234567890");
	}
	el = tm.elapsed_m(); piCout << el << h2.capacity();

	tm.reset();
	for (int i=0; i<10000; ++i) {
		_s = m2.value(prefix + PIString::fromNumber(i)+"1234567890");
	}
	el = tm.elapsed_m(); piCout << el;

	return 0;*/
	//################################
	CDPultWindow w;
	w.show();
	if (a.arguments().size() > 1)
		w.loadFile(a.arguments()[1]);
	return a.exec();
}
