/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */
/**
 * @file fugenDoc2.cpp
 * @brief fugenDoc.h の実装。I/O 関連とメニューハンドラー群。
 */
#include "stdafx.h"
#include "fugen.h"
#include "fugenDoc.h"

#include "MainFrm.h"
#include "IO/GLFileManager.h"
#include "IO/GLFileExporter.h"

#include "SnapAttrDlg.h"
#include "Common/CommandBase.h"

#include "Common/LocateState.h"
#include "Common/CommandStateOwner.h"
#include "Common/IdleCommand.h"

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

/////////////////////////////////////////////////////////////////////////////
// fugenDoc コマンド

void fugenDoc::OnCloseDocument(){
	// text display
	//OnEvalAllOff();

	// Clean the command objects except for m_default_tool here.
	while(m_command_tool_stack.size()>1){
		//We do not pop if the terminate request is to pop up the default command tool.
		//(This default command tool was set by fugenDoc.)
		MGCommandBase* command=current_command_tool();
		command->terminate_tool(true);
		delete command;
		m_command_tool_stack.pop();
	}
	m_default_tool.reset(0);
	fugenMainFrame* pFrame=theApp.MainFrame();
	fugenStatusBar& status=theStatusBar();
	status.SetDocument(0);

	// OK. Clean all views.
	CDocument::OnCloseDocument();
}

