#pragma once
#include "MouseSnap.h"
#include "CommonObject.h"
#include "Gate.h"
#include "Block.h"
#include "Wire.h"
#include "SpacialHashing.h"
#include "PriorQueue.h"
#include "TreeNode.h"
using namespace std;
class CINKSApp;
class CINKSView;
class CMouseTracker
{
public:
	enum TrackResult{
		TrackFailed = -2,
		TrackCancelled = -1,
		TrackContinue,
		TrackSucceeded,
		TrackMove,
		TrackNoMove,
		TrackCreateNew,
		TrackSelectRegion,
		TrackEditWire,
		TrackEditWireEdge
	};
	enum Mode{
		ModeNone,
		ModeSelect,
		ModeCreate,
		ModeZoomIn = 6,
		ModeZoomOut = 7,
		ModeZoomHand = 8
	};
	enum CreateMode{
		NoCreate = -1,
		CreateGate = 2,
		CreateWire,
		CreateBlock,
		CreateTag,
		CreateInv
	};
	// change this!!!
	enum CursorType{
		HandleNothing = -1,
		CursorSelect,
		CursorMove,
		CursorCopy,
		CursorCreateGate,
		CursorCreateBlock,
		CursorCreateWire,
		CursorCreateTag,
		CursorZoomIn,
		CursorZoomOut
	};

	CPoint m_PointStart;
	CPoint m_PointPrevious;
	CPoint m_Point;

public:
	CMouseTracker(){};
	CMouseTracker(CWnd *pWnd, CMouseSnap *SnapMouse);
	~CMouseTracker();
	void InitialUpdate(CINKSView *pView);
	int Track(CDC *pDC, UINT nFlags, CPoint point);
	BOOL OnSetCursor(CDC *pDC);
	void Reset();
	CRect GetSelectedRegion(){return m_rectSelectedRegion;}
	void Draw(CDC *pDC, Graphics &g);
	Matrix* GetTransformationMatrix(){return &m_Transform;}

private:
	enum UpdateMode{
		UpdateMouseFlags = 0x007f, // MK_LBUTTON... etc.
		UpdateRemove = 0x0001,
		UpdateFirst = 0x0002,
		UpdateDrawStartPointRect = 0x0004,
		UpdateDraw = 0x0008,
		UpdateMoveGObject = 0x0010,
		UpdateMoveTag = 0x0020,
		UpdateEditWire = 0x0040,
		UpdateEditWireEdge = 0x0080,
		UpdateLast = 0x0100
	};

	virtual int OnBeginTrack(UINT nFlags, CPoint point);
	virtual int OnEndTrack(int trackResult);
	virtual int OnMouseMessage(MSG &msg, UINT nFlags, CPoint point, CDC *pDC);
	virtual int OnMouseMove(UINT nFlags, CPoint point);
	virtual int OnLButtonDown(UINT nFlags, CPoint point);
	virtual int OnLButtonUp(UINT nFlags, CPoint point);
	virtual int OnRButtonDown(UINT nFlags, CPoint point);
	virtual int OnKeybMessage(MSG &msg, UINT nChar, UINT nRepCount, UINT nFlags);
	virtual void OnKeyDown(UINT nChar, UINT nRepCount, UINT nFlags);
	virtual void OnKeyUp(UINT nChar, UINT nRepCount, UINT nFlags);
	virtual int OnMessage(MSG &msg);

	virtual void OnUpdate(CDC *pDC, UINT nMode);

	virtual void OnHandScroll(CPoint point);
	int HandleTest(CPoint point);
	CCommonObject* ConnectHitTest(CPoint point, int &nNumber);
	void SelectMultiple(CPoint point); // draw rectangle
	bool AdaptWire(CPoint from, CPoint to, AnchorList &addTo); // try connect two points; returning true if succeeded
	bool AdaptWireSimple(CPoint from, CPoint to, AnchorList &addTo); // rectangular adapt
	int RecalculateWeight(CPoint start, CPoint end); // of new point added into the tree
	void TraverseTree(AnchorList &addTo, CTreeNode *last); // add new anchors when found connection; last == node with weight=0
	CTreeNode* FindMinWeightNode(CTreeNode *pRoot, CTreeNode *pMin);

	void DrawTag(CDC* pDC, CPoint point);
	
public:
	CINKSApp *theApp;
	Mode m_Mode;
	CreateMode m_CreateMode;
	bool m_bSelectRegion; // mode selecting objects in region
	bool m_bEditWire; // mode editing wire
	int m_nEditEdgeWirePoint;
	bool m_bMoveCObject; // mode moving object
	AnchorList Anchors; // Anchors for creating wire
	CCommonObject **m_gAddWireObject; // for hittest of inout 'ports' of CObjects
	int m_nWireConnection[2]; // indexes of hit inout ports (+inport -outport); when line hit, returns 1
	int m_nSOListCount;
	int m_nCOListCount;
	CList<CCommonObject*, CCommonObject*> *m_pSOList;
	CSpacialHashing *m_pSpaceHash; // used for creating wire
	CMouseSnap *m_SnapMouse;

private:
	CDC *pDC;
	CWnd *m_pWnd;
	CINKSView *m_pView;

	Pen *m_pPen;
	Brush *m_pBrush;

	Matrix m_Transform; // used for translating drafts of selected CObjects
	Matrix m_Translate; // used for translating CObjects
	
	int m_CursorMode;
	CRect m_rectSelectedRegion; // selected region
	Point *m_oldWirePoints;
	int m_nOldPointCount;
	GraphicsPath **m_pGPath; // bounding rectangles of selected object used as draft when moving them
	CPriorQueue<CTreeNode*> *m_pPriorQueue; // used for creating wire
	CTreeNode *m_pRoot;
};