// 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 "mesh_dlg.h"
#include "edit_morph_mesh_dlg.h"
//
#include "nel/3d/ps_particle.h"
#include "nel/3d/ps_mesh.h"
#include "nel/3d/particle_system_model.h"
//
#include "nel/misc/path.h"

///==================================================================
CMeshDlg::CMeshDlg(CParticleWorkspace::CNode *ownerNode, NL3D::CPSShapeParticle *sp, CParticleDlg  *particleDlg)
	: _Node(ownerNode), _ShapeParticle(sp), _EMMD(NULL), _ParticleDlg(particleDlg)
{
	//{{AFX_DATA_INIT(CMeshDlg)
	//}}AFX_DATA_INIT
}

CMeshDlg::~CMeshDlg()
{
	if (_EMMD)
	{
		_EMMD->DestroyWindow();
		delete _EMMD;
		_EMMD = NULL;
	}
}

///==================================================================
void CMeshDlg::init(CWnd *pParent, sint x, sint y)
{
	Create(IDD_CHOOSE_MESH, pParent);
	RECT r;
	GetClientRect(&r);
	r.top += y; r.bottom += y;
	r.right += x; r.left += x;
	MoveWindow(&r);	

	ShowWindow(SW_SHOW);
}


///==================================================================
void CMeshDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMeshDlg)
	DDX_Control(pDX, IDC_MESH_ERROR, m_MeshErrorMsg);
	DDX_Text(pDX, IDC_SHAPE_NAME, m_ShapeName);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMeshDlg, CDialog)
	//{{AFX_MSG_MAP(CMeshDlg)
	ON_BN_CLICKED(IDC_BROWSE_SHAPE, OnBrowseShape)
	ON_BN_CLICKED(IDC_ENABLE_MORPHING, OnEnableMorphing)
	ON_BN_CLICKED(IDC_EDIT_MORPH, OnEditMorph)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

///==================================================================
void CMeshDlg::touchPSState()
{
	if (_Node && _Node->getPSModel())
	{	
		_Node->getPSModel()->touchTransparencyState();
		_Node->getPSModel()->touchLightableState();
	}
}

///==================================================================
void CMeshDlg::OnBrowseShape() 
{
	
	CFileDialog fd(TRUE, ".shape", "*.shape", 0, NULL, this);
	if (fd.DoModal() == IDOK)
	{
		// Add to the path
		char drive[256];
		char dir[256];
		char path[256];
		char fname[256];
		char ext[256];


		// Add search path for the texture
		_splitpath (fd.GetPathName(), drive, dir, fname, ext);
		_makepath (path, drive, dir, NULL, NULL);
		NLMISC::CPath::addSearchPath (path);

		try
		{		
			_ShapeParticle->setShape(std::string(fname) + ext);		
			m_ShapeName = (std::string(fname) + ext).c_str();
			touchPSState();			
		}
		catch (NLMISC::Exception &e)
		{
			MessageBox(e.what(), "shape loading error");
		}		
		updateMeshErrorString();
	}
	UpdateData(FALSE);
}


///==================================================================
BOOL CMeshDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();	
	if (!dynamic_cast<NL3D::CPSConstraintMesh *>(_ShapeParticle))
	{
		// hide the unused fields
		GetDlgItem(IDC_ENABLE_MORPHING)->ShowWindow(SW_HIDE);
		GetDlgItem(IDC_EDIT_MORPH)->ShowWindow(SW_HIDE);
		GetDlgItem(IDC_MORPH_FRAME)->ShowWindow(SW_HIDE);
		m_ShapeName = _ShapeParticle->getShape().c_str();
		UpdateData(FALSE);
	}
	else
	{		
		NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast<NL3D::CPSConstraintMesh *>(_ShapeParticle);
		if (cm->getNumShapes() > 1)
		{
			((CButton *) GetDlgItem(IDC_ENABLE_MORPHING))->SetCheck(TRUE);
		}
		updateForMorph();
	}
	m_MeshErrorMsg.SetTextColor(RGB(255,  0,  0));

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