BOOL fugenDoc::OnOpenDocument(LPCTSTR lpszPathName){
	CWaitCursor wait;

	#ifdef _DEBUG
	if(IsModified())
		TRACE0("Warning: OnOpenDocument replaces an unsaved document.\n");
	#endif

	DeleteContents();
	SetModifiedFlag();// dirty during de-serialize

	if(load(lpszPathName)){
		ReportSaveLoadException(lpszPathName, 0, FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
		return FALSE;
	}

	SetModifiedFlag(FALSE);// start off with unmodified
	
	return TRUE;
}

BOOL fugenDoc::OnSaveDocument(LPCTSTR lpszPathName){
	CGLFileManager& factory = CGLFileManager::GetInstance();
	CGLFileExporter* handler = factory.GetExporter(lpszPathName);
	if(handler){
		save_view_context();
		handler->Save(m_group);

		SetModifiedFlag(FALSE); // start off with unmodified
		SetStatusMessage(IDS_PROMPT_SAVE_FILE, handler->GetFileName());
		return TRUE;
	}else{
		ReportSaveLoadException(lpszPathName, 0, TRUE, IDS_PROMPT_ERROR_SAVE);
		return FALSE;
	}
}

void fugenDoc::OnUpdateFileSave(CCmdUI* pCmdUI){
	//ビューの変更も保存したいので、上書き保存は常に可とする
	pCmdUI->Enable(TRUE);
}

void fugenDoc::OnUpdateFileSaveAs(CCmdUI* pCmdUI){
	pCmdUI->Enable();
}

int fugenDoc::ExportSelection(const CString& strPath, const MGPickObjects& target)
{
	// strPath に選択オブジェクトを保存する。
	CGLFileManager& mgr = CGLFileManager::GetInstance();
	CGLFileExporter* pHandler = mgr.GetExporter(strPath);
	if(!pHandler){
		// 保存形式が不明でエラー。
		return -1;
	}

	// 選択オブジェクトから作業用の MGGroup オブジェクトを作成して
	// 保存する。
	MGGroup work;
	MGPickObjects::const_iterator first=target.begin(),last=target.end();
	for(; first != last; ++first){
		work.append((*first)->top_object());// workのmemeberのdeleteをしてはいけない
	}

	int retcode=0;
	if(pHandler->Save(work)){
		retcode=(int)target.size();
	}

	// workのmemeberのdeleteをしてはいけない
	MGGroup::MYLIST::iterator i=work.begin(), iend=work.end();
	for(; i!=iend; i++){
		i->release();
	}
	return retcode;
}

void fugenDoc::OnSnapDialog(){
	CSnapAttrDlg dlg;
	MGSnapAttrib& sa = getSnapAttr();
	dlg.ImportFromSnap(sa);//Set data to display in the dialogue.
	
	//Set the angle mode and angle value from the status bar's MGCursorRestriction.
	fugenStatusBar& sbar=theStatusBar();
	MGCursorRestriction& cr=theCursorRestriction();

	dlg.m_bAngleSnap = cr.isAngleMode();
	dlg.m_dAngleSnapAngle=cr.get_angle();
	if(IDOK == dlg.DoModal()){
		//Update MGSnapAttrib attrib.
		dlg.ExportToSnap(sa);
		updateSnapMode();//update the mode from the attributes of sa.

		//Update MGCursorRestriction attrib.
		double angle=dlg.m_dAngleSnapAngle;
		cr.set_angle(angle);
		if(dlg.m_bAngleSnap)
			cr.addAngleMode();
		else
			cr.freeAngleMode();
		sbar.updateDisplay();
	}
}

void fugenDoc::OnUpdateSnapDialog(CCmdUI* pCmdUI){
}

namespace{
	// メニューアイテムのチェックやグレーアウトを実現するための補助関数

	typedef bool (MGSnapAttrib::*snap_getter1)() const;
	typedef bool (MGLocateState::*snap_getter2)() const;

	void UpdateCmdUI(
		fugenDoc& doc, CCmdUI& ui,
		snap_getter1 getter1,
		snap_getter2 getter2)
	{
		MGCommandBase* pCmdCur = doc.current_command_tool();
		MGLocateState* pCmd = dynamic_cast<MGLocateState*>(pCmdCur);
		if(!pCmd){
			MGCommandStateOwner* pOwner = dynamic_cast<MGCommandStateOwner*>(pCmdCur);
			if(pOwner){
				pCmd = dynamic_cast<MGLocateState*>(pOwner->GetCurState());
			}
		}

		if(!pCmd){
			ui.SetCheck((doc.getSnapAttr().*getter1)());
		}else{
			ui.Enable(pCmd->snap_lock_kind() == MGLocateState::UNLOCK_SNAP_ATTRIB);
			ui.SetCheck((pCmd->*getter2)());
		}
	}
}

void fugenDoc::OnSnapEnd() {
	MGSnapAttrib& attr=getSnapAttr();
	attr.setEnd(!attr.getEnd());
	current_command_tool()->updateSnapMode(attr);
}

void fugenDoc::OnUpdateSnapEnd(CCmdUI* pCmdUI){
	UpdateCmdUI(*this, *pCmdUI, &MGSnapAttrib::getEnd, &MGLocateState::snap_end);
}

void fugenDoc::OnSnapKnot(){
	MGSnapAttrib& attr=getSnapAttr();
	attr.setKnot(!attr.getKnot());
	current_command_tool()->updateSnapMode(attr);
}

void fugenDoc::OnUpdateSnapKnot(CCmdUI* pCmdUI){
	UpdateCmdUI(*this, *pCmdUI, &MGSnapAttrib::getKnot, &MGLocateState::snap_knot);
}

void fugenDoc::OnSnapNear(){
	MGSnapAttrib& attr=getSnapAttr();
	attr.setNear(!attr.getNear());
	current_command_tool()->updateSnapMode(attr);
}

void fugenDoc::OnUpdateSnapNear(CCmdUI* pCmdUI){
	UpdateCmdUI(*this, *pCmdUI, &MGSnapAttrib::getNear, &MGLocateState::snap_near);
}

void fugenDoc::OnSnapVertex(){
	MGSnapAttrib& attr=getSnapAttr();
	attr.setVertex(!attr.getVertex());
	current_command_tool()->updateSnapMode(attr);
}

void fugenDoc::OnUpdateSnapVertex(CCmdUI* pCmdUI){
	UpdateCmdUI(*this, *pCmdUI, &MGSnapAttrib::getVertex, &MGLocateState::snap_vertex);
}

void fugenDoc::OnSnapCenter(){
	MGSnapAttrib& attr=getSnapAttr();
	attr.setCenter(!attr.getCenter());
	current_command_tool()->updateSnapMode(attr);
}

void fugenDoc::OnUpdateSnapCenter(CCmdUI* pCmdUI){
	UpdateCmdUI(*this, *pCmdUI, &MGSnapAttrib::getCenter, &MGLocateState::snap_center);
}

void fugenDoc::OnSnapGrid(){
	MGSnapAttrib& attr=getSnapAttr();
	attr.setGrid(!attr.getGrid());
	enableGridSnap(attr.getGrid());
}

void fugenDoc::OnUpdateSnapGrid(CCmdUI* pCmdUI){
	pCmdUI->SetCheck(getSnapAttr().getGrid());
}

void fugenDoc::OnViewProjectXY(){
	InitialUpdateFrame(theApp.m_p2DxyViewTemplate,false);
}

void fugenDoc::OnViewProjectYZ(){
	InitialUpdateFrame(theApp.m_p2DyzViewTemplate,false);
}

void fugenDoc::OnViewProjectZX(){
	InitialUpdateFrame(theApp.m_p2DxzViewTemplate,false);
}

//////////////////////////////////////////////////////////////////////////////
// 一時表示コマンド

void fugenDoc::OnSysdKnotsNo(){
	DeleteDisplayList(ID_SYSD_KNOTS, true);//redraw after deleted.
}

void fugenDoc::OnUpdateSysdKnotsNo(CCmdUI* pCmdUI){
	pCmdUI->Enable(includes_sysgl(ID_SYSD_KNOTS) ? 1 : 0);
}

/*void fugenDoc::OnSysdCpolyOff(){
	DeleteDisplayList(ID_SYSD_CPOLY_ON,true);
}

void fugenDoc::OnUpdateSysdCpolyOff(CCmdUI* pCmdUI){
	pCmdUI->Enable(includes_sysgl(ID_SYSD_CPOLY_ON) ? 1 : 0);
}*/

void fugenDoc::OnSysdCurvaOff(){
	DeleteDisplayList(ID_SYSD_CURVA_ON,true);
}

void fugenDoc::OnUpdateSysdCurvaOff(CCmdUI* pCmdUI){
	pCmdUI->Enable(includes_sysgl(ID_SYSD_CURVA_ON) ? 1 : 0);
}


void fugenDoc::OnUpdateEvalSnapDisplayOn(CCmdUI* pCmdUI){
	pCmdUI->Enable(1);
//	pCmdUI->SetCheck(m_bitsSysDisp.test(ID_SNAPPOINTS) ? 1 : 0);
}


void fugenDoc::OnUpdateEvalSnapDisplayOff(CCmdUI* pCmdUI){
	pCmdUI->Enable(includes_sysgl(ID_EVAL_SNAP_DISPLAY_ON) ? 1 : 0);
}
