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

// GLUserPreference.cpp
#include "stdafx.h"
#include "mg/MGCL.h"
#include "mgGL/context.h"
#include "mgGL/Color.h"
#include "Common/CursorRestriction.h"
#include "Misc/UserPreference.h"


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

// User Preference

UserPreference::UserPreference(){
}

UserPreference::~UserPreference(){
}

namespace{
	template<typename T>
	T GetProfileT(CWinApp& app, LPCTSTR lpszSection, LPCTSTR lpszEntry, T defValue){
		BYTE* pData = 0;
		UINT nBytes;
		T buf;

		if(!app.GetProfileBinary(lpszSection, lpszEntry, &pData, &nBytes)){
			return defValue;
		}

		ASSERT(nBytes == sizeof(T));
		::CopyMemory(&buf, pData, nBytes);
		delete[] pData;
		return buf;
	}

	template<typename T>
	BOOL WriteProfileT(CWinApp& app, LPCTSTR lpszSection, LPCTSTR lpszEntry, T value)
	{
		return app.WriteProfileBinary(lpszSection, lpszEntry, (LPBYTE)&value, sizeof(T));
	}
}

// Initialize the user preference.
void UserPreference::Init(){
	// メンバーデータのマップオブジェクトをデフォルト値初期化

	// Bool
	InitBool(upv_Curve_Chamfer_Join, _T("Curve\\Chamfer"), _T("Join"), true);
	InitBool(upv_Curve_Chamfer_Trim, _T("Curve\\Chamfer"), _T("Trim"), true);
	InitBool(upv_Curve_Contour_SliceX, _T("Curve\\Contour"), _T("SliceX"), false);
	InitBool(upv_Curve_Contour_SliceY, _T("Curve\\Contour"), _T("SliceY"), false);
	InitBool(upv_Curve_Contour_SliceZ, _T("Curve\\Contour"), _T("SliceZ"), false);
	InitBool(upv_Curve_Convert_Remove, _T("Curve\\Convert"), _T("Remove"), false);
	InitBool(upv_Curve_EllipseFoci_Mark, _T("Curve\\EllipseFoci"), _T("Mark"), false);
	InitBool(upv_Curve_ExtendLineToPoint_Both, _T("Curve\\ExtendLineToPoint"), _T("Both"), false);
	InitBool(upv_Curve_Fillet_Join, _T("Curve\\Fillet"), _T("Join"), true);
	InitBool(upv_Curve_Fillet_Trim, _T("Curve\\Fillet"), _T("Trim"), true);
	InitBool(upv_Curve_ParamLine_UV, _T("Curve\\ParamLine"), _T("UV"), true);
	InitBool(upv_Curve_Line4Point_Both, _T("Curve\\Line4Point"), _T("Both"), false);
	InitBool(upv_Curve_LineAngled_Both, _T("Curve\\LineAngled"), _T("Both"), false);
	InitBool(upv_Curve_LineBisect_Both, _T("Curve\\LineBisect"), _T("Both"), false);
	InitBool(upv_Curve_LineNormal_Both, _T("Curve\\LineNormal"), _T("Both"), false);
	InitBool(upv_Curve_LineSingle_Both, _T("Curve\\LineSingle"), _T("Both"), false);
	InitBool(upv_Curve_LineVertical_Both, _T("Curve\\LineVertical"), _T("Both"), false);
	InitBool(upv_Curve_Parabola_Half, _T("Curve\\Parabola"), _T("Half"), false);
	InitBool(upv_Curve_PolygonEdge_Flip, _T("Curve\\PolygonEdge"), _T("Flip"), false);
	InitBool(upv_Curve_Rect3Point_Circle, _T("Curve\\Rect3Point"), _T("Circle"), true);
	InitBool(upv_Curve_RectCenter_Circle, _T("Curve\\RectCenter"), _T("Circle"), true);
	InitBool(upv_Curve_RectCorner_Circle, _T("Curve\\RectCorner"), _T("Circle"), true);
	InitBool(upv_Curve_RectVertical_Circle, _T("Curve\\RectVertical"), _T("Circle"), true);
	InitBool(upv_Curve_SplineCPoint_Sharp, _T("Curve\\SplineCPoint"), _T("Sharp"), false);
	InitBool(upv_Curve_SplineInterp_Sharp, _T("Curve\\SplineInterp"), _T("Sharp"), false);
	InitBool(upv_Curve_SplineSketch_Close, _T("Curve\\SplineSketch"), _T("Close"), false);
	InitBool(upv_Curve_SplineSketch_Planar, _T("Curve\\SplineSketch"), _T("Planar"), false);
	InitBool(upv_Curve_Smooth_FixEnd, _T("Curve\\Smooth"), _T("FixEnd"), true);
	InitBool(upv_Curve_Smooth_FixStart, _T("Curve\\Smooth"), _T("FixStart"), true);
	InitBool(upv_Curve_Smooth_Negate, _T("Curve\\Smooth"), _T("Negate"), false);

	InitBool(upv_Eval_CurveCurvature_Negate, _T("Eval\\CurveCurvature"), _T("Negate"), false);
	InitBool(upv_Eval_PointFromUV_CreatePoint, _T("Eval\\PointFromUV"), _T("CreatePoint"), false);
	InitBool(upv_Eval_PointFromUV_NormalizeU, _T("Eval\\PointFromUV"), _T("NormalizeU"), false);
	InitBool(upv_Eval_PointFromUV_NormalizeV, _T("Eval\\PointFromUV"), _T("NormalizeV"), false);
	InitBool(upv_Eval_SurfZebra_Vertical, _T("Eval\\SurfZebra"), _T("Vertical"), true);

	InitBool(upv_IsoCurve_Show, _T("IsoCurve"), _T("Show"), true);

	InitBool(upv_ModelingOp_GridSnap_Enabled, _T("ModelingOp\\GridSnap"), _T("Enabled"), false);
	InitBool(upv_ModelingOp_GridSnap_AngleEnabled, _T("ModelingOp\\GridSnap"), _T("AngleEnabled"), false);
	InitBool(upv_ModelingOp_GridSnap_PlanarEnabled, _T("ModelingOp\\ObjSnap"), _T("Enabled"), false);
	InitBool(upv_ModelingOp_ObjSnap_Enabled, _T("ModelingOp\\ObjSnap"), _T("ProjEnabled"), false);
	InitBool(upv_ModelingOp_ObjSnap_ProjEnabled, _T("ModelingOp\\ObjSnap"), _T("ProjToLockEnabled"), false);
	InitBool(upv_ModelingOp_ObjSnap_ProjToLockEnabled, _T("ModelingOp\\ObjSnap"), _T("ProjToLockEnabled"), false);
	InitBool(upv_ModelingOp_ObjSnap_ApprIntsctEnabled, _T("ModelingOp\\ObjSnap"), _T("ApprIntsctEnabled"), false);

	InitBool(upv_Render_Test_DrawLine, _T("Eval\\RenderTest"), _T("DrawLine"), false);

	InitBool(upv_ViewOp_RotationFlip, _T("ViewOp"), _T("RotationFlip"), false);
	InitBool(upv_ViewOp_TranslationFlip, _T("ViewOp"), _T("TranslationFlip"), false);

	InitBool(upv_ViewOp_TranslationAlways, _T("ViewOp"), _T("TranslationAlways"), true);

	InitBool(upv_Window_InitChildMaximum, _T("Window"), _T("InitChildMaximum"), false);

	// Int

	InitInt(upv_Color_Viewport_BackGround, _T("Color\\Viewport"), _T("BackGround"), RGB(0x9F, 0x9F, 0x9F), INT_MIN, INT_MAX);
	InitInt(upv_Color_Viewport_Grid, _T("Color\\Viewport"), _T("Grid"), RGB(0x8C, 0x8C, 0x8C), INT_MIN, INT_MAX);
	InitInt(upv_Color_Viewport_GridX, _T("Color\\Viewport"), _T("GridX"), RGB(0x96, 0x4B, 0x4B), INT_MIN, INT_MAX);
	InitInt(upv_Color_Viewport_GridY, _T("Color\\Viewport"), _T("GridY"), RGB(0x4B, 0x96, 0x4B), INT_MIN, INT_MAX);
	InitInt(upv_Color_Viewport_GridZ, _T("Color\\Viewport"), _T("GridZ"), RGB(0x4B, 0x4B, 0x96), INT_MIN, INT_MAX);
	InitInt(upv_Color_Viewport_Select, _T("Color\\Viewport"), _T("Select"), RGB(0xFF, 0xFF, 0x00), INT_MIN, INT_MAX);
	InitInt(upv_Color_Viewport_Lock, _T("Color\\Viewport"), _T("Lock"), RGB(0x8C, 0x8C, 0x8C), INT_MIN, INT_MAX);

	InitInt(upv_Color_Object_Default,_T("Color\\Object"), _T("Default"), RGB(0x0C, 0x0C, 0x0C), INT_MIN, INT_MAX);

	InitInt(upv_Curve_PolygonEdge_Num, _T("Curve\\PolygonEdge"), _T("Num"), 5, 3, INT_MAX);
	InitInt(upv_Curve_PolygonStar_Num, _T("Curve\\PolygonStar"), _T("Num"), 5, 3, INT_MAX);
	InitInt(upv_Curve_PolygonVertex_Num, _T("Curve\\PolygonVertex"), _T("Num"), 5, 3, INT_MAX);
	InitInt(upv_Curve_SplineCPoint_Degree, _T("Curve\\SplineCPoint"), _T("Degree"), 3, 1, INT_MAX);
	InitInt(upv_Curve_SplineInterp_Degree, _T("Curve\\SplineInterp"), _T("Degree"), 3, 1, INT_MAX);

	InitInt(upv_Curve_Smooth_CurvatureType, _T("Curve\\Smooth"), _T("CurvatureType"), 0, 0, 1);
	InitInt(upv_Curve_Smooth_Density, _T("Curve\\Smooth"), _T("Density"), 2, 2, INT_MAX);
	InitInt(upv_Curve_Smooth_DeviationType, _T("Curve\\Smooth"), _T("DeviationType"), 0, 0, 1);
	InitInt(upv_Curve_Smooth_EndCondition, _T("Curve\\Smooth"), _T("EndCondition"), 0, 0, 1);

	InitInt(upv_Display_RenderingViewport_BackGround, _T("Display\\RenderingViewport"), _T("Background"), RGB(0x9F, 0x9F, 0x9F), INT_MIN, INT_MAX);
	InitInt(upv_Display_RenderingViewport_Ambient, _T("Display\\RenderingViewport"), _T("Ambient"), RGB(0xFF, 0xFF, 0xFF), INT_MIN, INT_MAX);

	InitInt(upv_Eval_CurveCurvature_Density, _T("Eval\\CurveCurvature"), _T("Density"), 3, 1, 320);
	InitInt(upv_Eval_CurveCurvature_Type, _T("Eval\\CurveCurvature"), _T("Type"), 0, 0, 1);
	InitInt(upv_Eval_EdgeShow_Color, _T("Eval\\EdgeShow"), _T("Color"), RGB(0xFF, 0x00, 0xFF), INT_MIN, INT_MAX);
	InitInt(upv_Eval_SurfGauss_Type, _T("Eval\\SurfGauss"), _T("Type"), 0, 0, 3);
	InitInt(upv_Eval_SurfZebra_Color, _T("Eval\\SurfZebra"), _T("Color"), 0xFF0000, INT_MIN, INT_MAX);

	InitInt(upv_File_DocManager_OpenFilter, _T("File\\DocManager"), _T("OpenFilter"), -1, -1, INT_MAX);
	InitInt(upv_File_DocManager_SaveFilter, _T("File\\DocManager"), _T("SaveFilter"), -1, -1, INT_MAX);

	InitInt(upv_IsoCurve_Density, _T("IsoCurve"), _T("Density"), 1, 1, 100);

	InitInt(upv_ModelingOp_ObjSnap_Aparture, _T("ModelingOp\\ObjSnap"), _T("Aparture"), 16, 1, 30);

	InitInt(upv_Point_FromCurveDivide_Num, _T("Point\\FromCurveDivide"), _T("Num"), 5, 2, INT_MAX);

	InitInt(upv_Screen_Lang, _T("Screen"), _T("Lang"), 0, 0, 1); // 0: Eng (UN); 1: Jpn

	InitInt(upv_Surface_GridPoints_U, _T("Surface\\GridPoints"), _T("U"), 2, 2, INT_MAX);
	InitInt(upv_Surface_GridPoints_V, _T("Surface\\GridPoints"), _T("V"), 2, 2, INT_MAX);

	InitInt(upv_Tess_Fan, _T("Tess"), _T("Fan"), MGCL::MULTIPLE_TRIANGLES, 0, 3);
	InitInt(upv_Tess_MinTri, _T("Tess"), _T("MinTri"), 8, 1, INT_MAX);

	InitInt(upv_Undo_Size, _T("Undo"), _T("Size"), 20, 0, 1000);
	InitInt(upv_Undo_Memory, _T("Undo"), _T("Memory"), 1024, 512, 4096); // TODO: 上限値はシステムから得たい

	// Double	,


	InitDouble(upv_Curve_Arc_Radius, _T("Curve\\Arc"), _T("Radius"), 10., DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Chamfer_Distance1, _T("Curve\\Chamfer"), _T("Distance1"), 1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Chamfer_Distance2, _T("Curve\\Chamfer"), _T("Distance2"), 1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_CircleTTR_Radius, _T("Curve\\CircleTTR"), _T("Radius"), 10, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Conic_Rho, _T("Curve\\Conic"), _T("Rho"), 0.5, -1, 1);
	InitDouble(upv_Curve_Contour_Pitch, _T("Curve\\Contour"), _T("Pitch"), 2, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Convert_AngleZero, _T("Curve\\Convert"), _T("AngleZero"), 0.05, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Convert_LineZero, _T("Curve\\Convert"), _T("LineZero"), 1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_CornerArcCPR_Radius, _T("Curve\\CornerArcCPR"), _T("Radius"), 10, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Fillet_Radius, _T("Curve\\Fillet"), _T("Radius"), 1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Offset_Distance, _T("Curve\\Offset"), _T("Distance"), 1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_LineAngled_Angle, _T("Curve\\LineAngled"), _T("Angle"), 10, -360, 360);
	InitDouble(upv_Curve_Rect3Point_Radius, _T("Curve\\Rect3Point"), _T("Radius"), 3, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Rect3Point_Rho, _T("Curve\\Rect3Point"), _T("Rho"), 0.5, 0, 1);
	InitDouble(upv_Curve_RectCenter_Radius, _T("Curve\\RectCenter"), _T("Radius"), 3, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_RectCenter_Rho, _T("Curve\\RectCenter"), _T("Rho"), 0.5, 0, 1);
	InitDouble(upv_Curve_RectCorner_Radius, _T("Curve\\RectCorner"), _T("Radius"), 3, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_RectCorner_Rho, _T("Curve\\RectCorner"), _T("Rho"), 0.5, 0, 1);
	InitDouble(upv_Curve_RectVertical_Radius, _T("Curve\\RectVertical"), _T("Radius"), 3, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_RectVertical_Rho, _T("Curve\\RectVertical"), _T("Rho"), 0.5, 0, 1);
	InitDouble(upv_Curve_Smooth_Deviation, _T("Curve\\Smooth"), _T("Deviation"), 0.1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Curve_Smooth_Scale1, _T("Curve\\Smooth"), _T("Scale1"), 50, DBL_MIN, 1000);
	InitDouble(upv_Curve_Smooth_Scale2, _T("Curve\\Smooth"), _T("Scale2"), 50, DBL_MIN, 1000);
	InitDouble(upv_Curve_Smooth_Weight, _T("Curve\\Smooth"), _T("Weight"), 0.1, DBL_MIN, DBL_MAX);

	InitDouble(upv_Eval_CurveCurvature_Scale, _T("Eval\\CurveCurvature"), _T("Scale"), 1.0, 0.1, DBL_MAX);
	InitDouble(upv_Eval_SurfZebra_Thickness, _T("Eval\\SurfZebra"), _T("Thickness"), 0.1, DBL_MIN, DBL_MAX);

	InitDouble(upv_ModelingOp_GridSnap_Angle, _T("ModelingOp\\GridSnap"), _T("Angle"), 90., DBL_MIN, DBL_MAX);
	InitDouble(upv_ModelingOp_ObjSnap_Length, _T("ModelingOp\\GridSnap"), _T("Length"), 10., 0., DBL_MAX);

	InitDouble(upv_Point_FromCurveLength_Span, _T("Point\\FromCurveLength"), _T("Span"), 1, DBL_MIN, DBL_MAX);

	InitDouble(upv_Surface_Offset_Distance, _T("Surface\\Offset"), _T("Distance"), 1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Surface_QuadGCon_Angle, _T("Surface\\QuadGCon"), _T("Angle"), 0.1, DBL_MIN, mgDBLPAI);
	InitDouble(upv_Surface_QuadGCon_Gap, _T("Surface\\QuadGCon"), _T("Gap"), 0.1, DBL_MIN, DBL_MAX);
	InitDouble(upv_Surface_Smooth_Distance, _T("Surface\\Smooth"), _T("Distance"), 1, DBL_MIN, DBL_MAX);

	InitDouble(upv_Tess_CurveTol, _T("Tess"), _T("CurveTol"), 0.15, DBL_MIN, DBL_MAX);
	InitDouble(upv_Tess_SurfTol, _T("Tess"), _T("SurfTol"), 0.2, DBL_MIN, DBL_MAX);
	InitDouble(upv_Tess_MaxRat, _T("Tess"), _T("MaxRat"), 2.0, DBL_MIN, DBL_MAX);
	InitDouble(upv_Tess_MaxEdgeLen, _T("Tess"), _T("MaxEdgeLen"), -1.0, -DBL_MAX, DBL_MAX);

	InitDouble(upv_Tolerance_AngleZero, _T("Tolerance"), _T("AngleZero"), 0.025, 0.001, 0.1);
	InitDouble(upv_Tolerance_LineZero, _T("Tolerance"), _T("LineZero"), 0.05, 1e-8, 1.0);
	InitDouble(upv_Tolerance_MachineZero, _T("Tolerance"), _T("MachineZero"), 1e-20, DBL_MIN, 1e-2);
	InitDouble(upv_Tolerance_MaxKnotRatio, _T("Tolerance"), _T("MaxKnotRatio"), 500, 5, 5000);
	InitDouble(upv_Tolerance_RelZero, _T("Tolerance"), _T("RelZero"), 1e-6, 1e-20, 1.0);
	InitDouble(upv_Tolerance_WorldZero, _T("Tolerance"), _T("WorldZero"), 0.01, 1e-8, 1.0);

	InitDouble(upv_ViewOp_RotationDelta, _T("ViewOp"), _T("RotationDelta"), 4.5, 0, 360.);
	InitDouble(upv_ViewOp_TranslationDelta, _T("ViewOp"), _T("TranslationDelta"), 0.015, 0, 1.0);
	InitDouble(upv_ViewOp_ScaleDelta, _T("ViewOp"), _T("ScaleDelta"), 1.04, 1.0, 2.0);

	// String
}

