// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010  Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "std_afx.h"
#include "object_viewer.h"
#include "ps_mover_dlg.h"
#include "particle_tree_ctrl.h"
#include "particle_dlg.h"
#include "main_frame.h"
#include "nel/3d/ps_located.h"
#include "nel/3d/particle_system.h"


#include "editable_range.h"
#include "direction_attr.h"

/////////////////////////////////////////////////////////////////////////////
// CPSMoverDlg dialog


CPSMoverDlg::CPSMoverDlg(CParticleWorkspace::CNode *ownerNode, CWnd *parent, NL3D::CEvent3dMouseListener *ml,  NL3D::CPSLocated *editedLocated, uint32 editedLocatedIndex)   // standard constructor
	: CDialog(CPSMoverDlg::IDD, parent),
	  _Node(ownerNode),
	  _EditedLocated(editedLocated),
	  _EditedLocatedIndex(editedLocatedIndex),
	  _DirectionDlg(NULL),
	  _MouseListener(ml),
	  _Scale(NULL), _XScale(NULL), _YScale(NULL), _ZScale(NULL),
	  _ScaleText(NULL), _XScaleText(NULL), _YScaleText(NULL), _ZScaleText(NULL)
{

	

	const NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex];
	
	m_X.Format("%.3g", pos.x);
	m_Y.Format("%.3g", pos.y);
	m_Z.Format("%.3g", pos.z);

	//{{AFX_DATA_INIT(CPSMoverDlg)
	//}}AFX_DATA_INIT


}

CPSMoverDlg::~CPSMoverDlg()
{
	cleanScaleCtrl();
	if (_DirectionDlg) 
	{
		_DirectionDlg->DestroyWindow();
		delete _DirectionDlg;
	}
}

void CPSMoverDlg::updateListener(void)
{
	if(_ParticleDlg->MainFrame->isMoveElement())
	{
		const NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex];
		NLMISC::CMatrix m;
		m = _MouseListener->getModelMatrix();
		m.setPos(pos);
		_MouseListener->setModelMatrix(m);
		_Node->setModified(true);
	}
}

void CPSMoverDlg::updatePosition(void)
{
	UpdateData();
	const NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex];
	
	m_X.Format("%.3g", pos.x);
	m_Y.Format("%.3g", pos.y);
	m_Z.Format("%.3g", pos.z);

	UpdateData(FALSE);
}

void CPSMoverDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CPSMoverDlg)
	DDX_Control(pDX, IDC_SUB_COMPONENT, m_SubComponentCtrl);
	DDX_Text(pDX, IDC_XPOS, m_X);
	DDX_Text(pDX, IDC_YPOS, m_Y);
	DDX_Text(pDX, IDC_ZPOS, m_Z);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CPSMoverDlg, CDialog)
	//{{AFX_MSG_MAP(CPSMoverDlg)
	ON_BN_CLICKED(IDC_UPDATE_XPOS, OnUpdateXpos)
	ON_BN_CLICKED(IDC_UPDATE_YPOS, OnUpdateYpos)
	ON_BN_CLICKED(IDC_UPDATE_ZPOS, OnUpdateZpos)
	ON_LBN_SELCHANGE(IDC_SUB_COMPONENT, OnSelchangeSubComponent)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPSMoverDlg message handlers

void CPSMoverDlg::OnUpdateXpos() 
{
	UpdateData();
	NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex];
	float x;
	if (::sscanf(m_X, "%f", &x) == 1)
	{
		pos.x = x;
		updateListener();
	}
	else
	{
		MessageBox("invalid entry", "error");
	}
	UpdateData(FALSE);
}

void CPSMoverDlg::OnUpdateYpos() 
{
	UpdateData();
	NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex];
	float y;
	if (::sscanf(m_Y, "%f", &y) == 1)
	{
		pos.y = y;
		updateListener();
	}
	else
	{
		MessageBox("invalid entry", "error");
	}
	UpdateData(FALSE);	
}

void CPSMoverDlg::OnUpdateZpos() 
{
	UpdateData();
	NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex];
	float z;
	if (::sscanf(m_Z, "%f", &z) == 1)
	{
		pos.z = z;
		updateListener();		
	}
	else
	{
		MessageBox("invalid entry", "error");
	}
	UpdateData(FALSE);	
}

BOOL CPSMoverDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();

	uint numBound = _EditedLocated->getNbBoundObjects();
	
	uint nbCandidates = 0;

	for (uint k = 0; k < numBound; ++k)
	{
		if (dynamic_cast<NL3D::IPSMover *>(_EditedLocated->getBoundObject(k)))
		{
			uint insertedLine = m_SubComponentCtrl.AddString(_EditedLocated->getBoundObject(k)->getName().c_str());
			m_SubComponentCtrl.SetItemData(insertedLine, (DWORD) _EditedLocated->getBoundObject(k));
			++nbCandidates;			
		}
	}

	if (nbCandidates > 0)
	{
		m_SubComponentCtrl.SetCurSel(0);	
		_EditedLocated->getOwner()->setCurrentEditedElement(_EditedLocated, _EditedLocatedIndex, (NL3D::CPSLocatedBindable *) m_SubComponentCtrl.GetItemData(0));
	}
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CPSMoverDlg::cleanScaleCtrl(void)
{
	#define REMOVE_WINDOW(w) if (w) { w->DestroyWindow(); delete w; w = NULL; }
									
	REMOVE_WINDOW(_Scale);
	REMOVE_WINDOW(_XScale);
	REMOVE_WINDOW(_YScale);
	REMOVE_WINDOW(_ZScale);

	REMOVE_WINDOW(_ScaleText);
	REMOVE_WINDOW(_XScaleText);
	REMOVE_WINDOW(_YScaleText);
	REMOVE_WINDOW(_ZScaleText);
	REMOVE_WINDOW(_DirectionDlg);
}

