/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno             */
/* All rights reserved.                                             */
/* **************************************************************** */

/**
 * @file LocateState2.cpp
 * @brief LocateState.h の実装。ハンドラーでないメソッドがメイン。
 */
#include "stdafx.h"
#include "mg/Position.h"
#include "mgGL/Texture.h"
#include "fugen.h"
#include "fugenView.h"
#include "Misc/UserPreference.h"
#include "Common/GridCursor.h"
#include "Common/LocateState.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

namespace{
	// AAAAAKAAAAA // 1
	// AAAAAKAAAAA // 2
	// AAAKKKKKAAA // 3
	// AAKWWKWWKAA // 4
	// AAKWWKWWKAA // 5
	// KKKKKKKKKKK // 6
	// AAKWWKWWKAA // 7
	// AAKWWKWWKAA // 8
	// AAAKKKKKAAA // 9
	// AAAAAKAAAAA // a
	// AAAAAKAAAAA // b

	static const GLuint rasterBytes[] = {
		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 1
		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 2
		0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, // 3
		0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, // 4
		0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, // 5
		0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, // 6
		0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, // 7
		0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, // 8
		0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, // 9
		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // a
		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // b
	};

	const GLsizei pixelw = 11;
	const GLsizei pixelh = 11;
}

///Get the MGCursorImageData instance which is a static varialbe.
#define GRID_CURSOR_TEXTURE_UNIT 31
mgTexture* MGLocateState::getCursorTexture(){
	static mgTexture cursorImage;
	if(cursorImage.getTextureID()==0){
		cursorImage.set_image(pixelw,pixelh,rasterBytes
			,false//immutable texture
			,true//This is pointSprite
			,GL_CLAMP_TO_EDGE,GL_NEAREST);
	}
	return &cursorImage;
}

void MGLocateState::setAngleRestriction(double degree){
	m_CursorRestriction.addAngleMode();	
	m_CursorRestriction.set_angle(degree);

	fugenStatusBar& sbar = theStatusBar();
	sbar.updateDisplay();
}

///Set MGCursorRestriction mode to ELEVATION
void MGLocateState::setElevationRestriction(
	const MGPosition& origin,	//Elebvation origin
	const MGVector& normal		//Elevation normal diretion
){
	m_CursorRestriction.set_straight_to_map(origin,origin+normal);
	m_CursorRestriction.SetRestrictionMode(MGCursorRestriction::ELEVATION);

	fugenStatusBar& sbar=theStatusBar();
	sbar.updateDisplay();
}

///Set MGCursorRestriction mode to ELEVATION.
///This also prohibits the update of the cursorRestriction(prohibitAETPmodeUpdate).
///That is, disable_AETPmode() must be invoked() if desired.
void MGLocateState::setElevationRestrictionToProhibitUpdate(
	const MGPosition& origin,	//Elebvation origin
	const MGVector& normal		//Elevation normal diretion
){
	m_CursorRestriction.set_straight_to_map(origin,origin+normal);
	m_CursorRestriction.SetRestrictionMode(MGCursorRestriction::ELEVATION);
	m_CursorRestriction.prohibitAETPmodeUpdate();

	fugenStatusBar& sbar=theStatusBar();
	sbar.updateDisplay();
}

///Set elevation restriction by the MGLocateInfo.
///The normal is the info.window's cplane normal, and
///the base position of the normal is info.point_world.
void MGLocateState::setElevationRestrictionToProhibitUpdate(const MGLocateInfo& info){
	setElevationRestrictionToProhibitUpdate(
				info.point_world(),info.window()->cplane().plane().normal());
}

///Set MGCursorRestriction mode to PLANAR on the basepoint input..
void MGLocateState::setPlanarRestrictionPoint(
	const MGVector& normal, //normal of the plane.
	const MGPosition& basepoint
){
	m_CursorRestriction.set_planarToPoint(normal,basepoint);
	fugenStatusBar& sbar=theStatusBar();
	sbar.updateDisplay();
}

///Set MGCursorRestriction mode to PLANAR on the basepoint input..
void MGLocateState::setPlanarRestrictionPointToProhibitUpdate(
	const MGVector& normal, //normal of the plane.
	const MGPosition& basepoint
){
	m_CursorRestriction.set_planarToPoint(normal,basepoint);
	m_CursorRestriction.prohibitPmodeUpdate();

	fugenStatusBar& sbar=theStatusBar();
	sbar.updateDisplay();
}