void UserPreference::InitBool(
	UserPrefName key,
	LPCTSTR section,
	LPCTSTR entry,
	bool value)
{
	m_pref_bool.insert(
		std::make_pair(
			key,
			UserPrefBoolValue(section, entry, value)));
}

void UserPreference::InitInt(
	UserPrefName key,
	LPCTSTR section,
	LPCTSTR entry,
	int value,
	int lower,
	int upper){
	m_pref_int.insert(
		std::make_pair(
			key,
			UserPrefIntValue(section, entry, value, lower, upper)));
}

void UserPreference::InitDouble(
	UserPrefName key,
	LPCTSTR section,
	LPCTSTR entry,
	double value,
	double lower,
	double upper){
	m_pref_double.insert(
		std::make_pair(
			key,
			UserPrefDoubleValue(section, entry, value, lower, upper)));
}

void UserPreference::InitString(
	UserPrefName key,
	LPCTSTR section,
	LPCTSTR entry,
	const CString& value){
	m_pref_str.insert(
		std::make_pair(
			key,
			UserPrefStringValue(section, entry, value)));
}

///Export this preference to the context ctx.
void UserPreference::exportToContext(MGContext& ctx){

	// Tolerance
	const double angle_zero = GetDoubleValue(upv_Tolerance_AngleZero);
	const double rc_zero = GetDoubleValue(upv_Tolerance_RelZero);
	const double mach_zero = GetDoubleValue(upv_Tolerance_MachineZero);
	const double line_zero = GetDoubleValue(upv_Tolerance_LineZero);
	const double wc_zero = GetDoubleValue(upv_Tolerance_WorldZero);
	const double max_knot_ratio = GetDoubleValue(upv_Tolerance_MaxKnotRatio);
	ctx.set_tolerance(wc_zero,rc_zero,mach_zero,line_zero,angle_zero,max_knot_ratio);

	// Tessellation
	mgTLInputParam tess;
	tess.set_crvTol(GetDoubleValue(upv_Tess_CurveTol));
	tess.set_surfTol(GetDoubleValue(upv_Tess_SurfTol));
	tess.set_max_ratio(GetDoubleValue(upv_Tess_MaxRat));
	tess.set_fanKind(MGCL::fan_kind(GetIntValue(upv_Tess_Fan)));
	tess.set_minimum_tri(GetIntValue(upv_Tess_MinTri));
	tess.set_max_edge_len(GetDoubleValue(upv_Tess_MaxEdgeLen));
	ctx.set_tessellate_param(tess);

	// アプリオプション > 色
	ctx.set_Bcolor(GetBackgroundColor());
	ctx.set_Hcolor(GetHilightColor());
	ctx.set_Gcolor(GetObjectColor());

	// グリッド周りの色
	ctx.set_gridColors(GetGridColors());

	//Set the construction's line and axis colors.
	MGglViewAttrib& viewattr=ctx.theView();
	viewattr.cplane().set_colorsByViewID(1,GetGridColors());

	// アプリオプション > 全般 > サーフェスアイソカーブ密度
	ctx.set_line_density(
		GetBoolValue(upv_IsoCurve_Show) ? GetIntValue(upv_IsoCurve_Density) : 0
		);

	// アプリオプション > モデリング補助 各種
	// 主にグリッドスナップとオブジェクトスナップ関連
	MGSnapAttrib& snap = ctx.snap_attrib();
	const double dAprt = GetIntValue(upv_ModelingOp_ObjSnap_Aparture);
	snap.setGrid(GetBoolValue(upv_ModelingOp_GridSnap_Enabled));
	snap.setSnapAperture(dAprt,dAprt);
}

