#pragma once
#include "CommonObject.h"
#include "Wire.h"
#include "PriorQueue.h"
#include <set>
#include <vector>

using namespace std;

class CHashItem;
class CSpacialHashing
{

public:
	CSpacialHashing(int nScreenX, int nScreenY);
	~CSpacialHashing();
	void RegisterCObject(CCommonObject *pObject, int l, int t, int r, int b); // registration of an object
	void RegisterWire(CCommonObject *pObject, Point *points, int nPointCount);
	void DeRegisterCObject(CCommonObject *pObject, int l, int t, int r, int b); // deregistration of an object
	void DeRegisterWire(CCommonObject *pObject, Point *points, int nPointCount);
	void DeRegisterWire(CCommonObject *pObject);
	void DeRegisterCObject(CCommonObject *pObject); // deregistration of an object
	bool CanMoveCObject(GraphicsPath *newGP);
	void MoveCObject(CCommonObject *pObject, CPoint oldTL); // reregistration of an object
	void MoveWire(CCommonObject *pObject, Point *oldPoints, int nOldPointCount, Point *newPoints, int nNewPointCount); 
	CCommonObject *HashTest(CPoint point, int objType = -1); // hittest for registered objects
	CCommonObject *HashTestWireEdge(CPoint point, CCommonObject *pObjExclude);
	int GetHLine(int Vpos, int start, int end); // get maximum possible length of horizontal line from start
	int GetVLine(int Hpos, int start, int end); // get maximum possible length of vertical line from start
	void OutVH(stringstream &ss);
	void OutLine(stringstream &ss);
	bool HashAreaTest(CPoint point, int width, int height);
	void GetMaxXY(int *x, int *y);
	int GetWireDirAtPoint(CCommonObject *obj, CPoint point);
	std::vector<CCommonObject *> GetObjectsAtRegion(int l, int t, int r, int b);
private:
	void RegisterCObjectH(CCommonObject *pObject, int l, int r, int nID = -1, int nKey = -1);
	void RegisterCObjectV(CCommonObject *pObject, int t, int b, int nID = -1, int nKey = -1);
	void DeRegisterCObjectH(CCommonObject *pObject, int l, int r, int nID = -1);
	void DeRegisterCObjectV(CCommonObject *pObject, int t, int b, int nID = -1);

public:

private:
	CHashItem **m_aHItems; // horizontal array of items
	CHashItem **m_aVItems; // vertical array of items
	set<CHashItem> **m_lHItems;
	set<CHashItem> **m_lVItems;
	int m_nScreenX;
	int m_nScreenY;
};

//class CHashItem
//{
//public:
//	CHashItem(CCommonObject *pObject, CHashItem *pNext, int nID);
//	~CHashItem() {};
//	bool operator==(const CCommonObject*) const;
//	bool HasNext() {return m_pNextHashItem != NULL;}
//	CHashItem* GetNext() {return m_pNextHashItem;}
//	void SetNext(CHashItem *pNewNext) {m_pNextHashItem = pNewNext;}
//	CCommonObject* GetCurrentCO() {return m_pCObj;}
//	int GetID() {return m_nID;}
//private:
//
//public:
//private:
//	int m_nID;
//	CCommonObject *m_pCObj;
//	CHashItem *m_pNextHashItem;
//};

class CHashItem
{
public:
	CHashItem(CCommonObject *pObject, int nID, int nKey);
	CHashItem(CCommonObject *pObject, int nID); // nID == key
	CHashItem() {};
	~CHashItem() {};
	bool operator==(const CCommonObject*) const;
	bool operator <(const CHashItem &b) const
	{
		if(m_pCObj != b.m_pCObj){
			return m_pCObj < b.m_pCObj;
		}
		if(m_nID != b.m_nID){
			return m_nID < b.m_nID;
		}
		if(m_nKey != b.m_nKey){
			return m_nKey < b.m_nKey;
		}
		return false;
	}
//	bool HasNext() {return m_pNextHashItem != NULL;}
//	CHashItem* GetNext() {return m_pNextHashItem;}
//	void SetNext(CHashItem *pNewNext) {m_pNextHashItem = pNewNext;}
	CCommonObject* GetCurrentCO() {return m_pCObj;}
	int GetID() {return m_nID;}
	int GetKey() {return m_nKey;}
private:
public:	
private:
	int m_nID;
	int m_nKey;
	CCommonObject *m_pCObj;
//	CHashItem *m_pNextHashItem;
};