///==================================================================
void CMeshDlg::updateForMorph()
{
	NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast<NL3D::CPSConstraintMesh *>(_ShapeParticle);
	if (cm)
	{
		BOOL enable = cm->getNumShapes() > 1;						
		GetDlgItem(IDC_EDIT_MORPH)->EnableWindow(enable);
		GetDlgItem(IDC_BROWSE_SHAPE)->EnableWindow(!enable);
		GetDlgItem(IDC_SHAPE_NAME)->EnableWindow(!enable);
		if (!enable)
		{
			m_ShapeName = cm->getShape().c_str();
		}
		else
		{
			m_ShapeName = "";
		}
	}
	updateMeshErrorString();
	UpdateData(FALSE);
}

///==================================================================
void CMeshDlg::OnEnableMorphing() 
{
	NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast<NL3D::CPSConstraintMesh *>(_ShapeParticle);
	if (((CButton *) GetDlgItem(IDC_ENABLE_MORPHING))->GetCheck())
	{
		// morphing enabled..		
		std::string currName[2] = { cm->getShape(), cm->getShape()};
		cm->setShapes(currName, 2);		
	}
	else
	{
		// morphing disabled
		std::string currName = cm->getShape(0);
		cm->setShape(currName);
	}
	updateForMorph();
	updateModifiedFlag();
	updateMeshErrorString();
}

///==================================================================
void CMeshDlg::OnEditMorph() 
{
	nlassert(_EMMD == NULL);
	NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast<NL3D::CPSConstraintMesh *>(_ShapeParticle);
	EnableWindow(FALSE);
	_EMMD = new CEditMorphMeshDlg(_Node, cm, this, _ParticleDlg, this);
	_EMMD->init(this);
}

///==================================================================
void CMeshDlg::childPopupClosed(CWnd *child)
{
	nlassert(_EMMD == child);
	_EMMD->DestroyWindow();
	delete _EMMD;
	_EMMD = NULL;
	EnableWindow(TRUE);
	updateMeshErrorString();
}


///==================================================================
BOOL CMeshDlg::EnableWindow( BOOL bEnable)
{
	if (!bEnable)
	{
		GetDlgItem(IDC_EDIT_MORPH)->EnableWindow(FALSE);
		GetDlgItem(IDC_BROWSE_SHAPE)->EnableWindow(FALSE);
		GetDlgItem(IDC_ENABLE_MORPHING)->EnableWindow(FALSE);
		GetDlgItem(IDC_SHAPE_NAME)->EnableWindow(FALSE);	
	}
	else
	{
		GetDlgItem(IDC_ENABLE_MORPHING)->EnableWindow(TRUE);
		updateForMorph();
	}
	updateMeshErrorString();
	return CDialog::EnableWindow(bEnable);
}

///==================================================================
void CMeshDlg::updateMeshErrorString()
{
	GetDlgItem(IDC_MESH_ERROR)->SetWindowText("");
	NL3D::CPSConstraintMesh *cm = dynamic_cast<NL3D::CPSConstraintMesh *>(_ShapeParticle);
	if (!cm) return;
	std::vector<sint> numVerts;
	cm->getShapeNumVerts(numVerts);
	if (numVerts.empty()) return;
	if (numVerts.size() == 1)
	{
		GetDlgItem(IDC_MESH_ERROR)->SetWindowText((LPCTSTR) getShapeErrorString(numVerts[0]));
	}
	else
	{
		// display error msg for morphed meshs
		bool hasError = false;
		for(uint k = 0; k < numVerts.size(); ++k)
		{
			if (numVerts[k] < 0)
			{
				hasError = true;
				break;
			}
		}
		if (hasError)
		{
			CString errorInMorphMesh;
			errorInMorphMesh.LoadString(IDS_ERROR_IN_MORPH_MESH);
			GetDlgItem(IDC_MESH_ERROR)->SetWindowText((LPCTSTR) errorInMorphMesh);
		}
	}
}

//====================================================================
CString CMeshDlg::getShapeErrorString(sint errorCode)
{
	CString str;
	switch(errorCode)
	{
		case NL3D::CPSConstraintMesh::ShapeFileIsNotAMesh: str.LoadString(IDS_SHAPE_FILE_NOT_MESH); break;
		case NL3D::CPSConstraintMesh::ShapeFileNotLoaded: str.LoadString(IDS_SHAPE_NOT_LOADED); break;
		case NL3D::CPSConstraintMesh::ShapeHasTooMuchVertices: str.LoadString(IDS_TOO_MUCH_VERTICES); break;
		default:
		break;
	};
	return str;
}