// 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 "nel/3d/particle_system.h"
#include "object_viewer.h"
#include "located_target_dlg.h"
#include "collision_zone_dlg.h"
#include "editable_range.h"
#include "attrib_dlg.h"
#include "direction_attr.h"

/////////////////////////////////////////////////////////////////////////////
// CLocatedTargetDlg dialog


CLocatedTargetDlg::CLocatedTargetDlg(CParticleWorkspace::CNode *ownerNode,
									 NL3D::CPSTargetLocatedBindable *lbTarget,
									 CParticleDlg *particleDlg) : _Node(ownerNode), _LBTarget(lbTarget), _ParticleDlg(particleDlg)
{
	nlassert(particleDlg);
	//{{AFX_DATA_INIT(CLocatedTargetDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
}


void CLocatedTargetDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CLocatedTargetDlg)
	DDX_Control(pDX, IDC_AVAILABLE_TARGET, m_AvailableTargets);
	DDX_Control(pDX, IDC_TARGET, m_Targets);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CLocatedTargetDlg, CDialog)
	//{{AFX_MSG_MAP(CLocatedTargetDlg)
	ON_BN_CLICKED(IDC_ADD_TARGET, OnAddTarget)
	ON_BN_CLICKED(IDC_REMOVE_TARGET, OnRemoveTarget)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLocatedTargetDlg message handlers


void CLocatedTargetDlg::init(CWnd* pParent)
{
	Create(IDD_LOCATED_TARGET_DLG, pParent);
	ShowWindow(SW_SHOW);
}


void CLocatedTargetDlg::OnAddTarget() 
{
	UpdateData();
	int totalCount = m_AvailableTargets.GetCount();
	nlassert(totalCount);
	std::vector<int> indexs;
	indexs.resize(totalCount);
	int selCount = m_AvailableTargets.GetSelItems(totalCount, &indexs[0]);

	std::sort(indexs.begin(), indexs.begin() + selCount); // we never know ...

	// check that force isn't applied on a forever lasting object
	if (dynamic_cast<NL3D::CPSForce *>(_LBTarget))
	{	
		bool forEverLastingTarget = false;
		for (int k = 0; k < selCount; ++k)
		{
			NL3D::CPSLocated *loc = (NL3D::CPSLocated *) m_AvailableTargets.GetItemData(indexs[k] - k);
			nlassert(loc);
			if (loc->getLastForever())
			{
				forEverLastingTarget = true;
				break;
			}
		}
		if (forEverLastingTarget)
		{	
			CString warningStr;
			CString messStr;
			warningStr.LoadString(IDS_WARNING);
			messStr.LoadString(IDS_FORCE_APPLIED_ON_OBJECT_THAT_LAST_FOREVER);
			if (MessageBox((LPCTSTR) messStr, (LPCTSTR) warningStr, MB_OKCANCEL) != IDOK)
			{
				return;
			}
		}
	}
	//
	for (int k = 0; k < selCount; ++k)
	{
		NL3D::CPSLocated *loc = (NL3D::CPSLocated *) m_AvailableTargets.GetItemData(indexs[k] - k);
		nlassert(loc);
		_LBTarget->attachTarget(loc);
		m_AvailableTargets.DeleteString(indexs[k] - k);
		int l = m_Targets.AddString(loc->getName().c_str());
		m_Targets.SetItemData(l, (DWORD) loc);
	}	
	UpdateData(FALSE);
	//
	updateModifiedFlag();
}

void CLocatedTargetDlg::OnRemoveTarget() 
{
	UpdateData();	
	int totalCount = m_Targets.GetCount();
	nlassert(totalCount);
	std::vector<int> indexs;
	indexs.resize(totalCount);
	int selCount = m_Targets.GetSelItems(totalCount, &indexs[0]);
	std::sort(indexs.begin(), indexs.begin() + selCount); // we never know ...
	for (int k = 0; k < selCount; ++k)
	{
		NL3D::CPSLocated *loc = (NL3D::CPSLocated *) m_Targets.GetItemData(indexs[k] - k);
		nlassert(loc);
		_LBTarget->detachTarget(loc);
		m_Targets.DeleteString(indexs[k] - k);
		int l = m_AvailableTargets.AddString(loc->getName().c_str());
	
		m_AvailableTargets.SetItemData(l, (DWORD) loc);
	}
	UpdateData(FALSE);	
	updateModifiedFlag();
}