///Export this preference to the MGCursorRestriction cr.
//(the angle mode, angle value and length to cr)
void UserPreference::exportToCRestrict(MGCursorRestriction& cr)const{		
	bool bAngleSnap = GetBoolValue(upv_ModelingOp_GridSnap_AngleEnabled);
	cr.SetRestrictionMode(
		bAngleSnap ? MGCursorRestriction::ANGLE : MGCursorRestriction::FREE);

	double  dAngleSnapAngle, dMin, dMax;
	GetDoubleValue(upv_ModelingOp_GridSnap_Angle,dAngleSnapAngle, dMin, dMax);
	cr.set_angle(dAngleSnapAngle);

	double len;
	GetDoubleValue(upv_ModelingOp_ObjSnap_Length,len, dMin, dMax);
	std::pair<bool, double>& lenR=cr.get_distanceAttrib();
	lenR.first=false;
	lenR.second=len;
}

///Import this preference from the MGCursorRestriction cr.
//(the angle mode and angle value from cr)
void UserPreference::importFromCRestrict(const MGCursorRestriction& cr){		
	//Save cursor restriction mode data.
	SetBoolValue(upv_ModelingOp_GridSnap_AngleEnabled,
			cr.mode()==MGCursorRestriction::ANGLE);

	double angle=cr.get_angle();
	SetDoubleValue(upv_ModelingOp_GridSnap_Angle, angle);

	const std::pair<bool, double>& lenR=cr.get_distanceAttrib();
	SetDoubleValue(upv_ModelingOp_ObjSnap_Length,lenR.second);
}

