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

// TransMirror.cpp: MGTransMirrorTool クラスのインプリメンテーション

#include "stdafx.h"
#include "Calc/mgcalc.h"
#include "Calc/mgfunctor.h"
#include "fugenView.h"
#include "TransCmd/TransMirror.h"

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

// MGTransMirrorTool

MGTransMirrorTool::MGTransMirrorTool(fugenDoc* pDoc)
:MGCommandStateOwner(pDoc, ID_TRANSFORM_MIRROR), m_copy(true){
}

MGCommandBase* MGTransMirrorTool::initial_clone(fugenDoc* pDoc)const{
	return new MGTransMirrorTool(pDoc);
}

bool MGTransMirrorTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	if(current_object_is_valid(mgAll_Object,m_obj)){
		set_current_object(m_obj);
		//Input a point.
		set_child_current_command(new MGTransMirrorIPoint(this));
	}else{
		//select a curve to rotate.
		set_child_current_command(new MGTransMirrorSObj(this));
	}
	return false;
}

bool MGTransMirrorTool::OnCommandCanceled(UINT nIDS){
	clear_pick_object();
	return MGCommandStateOwner::OnCommandCanceled(nIDS);
}

void MGTransMirrorTool::calc_transform(fugenView* pView, const MGPosition& ref){
	const LInfoVec& linfos=locates();
	if(!linfos.size()){
		m_transf.set_null();
		return;
	}

	const MGPosition& P0=linfos[0]->point_world();
	MGVector v1 = ref - P0;
	MGVector v2 = pView->cplane().plane().normal();
	m_transf.set_reflect_3D(v1 * v2, P0);
}

bool MGTransMirrorTool::make_model(fugenView* pView){
	MGGelPositions gelps;
	MGPickObjects::iterator cur = m_obj.begin(), last = m_obj.end();
	for(; cur != last; ++cur){
		MGObject* obj = (*cur)->top_object()->clone();
		obj->transform(m_transf);
		gelps.push_back(MGGelPosition((*cur)->bottom_group(),obj));
	}

	if(m_copy){ // reflect & copy
		add_object_to_document(gelps);
	}else{      // only reflect
		replace(m_obj,gelps);
	}
	return true;
}

//set the cloned initial objects.
void MGTransMirrorTool::set_initial_object(){
	const MGPickObjects& curobj = current_objects();
	m_obj = curobj;
}

///////////////Object for transformation selection class/////////////
MGTransMirrorSObj::MGTransMirrorSObj(MGCommandStateOwner* owner)
:MGSelectState(owner, MGSelectState::MULTIPLE_SELECT){}

bool MGTransMirrorSObj::initiate_tool(){
	MGSelectState::initiate_tool();
	SetStatusMessage(IDS_PROMPT_OBJECT);
	return false;
}

bool MGTransMirrorSObj::OnKeyDown(
	fugenView* window, UINT nChar,UINT nRepCnt, UINT nFlags
){
	if(nChar==VK_RETURN){
		MGTransMirrorTool* owner=state_owner();
		owner->set_initial_object();
		if(!owner->m_obj.empty())
			set_sibling_next_command(new MGTransMirrorIPoint(owner));
		return false;
	}
	return MGSelectState::OnKeyDown(window, nChar, nRepCnt, nFlags);
}

/////////////Point input class//////////////
MGTransMirrorIPoint::MGTransMirrorIPoint(MGCommandStateOwner* owner)
:MGLocateState(owner, UNLOCK_SNAP_ATTRIB, LINE_RUBBER, POINT_IPDRAW){
}

bool MGTransMirrorIPoint::OnKeyDown(
	fugenView* window, UINT nChar,UINT nRepCnt, UINT nFlags
){
	MGTransMirrorTool* owner=state_owner();
	switch(nChar){
	case 'c':
	case 'C':
		owner->ToggleCopyMode();
		break;
	case VK_RETURN:
		return false;
	default:;
	}
	return MGLocateState::OnKeyDown(window, nChar, nRepCnt, nFlags);
}

bool MGTransMirrorIPoint::OnLocated(const MGLocateInfo& linfo){
	MGTransMirrorTool* owner=state_owner();
	const LInfoVec& linfos=locates();
	if(linfos.size()<=1){
		return false;
	}

	// 計算開始
	owner->calc_transform(linfo.window(), linfos.back()->point_world());
	if(!owner->make_model(linfo.window())){
		return owner->OnCommandCanceled(1);
	}
	return owner->OnCommandEnd(1);
}

void MGTransMirrorIPoint::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	const LInfoVec& linfos=locates();
	if(linfos.empty()){
		return;
	}

	MGTransMirrorTool* owner=state_owner();

	// 鏡像を描画	
	owner->calc_transform(pView, cursor());
	fugenView& glv=*pView;
	const MGDrawParam& para=glv.draw_param();
	int density=para.line_desity_wire_face();

	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	MGTransf& transf=owner->m_transf;
	MGPickObjects& objs=owner->m_obj;
	MGPickObjects::iterator cur = objs.begin(), last = objs.end();
	for(; cur != last; ++cur){
		std::unique_ptr<MGObject> obj((*cur)->top_object()->clone());
		obj->transform(transf);
		obj->drawWire(sgl,density);
	}

	// 対称移動に関する軸を描画
	MGColor::get_instance(MGColor::White).exec(sgl);
	const MGPosition& ref = linfos.size()<2 ? cursor():linfos[1]->point_world();
	sgl.Begin(GL_LINES);
	sgl.Vertex3dv(linfos[0]->point_world().data());
	sgl.Vertex3dv(ref.data());
	sgl.End();
}

void MGTransMirrorIPoint::prompt_message()const{
	CString strYesNo;
	strYesNo.LoadString(state_owner()->IsCopyMode() ? IDS_YES : IDS_NO);

	switch(locates().size()){
	case 0:
		SetStatusMessage(IDS_PROMPT_MIRROR_AXIS_START, strYesNo);
		break;
	case 1:
		SetStatusMessage(IDS_PROMPT_MIRROR_AXIS_END, strYesNo);
		break;
	}
}