BOOL CLocatedTargetDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	RECT r;

	uint k;
	uint nbTarg = _LBTarget->getNbTargets();

	m_Targets.InitStorage(nbTarg, 128);

	std::set<NL3D::CPSLocated *> targetSet;

	// fill the box thta tells us what the target are
	for(k = 0; k < nbTarg; ++k)
	{
		m_Targets.AddString(_LBTarget->getTarget(k)->getName().c_str() );
		m_Targets.SetItemData(k, (DWORD) _LBTarget->getTarget(k) );
		targetSet.insert(_LBTarget->getTarget(k));
	};

	// fill abox with the available targets
	NL3D::CParticleSystem  *ps = _LBTarget->getOwner()->getOwner();

	uint nbLocated = ps->getNbProcess();


	
	m_AvailableTargets.InitStorage(nbTarg, 128);
	for (k = 0; k < nbLocated; ++k)
	{
		NL3D::CPSLocated *loc = dynamic_cast<NL3D::CPSLocated *>(ps->getProcess(k));
		if (loc)
		{
			if (targetSet.find(loc) == targetSet.end())
			{
				int l = m_AvailableTargets.AddString(loc->getName().c_str() );				
				m_AvailableTargets.SetItemData(l, (DWORD) loc );				
			}
		}
	}


	const sint posX = 5;
	sint posY = 180;

	// collision zone case

	if (dynamic_cast<NL3D::CPSZone *>(_LBTarget))
	{
		CCollisionZoneDlg *czd = new CCollisionZoneDlg(_Node, dynamic_cast<NL3D::CPSZone *>(_LBTarget), _ParticleDlg);
		pushWnd(czd);
		czd->init(posX, posY, this);
	}


	// force with intensity case

	if (dynamic_cast<NL3D::CPSForceIntensity *>(_LBTarget))
	{
		_ForceIntensityWrapper.F = dynamic_cast<NL3D::CPSForceIntensity *>(_LBTarget);
		CAttribDlgFloat *fi = new CAttribDlgFloat(std::string("FORCE INTENSITY"), _Node, 0, 100);
		pushWnd(fi);			
		fi->setWrapper(&_ForceIntensityWrapper);
		fi->setSchemeWrapper(&_ForceIntensityWrapper);

		HBITMAP bmh = LoadBitmap(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_FORCE_INTENSITY));
		fi->init(bmh, posX, posY, this);
		

		fi->GetClientRect(&r);
		posY += r.bottom + 3;			
	}

	// vortex (to tune viscosity)
	if (dynamic_cast<NL3D::CPSCylindricVortex *>(_LBTarget))
	{
		CEditableRangeFloat *rv = new CEditableRangeFloat(std::string("RADIAL_VISCOSITY"), _Node, 0, 1);
		pushWnd(rv);
		_RadialViscosityWrapper.V = dynamic_cast<NL3D::CPSCylindricVortex *>(_LBTarget);
		rv->setWrapper(&_RadialViscosityWrapper);
		rv->init(posX + 140, posY, this);
		CStatic *s = new CStatic;
		pushWnd(s);
		s->Create("Radial viscosity : ", SS_LEFT, CRect(posX, posY, posX + 139, posY + 32), this);
		s->SetFont(CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT)));		
		s->ShowWindow(SW_SHOW);


		rv->GetClientRect(&r);
		posY += r.bottom + 3;

		CEditableRangeFloat *tv = new CEditableRangeFloat(std::string("TANGENTIAL_VISCOSITY"), _Node, 0, 1);
		pushWnd(tv);
		_TangentialViscosityWrapper.V = dynamic_cast<NL3D::CPSCylindricVortex *>(_LBTarget);
		tv->setWrapper(&_TangentialViscosityWrapper);
		tv->init(posX + 140, posY, this);

		s = new CStatic;			
		pushWnd(s);
		s->Create("Tangential Viscosity : ", SS_LEFT, CRect(posX, posY, posX + 139, posY + 32), this);
		s->ShowWindow(SW_SHOW);

		tv->GetClientRect(&r);
		posY += r.bottom + 3;
	}

	// deals with emitters that have a direction
	if (dynamic_cast<NL3D::CPSDirection *>(_LBTarget))
	{
		CDirectionAttr *da = new CDirectionAttr(std::string("DIRECTION"));
		pushWnd(da);		
		_DirectionWrapper.E = dynamic_cast<NL3D::CPSDirection *>(_LBTarget);
		da->setWrapper(&_DirectionWrapper);
		da->setDirectionWrapper(dynamic_cast<NL3D::CPSDirection *>(_LBTarget));
		da->init(posX, posY, this);
		da->GetClientRect(&r);
		posY += r.bottom;
	}

	// Brownian (to tune parametric factor)
	if (dynamic_cast<NL3D::CPSBrownianForce *>(_LBTarget))
	{
		CEditableRangeFloat *rv = new CEditableRangeFloat(std::string("PARAMETRIC_FACTOR"), _Node, 0, 64);
		pushWnd(rv);
		_ParamFactorWrapper.F = static_cast<NL3D::CPSBrownianForce *>(_LBTarget);
		rv->setWrapper(&_ParamFactorWrapper);
		rv->init(posX + 140, posY, this);
		CStatic *s = new CStatic;
		pushWnd(s);
		s->Create("Parametric factor : ", SS_LEFT, CRect(posX, posY, posX + 139, posY + 40), this);
		s->SetFont(CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT)));		
		s->ShowWindow(SW_SHOW);

		rv->GetClientRect(&r);
		posY += r.bottom + 3;
	
	}



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