void UserPreference::LoadRegistry(CWinApp& app)
{
	// Bool
	{
		UserPrefBoolMap::iterator
			first = m_pref_bool.begin(), last = m_pref_bool.end();
		for(; first != last; ++first){
			UserPrefBoolValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			bool bVal = GetProfileT(app, section, entry, pref.value);
			//TRACE(_T("%s %s %d\n"), section, entry, bVal);
			pref.value = bVal;
		}
	}

	// Int
	{
		UserPrefIntMap::iterator
			first = m_pref_int.begin(), last = m_pref_int.end();
		for(; first != last; ++first){
			UserPrefIntValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			int nVal = app.GetProfileInt(section, entry, pref.value);
			//TRACE(_T("%s %s %d\n"), section, entry, nVal);
			pref.value = nVal;
		}
	}

	// Double
	{
		UserPrefDoubleMap::iterator
			first = m_pref_double.begin(), last = m_pref_double.end();
		for(; first != last; ++first){
			UserPrefDoubleValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			double dVal = GetProfileT(app, section, entry, pref.value);
			//TRACE(_T("%s %s %g\n"), section, entry, dVal);
			pref.value = dVal;
		}
	}

	// String
	{
		UserPrefStringMap::iterator
			first = m_pref_str.begin(), last = m_pref_str.end();
		for(; first != last; ++first){
			UserPrefStringValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			CString strVal = app.GetProfileString(section, entry, pref.value);
			//TRACE(_T("%s %s %s\n"), section, entry, strVal);
			pref.value = strVal;
		}
	}

	m_backgroundColor=FromCOLORREF(GetIntValue(upv_Color_Viewport_BackGround));
	m_hilightColor=FromCOLORREF(GetIntValue(upv_Color_Viewport_Select));
	m_objectColor=FromCOLORREF(GetIntValue(upv_Color_Object_Default));
	m_gridColor[0]=FromCOLORREF(GetIntValue(upv_Color_Viewport_Grid));
	m_gridColor[1]=FromCOLORREF(GetIntValue(upv_Color_Viewport_GridX));
	m_gridColor[2]=FromCOLORREF(GetIntValue(upv_Color_Viewport_GridY));
	m_gridColor[3]=FromCOLORREF(GetIntValue(upv_Color_Viewport_GridZ));
}