void CPSMoverDlg::createScaleControls(void)
{
	cleanScaleCtrl();

			
	NL3D::IPSMover *m = getMoverInterface();
	if (!m) return;

	const sint xPos = 10;
	sint yPos = 330;
	


	RECT r;

	if (m->supportUniformScaling() && ! m->supportNonUniformScaling() )
	{
		_Scale = new CEditableRangeFloat("UNIFORM SCALE", _Node, 0.f, 4.f);
		_UniformScaleWrapper.M = m;
		_UniformScaleWrapper.Index = _EditedLocatedIndex;

		_Scale->setWrapper(&_UniformScaleWrapper);
		_Scale->init(100 + xPos, yPos, this);

		_ScaleText = new CStatic;
		_ScaleText ->Create("Scale : ", SS_LEFT, CRect(xPos, yPos + 10, xPos + 60, yPos + 32), this);
		_ScaleText ->ShowWindow(SW_SHOW);

		_Scale->GetClientRect(&r);
		yPos += r.bottom;
	}
	else if (m->supportNonUniformScaling())
	{
		

		// dialog for edition of x scale
		_XScale = new CEditableRangeFloat("X SCALE", _Node, 0.f, 4.f);
		_XScaleWrapper.M = m;
		_XScaleWrapper.Index = _EditedLocatedIndex;
		_XScale->setWrapper(&_XScaleWrapper);
		_XScale->init(xPos + 70, yPos, this);
		_XScale->GetClientRect(&r);

		_XScaleText = new CStatic;
		_XScaleText ->Create("x Scale : ", SS_LEFT, CRect(xPos, yPos + 10, xPos + 60, yPos + 32), this);
		_XScaleText ->ShowWindow(SW_SHOW);

		yPos += r.bottom;

		// dialog for edition of y scale
		_YScale = new CEditableRangeFloat("Y SCALE", _Node, 0.f, 4.f);
		_YScaleWrapper.M = m;
		_YScaleWrapper.Index = _EditedLocatedIndex;
		_YScale->setWrapper(&_YScaleWrapper);
		_YScale->init(xPos + 70, yPos, this);
		_YScale->GetClientRect(&r);
		

		_YScaleText = new CStatic;
		_YScaleText ->Create("y Scale : ", SS_LEFT, CRect(xPos, yPos + 10, xPos + 60, yPos + 32), this);
		_YScaleText ->ShowWindow(SW_SHOW);

		yPos += r.bottom;

		// dialog for edition of x scale
		_ZScale = new CEditableRangeFloat("Z SCALE", _Node, 0.f, 4.f);
		_ZScaleWrapper.M = m;
		_ZScaleWrapper.Index = _EditedLocatedIndex;
		_ZScale->setWrapper(&_ZScaleWrapper);
		_ZScale->init(xPos + 70, yPos, this);
		_ZScale->GetClientRect(&r);
		
		_ZScaleText = new CStatic;
		_ZScaleText ->Create("z Scale : ", SS_LEFT, CRect(xPos, yPos + 10, xPos + 60, yPos + 32), this);
		_ZScaleText ->ShowWindow(SW_SHOW);
	}


	if (m->onlyStoreNormal())
	{
		_DirectionDlg = new CDirectionAttr(" ELEMENT DIRECTION");
		_DirectionDlg->init(xPos, yPos, this);
		_DirectionWrapper.M = m;
		_DirectionWrapper.Index = _EditedLocatedIndex;
		_DirectionDlg->setWrapper(&_DirectionWrapper);
	}

	
}

void CPSMoverDlg::OnSelchangeSubComponent() 
{
	UpdateData();	
	createScaleControls();
	_EditedLocated->getOwner()->setCurrentEditedElement(_EditedLocated, _EditedLocatedIndex, getLocatedBindable());
	UpdateData(FALSE);
}


NL3D::IPSMover *CPSMoverDlg::getMoverInterface(void)
{
	UpdateData();
	nlassert(_EditedLocated);
	sint currIndex = m_SubComponentCtrl.GetCurSel();
	if (currIndex == -1) return NULL;	
	return dynamic_cast<NL3D::IPSMover *>((NL3D::CPSLocatedBindable *)(m_SubComponentCtrl.GetItemData(currIndex)));
}

void CPSMoverDlg::init(CParticleDlg	*parent)
{
	_ParticleDlg= parent;

	Create(CPSMoverDlg::IDD, parent);
	ShowWindow(SW_SHOW);
	createScaleControls();
}


NL3D::CPSLocatedBindable *CPSMoverDlg::getLocatedBindable(void)
{
	UpdateData();
	nlassert(_EditedLocated);
	sint currIndex = m_SubComponentCtrl.GetCurSel();
	if (currIndex == -1) return NULL;
	
	return (NL3D::CPSLocatedBindable *) m_SubComponentCtrl.GetItemData(currIndex);
}