//
// Tools_Edge_Selection.h
//
// Created by JGP 09/05/06
//
// Copyright (C) 2006 Rebellion (Derby), All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif


#ifndef __TOOLS_EDGE_SELECTION_H__
#define __TOOLS_EDGE_SELECTION_H__


#include "Tools_Undo.h"
#include "Core/Asura_Maths.h"
#include "Misc/list_tem.hpp"
#include "Misc/Tools_Polygon_Selection.h"


struct ModuleEdgeTriplet
{

	ModuleEdgeTriplet() 
	{
	}

	ModuleEdgeTriplet( int m, int v1, int v2 ) 
	{ 
		m_iModuleIndex = m; 
		//make the first vertex the lower one , to avoid getting the same edge in two directions.
		m_aiVertexIndex[0] = Asura_Maths::Min(v1,v2); 
		m_aiVertexIndex[1] = Asura_Maths::Max(v1,v2); 
	}

	bool operator ==( const ModuleEdgeTriplet& e ) 
	{
		return ( ( e.m_iModuleIndex == m_iModuleIndex ) && ( e.m_aiVertexIndex[0] == m_aiVertexIndex[0] ) && ( e.m_aiVertexIndex[1] == m_aiVertexIndex[1] ) );
	}

	bool operator !=( const ModuleEdgeTriplet& e ) 
	{
		return ( !( *this == e ) );
	}

	int m_iModuleIndex;
	int m_aiVertexIndex[2];

};


struct EdgeSelectionUndoData : public ModuleEdgeTriplet
{

	enum UndoType
	{
		UndoType_Added,
		UndoType_Removed,
		UndoType_ForceInt = 0xffffffff,
	};
	
	enum UndoType m_eUndoType;

};


class EdgeSelectionUndo : public FixedSizeUndo
{
public:

	EdgeSelectionUndo()
		: FixedSizeUndo( 10000, sizeof( EdgeSelectionUndoData ) )
	{
	}

	void ProcessUndoData( void* pData );
	
	void LogEdgeSelected( int iModule, int iVert1, int iVert2 );
	void LogEdgeDeselected( int iModule, int iVert1, int iVert2 );

};


enum EdgeSelectionMode
{
	ESelectionMode_Vertex,
	ESelectionMode_Polygon,
	ESelectionMode_Object,
	ESelectionMode_HorizontalEdge,
	ESelectionMode_ContinuousEdge,

	ESelectionMode_NumModes,
};


#define EdgeSelectionUpdate_Standard 0
#define EdgeSelectionUpdate_NoMouseSelection 1
#define EdgeSelectionUpdate_NoSelection 2


class Tools_Edge_Selection
{

public: 

	static void Initialise();
	static void Shutdown();
	
	static void Activate();
	static void Deactivate();

	static void Update( int iUpdateMode = EdgeSelectionUpdate_Standard );
	static void Render();

	static bool IsActive() { return s_bActive; }

	static void SelectEdge( int iModuleIndex, int iVertexIndex1, int iVertexIndex2, const bool bAllowUndo = true ); 
	static void DeselectEdge( int iModuleIndex, int iVertexIndex1, int iVertexIndex2, const bool bAllowUndo = true );
	static void SelectPolygon( int iModuleIndex, int iPolygonIndex ); 
	static void DeselectPolygon( int iModuleIndex, int iPolygonIndex );
	static void SelectObject( int iModuleIndex ); 
	static void DeselectObject( int iModuleIndex );
	static void SelectHorizontalEdge(const ModuleEdgeTriplet& xEdge);
	static void DeselectHorizontalEdge(const ModuleEdgeTriplet& xEdge);
	static void SelectContinuousEdge(const ModuleEdgeTriplet& xEdge);
	static void DeselectContinuousEdge(const ModuleEdgeTriplet& xEdge);
	static void SelectAll();
	static void DeselectAll();

	static void HandleMeshChange(int iModuleIndex);
	static void DeleteModule(int iModuleIndex);

	//iterating through the selection
	
	static List<ModuleEdgeTriplet>* GetList() { return &s_xSelectionList; }
	static const int CountSelectedEdges();

	// overlay

	static void ToggleSelectionOverlay();
	static bool IsSelectionOverlayOn();

private:

	//selection overlay functions

	static void CreateSelectionOverlay();
	static void CloseSelectionOverlay();
	
	static bool GetEdgeUnderMouse( ModuleEdgeTriplet& xEdge );
	static bool GetHighlitEdge( ModuleEdgeTriplet& xEdge );

	static void ClearUndo() { s_xSelectionUndo.FlushUndoBuffer(); }

	static void HighlightSelection();							// red outline
   	static void HighlightEdge( ModuleEdgeTriplet& xEdge );		// pulsing white outline
   	static void HighlightPolygon( PolygonID& xPolygon );		// pulsing white outline

	static void Undo();	
	static void Redo();	

	static void HandleKeyboard();
	static void HandleMouseSelection();
	static void TransferModeData( int iMode );

	//Gets a list of connected ledge-like edges
	static void ListHorizontalEdge(const ModuleEdgeTriplet& xStartEdge, List<ModuleEdgeTriplet>& xEdgeList);

	//Gets the angle between the polygons either side of the edge.
	//If it fails (there aren't two suitable polygons) then it returns false withour altering fAngle
	static bool GetAngleAtEdge(const ModuleEdgeTriplet& xStartEdge, Asura_Angle& fAngle);

	//gets a list of connected edges ,stoppinig when a branch is reached
	static void ListContinuousEdge(const ModuleEdgeTriplet& xStartEdge,List<ModuleEdgeTriplet>& xEdgeList);



	// variables

	static bool s_bShowSelection; 
	static bool s_bSelectionLocked;
	static int s_iSelectionMode;								// value from enum EdgeSelectionMode
	static int s_iSelectionModeListOffset;						// just used since I need a paramater for the list overlay thingy

	static Asura_Vector_2 s_xSelectionOverlayPosition;
	static bool s_bSelectionOverlayOpen;
	static u_int s_uSelectionOverlayMinimised;

	static float s_fEdgePlaneTolerance;
	static float s_fEdgeJoinTolerance;
	
	static List<ModuleEdgeTriplet> s_xSelectionList;

	static EdgeSelectionUndo s_xSelectionUndo;
	
	static bool s_bButtonDownForSelection;						// used to determine whether the mouse button was pressed to start polygon selection
	static ModuleEdgeTriplet s_xHighlitEdge;					// edge mouse is currently over
	static PolygonID s_xHighlitPolygon;							// polygon mouse is currently over

	static bool s_bActive;

};



#endif // __TOOLS_EDGE_SELECTION_H__