void UserPreference::SaveRegistry(CWinApp& app)
{
	// Bool
	{
		UserPrefBoolMap::iterator
			first = m_pref_bool.begin(), last = m_pref_bool.end();
		for(; first != last; ++first){
			const UserPrefBoolValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			//TRACE(_T("%s %s %d\n"), section, entry, pref.value);
			WriteProfileT(app, section, entry, pref.value);
		}
	}

	// Int
	{
		UserPrefIntMap::iterator
			first = m_pref_int.begin(), last = m_pref_int.end();
		for(; first != last; ++first){
			const UserPrefIntValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			//TRACE(_T("%s %s %d\n"), section, entry, pref.value);
			app.WriteProfileInt(section, entry, pref.value);
		}
	}

	// Double
	{
		UserPrefDoubleMap::iterator
			first = m_pref_double.begin(), last = m_pref_double.end();
		for(; first != last; ++first){
			const UserPrefDoubleValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			//TRACE(_T("%s %s %g\n"), section, entry, pref.value);
			WriteProfileT(app, section, entry, pref.value);
		}
	}

	// String
	{
		UserPrefStringMap::iterator
			first = m_pref_str.begin(), last = m_pref_str.end();
		for(; first != last; ++first){
			const UserPrefStringValue& pref = first->second;
			LPCTSTR section = pref.section;
			LPCTSTR entry = pref.entry;

			//TRACE(_T("%s %s %s\n"), section, entry, pref.value);
			app.WriteProfileString(section, entry, pref.value);
		}
	}
}