///Set MGCursorRestriction mode to TAB
void MGLocateState::setTabRestriction(
	const MGPosition& P0,	//Tab's straight's start point.
	const MGPosition& P1	//Tab's straight's end point.
){
	//Update locate's attribute
	m_CursorRestriction.SetRestrictionMode(MGCursorRestriction::TABMODE);
	m_CursorRestriction.set_straight_to_map(P0,P1);

	fugenStatusBar& sbar=theStatusBar();
	sbar.updateDisplay();
}

///Set MGCursorRestriction mode to TAB
///This also prohibits the update of the cursorRestriction(prohibitAETPmodeUpdate).
void MGLocateState::setTabRestrictionToProhibitUpdate(
	const MGPosition& P0,	//Tab's straight's start point.
	const MGPosition& P1	//Tab's straight's end point.
){
	//Update locate's attribute
	m_CursorRestriction.SetRestrictionMode(MGCursorRestriction::TABMODE);
	m_CursorRestriction.set_straight_to_map(P0,P1);
	m_CursorRestriction.prohibitAETPmodeUpdate();

	fugenStatusBar& sbar=theStatusBar();
	sbar.updateDisplay();
}

///Turn off ANGLE/TAB/ELEVATION restriction to be FREE.
void MGLocateState::disable_AETPmode(){
	m_CursorRestriction.allowAETPmodeUpdate();
	m_CursorRestriction.SetRestrictionMode(MGCursorRestriction::FREE);

	fugenStatusBar& sbar = theStatusBar();
	sbar.updateDisplay();
}

/// Prohibit ANGLE/ELEVATION/TAB mode. The mode be changed to FREE.
void MGLocateState::prohibitAETPmodeUpdate(){
	m_CursorRestriction.prohibitAETPmodeUpdate();
	fugenStatusBar& sbar = theStatusBar();
	sbar.updateDisplay();
}

void MGLocateState::setDistanceRestriction(double dist){
	m_CursorRestriction.set_distance(dist);
	if(dist>0.)
		m_CursorRestriction.set_distanceMode_ON();
}

//Set object snap objectives.
void MGLocateState::set_snap_objectives(const MGGroup& objectives){
	m_objectives.clear();
	MGGroup::const_iterator j=objectives.begin(), jend=objectives.end();
	for(; j!=jend; j++)
		m_objectives.push_back(j->get());
}

void MGLocateState::add_snap_objectives(
	const std::list<const MGGel*>& objectives
){
	std::list<const MGGel*>::const_iterator j=objectives.begin(), jend=objectives.end();
	for(; j!=jend; j++){
		const MGGel* gelj=*j;
		m_objectives.remove(gelj);
		m_objectives.push_front(gelj);
	}
}

MGSnapPositions::snap_kind MGLocateState::snap(
	fugenView* window, UINT nFlags, const CPoint& point
){
	// カレント点からロケート点(Probe点)を求める
	MGPosition crsr(cursor());
	const MGObject* pObj = m_located_object;
	m_snapKind=locate_object_snap_point(
		window, point, crsr, pObj, m_located_param);
	document()->set_cursor(crsr);
	m_located_object = const_cast<MGObject*>(pObj);

	// Probe点が求まった場合はカーソル ID を変更する。
	UINT nIDC = IDC_CURSOR_SNAP;
	switch(m_snapKind){
	case MGSnapPositions::endpos:
		nIDC = IDC_CURSOR_END;
		break;
	case MGSnapPositions::knotpos:
		nIDC = IDC_CURSOR_KNOT;
		break;
	case MGSnapPositions::nearpos:
		nIDC = IDC_CURSOR_NEAR;
		break;
	case MGSnapPositions::vertexpos:
		nIDC = IDC_CURSOR_VERTEX;
		break;
	case MGSnapPositions::centerpos:
		nIDC = IDC_CURSOR_CENTER;
		break;
	default:
		nIDC = IDC_CURSOR_SNAP;
		break;
	}

	VERIFY(m_hCursor = AfxGetApp()->LoadCursor(nIDC) );
	return m_snapKind;
}
