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

#include "stdafx.h"
#include "Calc/mgcalc.h"
#include "fugenView.h"
#include "TransCmd/TransCopy.h"

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

// MGTransCopyTool

MGTransCopyTool::MGTransCopyTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_TRANSFORM_COPY){
}

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

bool MGTransCopyTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	if(resetCurrentObjects(mgAll_Object)){
		MGTransCopyIPoint* ncmd=new MGTransCopyIPoint(this, current_objects());
		//Input a point.
		set_child_current_command(ncmd);
	}else{
		//select objects to copy.
		set_child_current_command(new MGTransCopySObj(this));
	}
	return false;
}

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

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

bool MGTransCopySObj::initiate_tool(){
	MGSelectState::initiate_tool();
	SetStatusMessage(IDS_PROMPT_COPY_OBJECT);
	return false;
}

bool MGTransCopySObj::OnKeyDown(
	fugenView* window, UINT nChar,UINT nRepCnt, UINT nFlags
){
	if(nChar==VK_RETURN){
		const MGPickObjects& targets=current_objects();
		if(targets.empty())
			return false;

		//Input a point.
		set_sibling_next_command(new MGTransCopyIPoint(get_owner_command(),targets));
		return false;
	}
	return MGSelectState::OnKeyDown(window, nChar, nRepCnt, nFlags);
}

/////////////Point input class//////////////
MGTransCopyIPoint::MGTransCopyIPoint(
	MGCommandStateOwner* owner, const MGPickObjects& targets
):MGLocateState(owner, UNLOCK_SNAP_ATTRIB, LINE_RUBBER, POINT_IPDRAW),
m_objs(targets),m_bVert(false){
}

bool MGTransCopyIPoint::OnKeyDown(
	fugenView* pView, UINT nChar,UINT nRepCnt, UINT nFlags
){
	switch(nChar){
	case 'i':
	case 'I':
		if(command_id()==ID_TRANSFORM_MOVE)
			break;//We accept only when copy command.

		// identical translation, i.e. copy.
		m_move.set_null();//null indicates copy of the objects without translation.
		if(!make_model()){
			return OnCommandCanceled(1);
		}
		return OnCommandEnd(1);

	case 'v':
	case 'V':
		m_bVert ^= true;
		if(m_bVert){
			if(locates().size()==1){
				setElevationRestrictionToProhibitUpdate(*locates()[0]);
			}
		}else{
			disable_AETPmode();
		}
		break;

	case VK_RETURN://We do not accept return key.
		return false;

	default:;
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGTransCopyIPoint::OnLocated(const MGLocateInfo& info){
	const LInfoVec& linfos=locates();
	size_t np=linfos.size();
	if(np==0){
		disable_AETPmode();
		return false;
	}

	if(np<=1){
		if(m_bVert){
			setElevationRestrictionToProhibitUpdate(*linfos[0]);
		}
		return false;
	}

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

bool MGTransCopyIPoint::make_model(){
	if(m_objs.empty()){
		return false;
	}

	MGGelPositions gelps;
	MGPickObjects::iterator cur = m_objs.begin(), last = m_objs.end();
	for(; cur != last; ++cur){
		MGObject* obj = (*cur)->top_object()->clone();
		if(!m_move.is_null()){ // identical copy の場合を牽制
			obj->transform(m_move);
		}
		gelps.push_back(MGGelPosition((*cur)->bottom_group(),obj));
	}

	if(command_id()==ID_TRANSFORM_COPY)
		add_object_to_document(gelps);
	else
		replace(m_objs, gelps);
	return true;
}

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

	fugenView& glv=*pView;
	const MGDrawParam& para=glv.draw_param();
	int density=para.line_desity_wire_face();

	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	if(!m_objs.empty() && !m_move.is_null()){
		MGPickObjects::iterator cur = m_objs.begin(), last = m_objs.end();
		for(; cur != last; ++cur){
			std::unique_ptr<MGObject> obj((*cur)->top_object()->clone());
			obj->transform(m_move);
			obj->drawWire(sgl,density);
		}
	}

	const MGPosition& P0=linfos[0]->point_world();
	MGColor::get_instance(MGColor::White).exec(sgl);
	sgl.Begin(GL_LINES);
	sgl.Vertex3dv(P0.data());
	sgl.Vertex3dv(cursor().data()); // 補正済
	sgl.End();
}

void MGTransCopyIPoint::calc_transform(const MGPosition& ref){
	const LInfoVec& linfos=locates();
	assert(!linfos.empty());
	const MGPosition& P0=linfos[0]->point_world();
	m_move = ref-P0;
}

void MGTransCopyIPoint::prompt_message()const{
	switch(locates().size()){
	case 0:{
			CString strYesNo;
			strYesNo.LoadString(m_bVert ? IDS_YES : IDS_NO);
			SetStatusMessage(IDS_PROMPT_COPY_START, strYesNo);
		}
		break;
	case 1:
		SetStatusMessage(IDS_PROMPT_COPY_END);
		break;
	}
}