bool UserPreference::GetBoolValue(UserPrefName key, Access acc) const
{
	UserPrefBoolMap::const_iterator i = m_pref_bool.find(key);
	ASSERT(i != m_pref_bool.end());

	switch(acc){
	case CurrentValue:
		return i->second.value;
	case DefaultValue:
		return i->second.def;
	default:
		return i->second.value;
	}
}

void UserPreference::SetBoolValue(UserPrefName key, bool bValue)
{
	UserPrefBoolMap::iterator i = m_pref_bool.find(key);
	ASSERT(i != m_pref_bool.end());
	i->second.value = bValue;
}

void UserPreference::GetIntValue(
	UserPrefName key,
	int& nValue,
	int& nLower,
	int& nUpper) const
{
	UserPrefIntMap::const_iterator i = m_pref_int.find(key);
	ASSERT(i != m_pref_int.end());

	const UserPrefIntValue& pref = i->second;

	nValue = pref.value;
	if(nValue < pref.lower){
		nValue = pref.lower;
	}
	else if(pref.upper < nValue){
		nValue = pref.upper;
	}

	nLower = pref.lower;
	nUpper = pref.upper;

	ASSERT(pref.lower <= nValue && nValue <= pref.upper);
}

int UserPreference::GetIntValue(UserPrefName key, Access acc) const
{
	if(acc != DefaultValue){
		int nValue, nLower, nUpper;
		GetIntValue(key, nValue, nLower, nUpper);

		switch(acc){
		case CurrentValue:
			return nValue;
		case LowerValue:
			return nLower;
		case UpperValue:
			return nUpper;
		default:
			return nValue;
		}
	}
	else{
		UserPrefIntMap::const_iterator i = m_pref_int.find(key);
		ASSERT(i != m_pref_int.end());
		return i->second.def;
	}
}

void UserPreference::SetIntValue(UserPrefName key, int nValue)
{
	UserPrefIntMap::iterator i = m_pref_int.find(key);
	ASSERT(i != m_pref_int.end());
	i->second.value = nValue;

	switch(key){
	case upv_Color_Viewport_BackGround:
		m_backgroundColor=FromCOLORREF(nValue);
		return;
	case upv_Color_Viewport_Grid:
		m_gridColor[0]=FromCOLORREF(nValue);
		return;
	case upv_Color_Viewport_Select:
		m_hilightColor=FromCOLORREF(nValue);
		return;
	case upv_Color_Viewport_GridX:
		m_gridColor[1]=FromCOLORREF(nValue);
		return;
	case upv_Color_Viewport_GridY:
		m_gridColor[2]=FromCOLORREF(nValue);
		return;
	case upv_Color_Viewport_GridZ:
		m_gridColor[3]=FromCOLORREF(nValue);
		return;
	case upv_Color_Object_Default:
		m_objectColor=FromCOLORREF(nValue);
		return;
	}

}

void UserPreference::GetDoubleValue(
	UserPrefName key,
	double& dValue,
	double& dLower,
	double& dUpper) const
{
	// GetInt とほぼ同じ

	UserPrefDoubleMap::const_iterator i = m_pref_double.find(key);
	ASSERT(i != m_pref_double.end());
	const UserPrefDoubleValue& pref = i->second;

	dValue = pref.value;
	if(dValue < pref.lower){
		dValue = pref.lower;
	}
	else if(pref.upper < dValue){
		dValue = pref.upper;
	}

	dLower = pref.lower;
	dUpper = pref.upper;
	ASSERT(pref.lower <= dValue && dValue <= pref.upper);
}

double UserPreference::GetDoubleValue(UserPrefName key, Access acc) const
{
	if(acc != DefaultValue){
		double dVal, dLower, dUpper;
		GetDoubleValue(key, dVal, dLower, dUpper);

		switch(acc){
		case CurrentValue:
			return dVal;
		case LowerValue:
			return dLower;
		case UpperValue:
			return dUpper;
		default:
			return dVal;
		}
	}
	else{
		UserPrefDoubleMap::const_iterator i = m_pref_double.find(key);
		ASSERT(i != m_pref_double.end());
		return i->second.def;
	}
}

void UserPreference::SetDoubleValue(UserPrefName key, double dValue)
{
	// SetInt とほぼ同じ
	UserPrefDoubleMap::iterator i = m_pref_double.find(key);
	ASSERT(i != m_pref_double.end());
	i->second.value = dValue;
}

CString UserPreference::GetStringValue(UserPrefName key, Access acc) const
{
	UserPrefStringMap::const_iterator i = m_pref_str.find(key);
	ASSERT(i != m_pref_str.end());

	switch(acc){
	case CurrentValue:
		return i->second.value;
	case DefaultValue:
		return i->second.def;
	default:
		return i->second.value;
	}
}

void UserPreference::SetStringValue(UserPrefName key, const CString& strValue)
{
	UserPrefStringMap::iterator i = m_pref_str.find(key);
	ASSERT(i != m_pref_str.end());
	i->second.value = strValue;
}

// Signleton対応
UserPreference* UserPreference::m_pPreference=NULL;

UserPreference& UserPreference::getInstance(){
	VERIFY(m_pPreference!=NULL);
	return *m_pPreference;
}

void UserPreference::setInstance(UserPreference* pref){ 
	m_pPreference = pref;
}

const MGColor& getUserPrefBackgroundColor(){
	UserPreference& pref = UserPreference::getInstance();
	return pref.GetBackgroundColor();
}

const MGColor& getUserPrefSelectionColor(){
	UserPreference& pref = UserPreference::getInstance();
	return pref.GetHilightColor();
}

const MGColor& getUserPrefObjectColor(){
	UserPreference& pref = UserPreference::getInstance();
	return pref.GetObjectColor();
}

const MGColor* getUserPrefGridColor(){
	UserPreference& pref = UserPreference::getInstance();
	return pref.GetGridColors();
}
