// 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 "vegetable_dlg.h"
#include "vegetable_density_page.h"
#include "vegetable_apperance_page.h"
#include "vegetable_scale_page.h"
#include "vegetable_rotate_page.h"
#include "vegetable_copy_dlg.h"
#include "vegetable_edit_tools.h"
#include "vegetable_wind_dlg.h"
#include "nel/3d/vegetable.h"
#include "nel/3d/tile_vegetable_desc.h"



/////////////////////////////////////////////////////////////////////////////
// CVegetableDlg dialog


CVegetableDlg::CVegetableDlg(CObjectViewer *viewer, CWnd* pParent /*=NULL*/)
	: CDialog(CVegetableDlg::IDD, pParent), _ObjView(viewer),
	_PropertySheet(NULL), _VegetableDensityPage(NULL), _VegetableApperancePage(NULL), 
	_VegetableScalePage(NULL), _VegetableRotatePage(NULL),
	_VegetableWindDlg(NULL)
{
	nlassert(viewer);

	_LastVegetSetName= "*.vegetset";

	// init VegetableList
	VegetableList.VegetableDlg= this;

	//{{AFX_DATA_INIT(CVegetableDlg)
	//}}AFX_DATA_INIT
}


void CVegetableDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CVegetableDlg)
	DDX_Control(pDX, IDC_LIST_VEGETABLE, VegetableList);
	DDX_Control(pDX, IDC_STATIC_VEGETABLE_PERF, StaticPolyCount);
	DDX_Control(pDX, IDC_CHECK_VEGETABLE_SNAPTOGROUND, CheckSnapToGround);
	DDX_Control(pDX, IDC_CHECK_VEGETABLE_ENABLE, CheckEnableVegetable);
	DDX_Control(pDX, IDC_CHECK_VEGETABLE_AUTOMATIC, CheckAutomaticRefresh);
	DDX_Control(pDX, IDC_BUTTON_VEGETABLE_REFRESH, ButtonRefreshLandscape);
	DDX_Control(pDX, IDC_CHECK_VEGETABLE_SHOW, CheckShowLandscape);
	DDX_Control(pDX, IDC_STATIC_SELECT_VEGETABLE, SelectVegetableStaticText);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CVegetableDlg, CDialog)
	//{{AFX_MSG_MAP(CVegetableDlg)
	ON_WM_DESTROY()
	ON_LBN_SELCHANGE(IDC_LIST_VEGETABLE, OnSelchangeListVegetable)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_ADD, OnButtonVegetableAdd)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_CLEAR, OnButtonVegetableClear)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_INSERT, OnButtonVegetableInsert)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_LOAD_DESC, OnButtonVegetableLoadDesc)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_LOAD_SET, OnButtonVegetableLoadSet)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_REMOVE, OnButtonVegetableRemove)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_SAVE_DESC, OnButtonVegetableSaveDesc)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_SAVE_SET, OnButtonVegetableSaveSet)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_APPEND_SET, OnButtonVegetableAppendSet)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_COPY, OnButtonVegetableCopy)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_REFRESH, OnButtonVegetableRefresh)
	ON_BN_CLICKED(IDC_CHECK_VEGETABLE_SHOW, OnCheckVegetableShow)
	ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_SETUP_WIND, OnButtonVegetableSetupWind)
	ON_BN_CLICKED(IDC_CHECK_VEGETABLE_AUTOMATIC, OnCheckVegetableAutomatic)
	ON_BN_CLICKED(IDC_CHECK_VEGETABLE_ENABLE, OnCheckVegetableEnable)
	ON_BN_CLICKED(IDC_CHECK_VEGETABLE_SNAPTOGROUND, OnCheckVegetableSnaptoground)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVegetableDlg message handlers

void CVegetableDlg::OnDestroy() 
{
	setRegisterWindowState (this, REGKEY_OBJ_VIEW_VEGETABLE_DLG);

	CDialog::OnDestroy();
	
	// TODO: Add your message handler code here
	
}


CVegetableDlg::~CVegetableDlg()
{
	#define  REMOVE_WND(wnd) if (wnd) { wnd->DestroyWindow(); delete wnd; }
	REMOVE_WND(_VegetableDensityPage);
	REMOVE_WND(_VegetableApperancePage);	
	REMOVE_WND(_VegetableScalePage);
	REMOVE_WND(_VegetableRotatePage);
	REMOVE_WND(_PropertySheet);	
	// destroy and remove wind dialog
	REMOVE_WND(_VegetableWindDlg);	
}




// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************


// ***************************************************************************
void			CVegetableDlg::doRefreshVegetableDisplay()
{
	NL3D::CTileVegetableDesc	vegetSet;

	// first build the vegetSet, but don't keep <default> shapeName. and skip Hiden vegetables too
	buildVegetableSet(vegetSet, false, false);

	// then refresh window.
	_ObjView->refreshVegetableLandscape(vegetSet);
}


// ***************************************************************************
void			CVegetableDlg::refreshVegetableDisplay()
{
	// if automatic refresh is checked.
	if(CheckAutomaticRefresh.GetCheck()==1)
		// then do it
		doRefreshVegetableDisplay();
}


// ***************************************************************************
void			CVegetableDlg::setVegetableToEdit(NL3D::CVegetable *vegetable)
{
	if(vegetable == NULL)
	{
		// Show the SelectVegetableStaticText
		SelectVegetableStaticText.ShowWindow(true);

		// Hide the property sheet.
		_PropertySheet->ShowWindow(false);
	}
	else
	{
		// Hide the SelectVegetableStaticText
		SelectVegetableStaticText.ShowWindow(false);

		// Setup 3 property pages.
		_VegetableDensityPage->setVegetableToEdit(vegetable);
		_VegetableApperancePage->setVegetableToEdit(vegetable);
		_VegetableScalePage->setVegetableToEdit(vegetable);
		_VegetableRotatePage->setVegetableToEdit(vegetable);

		// Show the property sheet.
		_PropertySheet->ShowWindow(true);
	}
}

// ***************************************************************************
uint				CVegetableDlg::getNumVegetables() const
{
	return (uint)_Vegetables.size();
}
// ***************************************************************************
std::string			CVegetableDlg::getVegetableName(uint id) const
{
	nlassert(id<_Vegetables.size());
	return	_Vegetables[id].VegetableName;
}
// ***************************************************************************
void				CVegetableDlg::updateCurSelVegetableName()
{
	sint	id= VegetableList.GetCurSel();
	if(id!=LB_ERR)
	{
		_Vegetables[id].updateVegetableName();
		// replace name in the listBox: must delete, and re-insert
		VegetableList.DeleteString(id);
		VegetableList.InsertString(id, _Vegetables[id].VegetableName.c_str());
		VegetableList.SetCurSel(id);
	}
}

// ***************************************************************************
NL3D::CVegetable	*CVegetableDlg::getVegetable(uint id) const
{
	nlassert(id<_Vegetables.size());
	return _Vegetables[id].Vegetable;
}


static const char	*NL_DefaultVegetName= "<default>";

// ***************************************************************************
CVegetableDlg::CVegetableDesc::CVegetableDesc()
{
	Vegetable= NULL;
	VegetableName= NL_DefaultVegetName;
	Visible= true;
}

// ***************************************************************************
void		CVegetableDlg::CVegetableDesc::initDefaultVegetable()
{
	Vegetable= new NL3D::CVegetable;
	// update vegetableName according to Vegetable
	updateVegetableName();

	// init Vegetable with some good default values.

	// General/Density.
	// Density.
	Vegetable->Density.Abs= NL_VEGETABLE_DENSITY_ABS_DEFAULT;
	Vegetable->Density.Rand= NL_VEGETABLE_DENSITY_RAND_DEFAULT;
	Vegetable->Density.Frequency= NL_VEGETABLE_FREQ_DEFAULT;
	// disable MaxDensity
	Vegetable->MaxDensity= -1;
	// Leave ShapeName to ""
	// Default DistType is always 0.
	Vegetable->DistType= 0;


	// Apperance
	// BendPhase
	Vegetable->BendPhase.Abs= NL_VEGETABLE_BENDPHASE_ABS_DEFAULT;
	Vegetable->BendPhase.Rand= NL_VEGETABLE_BENDPHASE_RAND_DEFAULT;
	Vegetable->BendPhase.Frequency= NL_VEGETABLE_FREQ_DEFAULT;
	// BendFactor
	Vegetable->BendFactor.Abs= NL_VEGETABLE_BENDFACTOR_ABS_DEFAULT;
	Vegetable->BendFactor.Rand= NL_VEGETABLE_BENDFACTOR_RAND_DEFAULT;
	Vegetable->BendFactor.Frequency= NL_VEGETABLE_FREQ_DEFAULT;
	// Color
	Vegetable->Color.NoiseValue.Abs= NL_VEGETABLE_COLOR_ABS_DEFAULT;
	Vegetable->Color.NoiseValue.Rand= NL_VEGETABLE_COLOR_RAND_DEFAULT;
	Vegetable->Color.NoiseValue.Frequency= NL_VEGETABLE_FREQ_DEFAULT;

	// Scale
	// ScaleXY
	Vegetable->Sxy.Abs= NL_VEGETABLE_SCALE_ABS_DEFAULT;
	Vegetable->Sxy.Rand= NL_VEGETABLE_SCALE_RAND_DEFAULT;
	Vegetable->Sxy.Frequency= NL_VEGETABLE_FREQ_DEFAULT;
	// ScaleZ.
	Vegetable->Sz.Abs= NL_VEGETABLE_SCALE_ABS_DEFAULT;
	Vegetable->Sz.Rand= NL_VEGETABLE_SCALE_RAND_DEFAULT;
	Vegetable->Sz.Frequency= NL_VEGETABLE_FREQ_DEFAULT;

	// Rotate
	// RotateX
	Vegetable->Rx.Abs= NL_VEGETABLE_ROTATEX_ABS_DEFAULT;
	Vegetable->Rx.Rand= NL_VEGETABLE_ROTATEX_RAND_DEFAULT;
	Vegetable->Rx.Frequency= NL_VEGETABLE_FREQ_DEFAULT;
	// RotateY
	Vegetable->Ry.Abs= NL_VEGETABLE_ROTATEY_ABS_DEFAULT;
	Vegetable->Ry.Rand= NL_VEGETABLE_ROTATEY_RAND_DEFAULT;
	Vegetable->Ry.Frequency= NL_VEGETABLE_FREQ_DEFAULT;
	// RotateZ
	Vegetable->Rz.Abs= NL_VEGETABLE_ROTATEZ_ABS_DEFAULT;
	Vegetable->Rz.Rand= NL_VEGETABLE_ROTATEZ_RAND_DEFAULT;
	Vegetable->Rz.Frequency= NL_VEGETABLE_ROTATEZ_FREQ_DEFAULT;

}

// ***************************************************************************
void		CVegetableDlg::CVegetableDesc::initVegetable(const NL3D::CVegetable &vegetable)
{
	Vegetable= new NL3D::CVegetable(vegetable);
	// update vegetableName according to Vegetable
	updateVegetableName();
}


// ***************************************************************************
void		CVegetableDlg::CVegetableDesc::updateVegetableName()
{
	// Build the vegetable Name according to the ShapeName
	if(Vegetable->ShapeName=="")
	{
		VegetableName= NL_DefaultVegetName;
	}
	else
	{
		std::string::size_type pos= Vegetable->ShapeName.find(".veget");
		VegetableName= Vegetable->ShapeName.substr(0, pos);
		// And (to be clearer) append distance of creation.
		char	str[256];
		sprintf(str, " - %dm", (Vegetable->DistType+1)*10);
		VegetableName+= str;
		// NB: if you add info with other parameters, you must use updateCurSelVegetableName() if they change
	}
}


// ***************************************************************************
void		CVegetableDlg::CVegetableDesc::deleteVegetable()
{
	delete Vegetable;
	Vegetable= NULL;
	VegetableName= NL_DefaultVegetName;
}


// ***************************************************************************
void		CVegetableDlg::clearVegetables()
{
	// delete all vegetables.
	for(uint i=0; i<_Vegetables.size(); i++)
	{
		_Vegetables[i].deleteVegetable();
	}
	_Vegetables.clear();

	// update view
	VegetableList.ResetContent();
	setVegetableToEdit(NULL);
}


// ***************************************************************************
bool		CVegetableDlg::loadVegetableSet(NL3D::CTileVegetableDesc &vegetSet, const char *title)
{
	vegetSet.clear();
	bool	ok= false;

	CFileDialog fd(TRUE, ".vegetset", "*.vegetset", 0, NULL, this) ;
	fd.m_ofn.lpstrTitle= title;
	if (fd.DoModal() == IDOK)
	{
		NLMISC::CIFile	f;
		
		ok= true;

		if( f.open((const char*)fd.GetPathName()) )
		{
			try
			{
				// read the vegetable
				f.serial(vegetSet);
				// bkup fileName.
				_LastVegetSetName= (const char*)fd.GetFileName();
			}
			catch(NLMISC::EStream &)
			{
				ok= false;
				MessageBox("Failed to load file!");
			}
		}
		else
		{
			ok= false;
			MessageBox("Failed to open file!");
		}
	}

	return ok;
}

// ***************************************************************************
void		CVegetableDlg::buildVegetableSet(NL3D::CTileVegetableDesc &vegetSet, bool keepDefaultShapeName, bool keepHiden )
{
	vegetSet.clear();
	float	degToRad= (float)(NLMISC::Pi / 180.f);

	// build the list.
	std::vector<NL3D::CVegetable>	vegetables;
	for(uint i=0;i<_Vegetables.size();i++)
	{
		// if don't want to keep <default> ShapeNames, skip them.
		if(!keepDefaultShapeName && _Vegetables[i].Vegetable->ShapeName=="")
			continue;
		// if don't want to keep hiden vegetables, skip them.
		if(!keepHiden && !_Vegetables[i].Visible)
			continue;

		vegetables.push_back(*_Vegetables[i].Vegetable);
		// get dst index.
		uint	dstId= (uint)vegetables.size()-1;
		// transform degrees in radians.
		vegetables[dstId].Rx.Abs*= degToRad;
		vegetables[dstId].Rx.Rand*= degToRad;
		vegetables[dstId].Ry.Abs*= degToRad;
		vegetables[dstId].Ry.Rand*= degToRad;
		vegetables[dstId].Rz.Abs*= degToRad;
		vegetables[dstId].Rz.Rand*= degToRad;
	}

	// build the set.
	vegetSet.build(vegetables);
}


// ***************************************************************************
void		CVegetableDlg::appendVegetableSet(NL3D::CTileVegetableDesc &vegetSet)
{
	float	radToDeg= (float)(180.f / NLMISC::Pi);

	// for all distances Types.
	for(uint distType=0; distType<NL3D_VEGETABLE_BLOCK_NUMDIST; distType++)
	{
		// retrieve list of vegetable
		const std::vector<NL3D::CVegetable>		&vegetList= vegetSet.getVegetableList(distType);

		// for all of them
		for(uint i=0;i<vegetList.size();i++)
		{
			// append the vegetable to the list.
			NL3D::CVegetable	veget= vegetList[i];

			// transform radians into degrees.
			veget.Rx.Abs*= radToDeg;
			veget.Rx.Rand*= radToDeg;
			veget.Ry.Abs*= radToDeg;
			veget.Ry.Rand*= radToDeg;
			veget.Rz.Abs*= radToDeg;
			veget.Rz.Rand*= radToDeg;

			// Add a new vegetable to the list.
			_Vegetables.push_back( CVegetableDesc ());
			uint	id= (uint)_Vegetables.size()-1;
			_Vegetables[id].initVegetable(veget);

			// update view
			VegetableList.AddString(_Vegetables[id].VegetableName.c_str());
		}
	}
}


// ***************************************************************************
// ***************************************************************************
// CVegetableDlg message handlers
// ***************************************************************************
// ***************************************************************************


// ***************************************************************************
BOOL CVegetableDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();


	_PropertySheet= new CPropertySheet();

	// Create the 4 pages.
	// density
	_VegetableDensityPage= new CVegetableDensityPage();
	_VegetableDensityPage->initVegetableDlg(this);
	_PropertySheet->AddPage(_VegetableDensityPage);
	// appearance
	_VegetableApperancePage= new CVegetableApperancePage();
	_VegetableApperancePage->initVegetableDlg(this);
	_PropertySheet->AddPage(_VegetableApperancePage);
	// scale
	_VegetableScalePage= new CVegetableScalePage();
	_VegetableScalePage->initVegetableDlg(this);
	_PropertySheet->AddPage(_VegetableScalePage);
	// rot
	_VegetableRotatePage= new CVegetableRotatePage();
	_VegetableRotatePage->initVegetableDlg(this);
	_PropertySheet->AddPage(_VegetableRotatePage);

	// Create the _PropertySheet in the DialogBox.
	_PropertySheet->Create(this, WS_CHILD | DS_CONTROL | WS_VISIBLE, 0);
	// Enlarge at max size of the PropertySheet
	_PropertySheet->MoveWindow(160, 0, 1000, 570);


	// Force creation of the 4 pages, by selecting them.
	_PropertySheet->SetActivePage(0);
	_PropertySheet->SetActivePage(1);
	_PropertySheet->SetActivePage(2);
	_PropertySheet->SetActivePage(3);
	// Start with Density page selected.
	_PropertySheet->SetActivePage(0);


	// Init the Dlg with no vegetable to edit.
	setVegetableToEdit(NULL);

	// Enable the Automatic update by default.
	CheckAutomaticRefresh.SetCheck(1);
	CheckEnableVegetable.SetCheck(1);
	CheckSnapToGround.SetCheck(1);

	// Disable the refresh button, because landscape not displayed by default
	ButtonRefreshLandscape.EnableWindow(false);


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


// ***************************************************************************
void CVegetableDlg::OnSelchangeListVegetable() 
{
	// set the new vegetable to edit.
	sint	id= VegetableList.GetCurSel();
	if(id==LB_ERR)
		setVegetableToEdit( NULL );
	else
		setVegetableToEdit( _Vegetables[id].Vegetable );
}

void CVegetableDlg::OnButtonVegetableAdd() 
{
	// Add a new vegetable to the list.
	_Vegetables.push_back(CVegetableDesc ());
	uint	id= (uint)_Vegetables.size()-1;
	_Vegetables[id].initDefaultVegetable();

	// update view
	VegetableList.AddString(_Vegetables[id].VegetableName.c_str());

	// update 3D view
	refreshVegetableDisplay();
}

void CVegetableDlg::OnButtonVegetableClear() 
{
	if(_Vegetables.size()==0)
		return;

	if( MessageBox("Clear all the list?", "Clear List", MB_OKCANCEL | MB_ICONWARNING | MB_APPLMODAL)==IDOK )
	{
		clearVegetables();

		// update 3D view
		refreshVegetableDisplay();
	}
}

void CVegetableDlg::OnButtonVegetableInsert() 
{
	sint	id= VegetableList.GetCurSel();
	if(id!=LB_ERR)
	{
		// Add a new vegetable to the list.
		_Vegetables.insert(_Vegetables.begin()+id, CVegetableDesc());
		_Vegetables[id].initDefaultVegetable();

		// update view
		VegetableList.InsertString(id, _Vegetables[id].VegetableName.c_str());

		// update 3D view
		refreshVegetableDisplay();
	}
	else
	{
		// perform like an add.
		OnButtonVegetableAdd();
	}
}

void CVegetableDlg::OnButtonVegetableRemove() 
{
	sint	id= VegetableList.GetCurSel();
	if(id!=LB_ERR)
	{
		// UnSelect
		setVegetableToEdit(NULL);

		// erase the vegetable from the list.
		_Vegetables[id].deleteVegetable();
		_Vegetables.erase(_Vegetables.begin()+id);

		// update view
		VegetableList.DeleteString(id);

		// select if posssible at the same id.
		if(id>=(sint)_Vegetables.size())
			id--;
		if(id>=0)
		{
			// set the cur selection
			VegetableList.SetCurSel(id);
			// And set the new to edit
			OnSelchangeListVegetable();
		}

		// update 3D view
		refreshVegetableDisplay();
	}
}

// ***************************************************************************
void CVegetableDlg::OnButtonVegetableLoadDesc() 
{
	CFileDialog fd(TRUE, ".vegetdesc", "*.vegetdesc", 0, NULL, this) ;
	fd.m_ofn.lpstrTitle= "Open Vegetable Descriptor";
	if (fd.DoModal() == IDOK)
	{
		NLMISC::CIFile	f;
		
		if( f.open((const char*)fd.GetPathName()) )
		{
			NL3D::CVegetable	veget;
			try
			{
				// read the vegetable
				f.serial(veget);
				// Add a new vegetable to the list.
				_Vegetables.push_back(CVegetableDesc ());
				uint	id= (uint)_Vegetables.size()-1;
				_Vegetables[id].initVegetable(veget);

				// update view
				VegetableList.AddString(_Vegetables[id].VegetableName.c_str());

				// update 3D view
				refreshVegetableDisplay();
			}
			catch(NLMISC::EStream &)
			{
				MessageBox("Failed to load file!");
			}
		}
		else
		{
			MessageBox("Failed to open file!");
		}
	}

}

void CVegetableDlg::OnButtonVegetableSaveDesc() 
{
	sint	id= VegetableList.GetCurSel();
	if(id!=LB_ERR)
	{
		NL3D::CVegetable	&veget= *_Vegetables[id].Vegetable;

		std::string		fileName= _Vegetables[id].VegetableName + ".vegetdesc";

		CFileDialog fd(FALSE, "vegetdesc", fileName.c_str(), OFN_OVERWRITEPROMPT, "VegetDescFiles (*.vegetdesc)|*.vegetdesc|All Files (*.*)|*.*||", this) ;
		fd.m_ofn.lpstrTitle= "Save Vegetable Descriptor";
		if (fd.DoModal() == IDOK)
		{
			NLMISC::COFile	f;
			
			if( f.open((const char*)fd.GetPathName()) )
			{
				try
				{
					// save the vegetable
					f.serial(veget);
				}
				catch(NLMISC::EStream &)
				{
					MessageBox("Failed to save file!");
				}
			}
			else
			{
				MessageBox("Failed to open file for write!");
			}
		}
	}

}


// ***************************************************************************
void CVegetableDlg::OnButtonVegetableLoadSet() 
{
	NL3D::CTileVegetableDesc	vegetSet;
	// if succes to load the vegetSet
	if(loadVegetableSet(vegetSet, "Load Vegetable Set"))
	{
		// Delete all vegetables.
		clearVegetables();

		// build them from list.
		appendVegetableSet(vegetSet);

		// update 3D view
		refreshVegetableDisplay();
	}
}


void CVegetableDlg::OnButtonVegetableAppendSet() 
{
	NL3D::CTileVegetableDesc	vegetSet;
	// if succes to load the vegetSet
	if(loadVegetableSet(vegetSet, "Append Vegetable Set"))
	{
		// Do not Delete any vegetables.
		// build them from list.
		appendVegetableSet(vegetSet);

		// update 3D view
		refreshVegetableDisplay();
	}
}


void CVegetableDlg::OnButtonVegetableSaveSet() 
{
	NL3D::CTileVegetableDesc	vegetSet;

	// first build the vegetSet.
	buildVegetableSet(vegetSet);

	// Then try to save it.
	CFileDialog fd(FALSE, "vegetset", _LastVegetSetName.c_str(), OFN_OVERWRITEPROMPT, "VegetSetFiles (*.vegetset)|*.vegetset|All Files (*.*)|*.*||", this) ;
	fd.m_ofn.lpstrTitle= "Save Vegetable Set";
	if (fd.DoModal() == IDOK)
	{
		NLMISC::COFile	f;
		
		if( f.open((const char*)fd.GetPathName()) )
		{
			try
			{
				// save the vegetable set
				f.serial(vegetSet);
			}
			catch(NLMISC::EStream &)
			{
				MessageBox("Failed to save file!");
			}
		}
		else
		{
			MessageBox("Failed to open file for write!");
		}
	}
	
}


// ***************************************************************************
void CVegetableDlg::OnButtonVegetableCopy() 
{
	sint	dstid= VegetableList.GetCurSel();
	if(dstid!=LB_ERR)
	{
		CVegetableCopyDlg	dlg(this);

		if(dlg.DoModal()==IDOK)
		{
			sint	srcid= dlg.VegetableSelected;
			if(srcid!=LB_ERR && srcid!=dstid)
			{
				// copy from src to dst
				NL3D::CVegetable	&vegetSrc= *_Vegetables[srcid].Vegetable;
				NL3D::CVegetable	&vegetDst= *_Vegetables[dstid].Vegetable;

				// copy all?
				if(!dlg.SubsetCopy)
				{
					// copy all the vegetable
					vegetDst= vegetSrc;
				}
				else
				{
					// copy mesh part.
					if(dlg.Mesh)
					{
						vegetDst.ShapeName= vegetSrc.ShapeName;
					}
					// Density/dist.
					if(dlg.Distance)
						vegetDst.DistType = vegetSrc.DistType;
					if(dlg.Density)
						vegetDst.Density = vegetSrc.Density;
					if(dlg.MaxDensity)
						vegetDst.MaxDensity = vegetSrc.MaxDensity;
					if(dlg.AngleSetup)
					{
						switch(vegetSrc.getAngleType())
						{
						case NL3D::CVegetable::AngleGround:
							vegetDst.setAngleGround(vegetSrc.getCosAngleMin());
							break;
						case NL3D::CVegetable::AngleCeiling:
							vegetDst.setAngleCeiling(vegetSrc.getCosAngleMax());
							break;
						case NL3D::CVegetable::AngleWall:
							vegetDst.setAngleWall(vegetSrc.getCosAngleMin(), vegetSrc.getCosAngleMax());
							break;
						}
					}
					// Appearance
					if(dlg.BendPhase)
						vegetDst.BendPhase = vegetSrc.BendPhase;
					if(dlg.BendFactor)
						vegetDst.BendFactor = vegetSrc.BendFactor;
					if(dlg.ColorNoise)
						vegetDst.Color.NoiseValue = vegetSrc.Color.NoiseValue;
					if(dlg.ColorSetup)
						vegetDst.Color.Gradients = vegetSrc.Color.Gradients;
					// Scale/Rot
					if(dlg.ScaleXY)
						vegetDst.Sxy = vegetSrc.Sxy;
					if(dlg.ScaleZ)
						vegetDst.Sz = vegetSrc.Sz;
					if(dlg.RotateX)
						vegetDst.Rx = vegetSrc.Rx;
					if(dlg.RotateY)
						vegetDst.Ry = vegetSrc.Ry;
					if(dlg.RotateZ)
						vegetDst.Rz = vegetSrc.Rz;
				}

				// update dst vegetableName according to Vegetable copied
				_Vegetables[dstid].updateVegetableName();


				// deselect, then reselect, to refresh.
				setVegetableToEdit(NULL);
				// set the cur selection
				VegetableList.SetCurSel(dstid);
				// And set the new to edit
				OnSelchangeListVegetable();

				// must also update our name in view
				updateCurSelVegetableName();


				// update 3D view
				refreshVegetableDisplay();
			}
		}
	}
}

void CVegetableDlg::OnButtonVegetableRefresh() 
{
	// refresh view, independently of checkBox
	doRefreshVegetableDisplay();
}

void CVegetableDlg::OnCheckVegetableAutomatic() 
{
	// Enabling the checkBox do a refresh (NB: disabling don't do a refresh).
	refreshVegetableDisplay();
}

void CVegetableDlg::OnCheckVegetableShow() 
{
	if(CheckShowLandscape.GetCheck()==1)
	{
		// Landscape not created ??
		if(!_ObjView->isVegetableLandscapeCreated())
		{
			// if success to create / Load the landscape.
			if(_ObjView->createVegetableLandscape())
			{
				// Enable the refresh button
				ButtonRefreshLandscape.EnableWindow(true);

				// refresh view, independently of checkBox
				doRefreshVegetableDisplay();
			}
			else
			{
				// Failed in load, never retry.
				CheckShowLandscape.SetCheck(0);
				CheckShowLandscape.EnableWindow(false);
			}
		}

		// show the landscape
		_ObjView->showVegetableLandscape();
	}
	else
	{
		_ObjView->hideVegetableLandscape();
	}
}


// ***************************************************************************
void CVegetableDlg::OnCheckVegetableEnable() 
{
	// update view.
	_ObjView->enableLandscapeVegetable(CheckEnableVegetable.GetCheck()==1);
}


// ***************************************************************************
void CVegetableDlg::OnButtonVegetableSetupWind() 
{
	// create the window if necessary
	if(!_VegetableWindDlg)
	{
		_VegetableWindDlg= new CVegetableWindDlg(_ObjView, this);
		_VegetableWindDlg->Create(CVegetableWindDlg::IDD, this);
	}

	// show the window.
	_VegetableWindDlg->ShowWindow(true);
}


// ***************************************************************************
void CVegetableDlg::OnCheckVegetableSnaptoground() 
{
	// update view.
	_ObjView->snapToGroundVegetableLandscape(CheckSnapToGround.GetCheck()==1);
}


// ***************************************************************************
void CVegetableDlg::swapShowHideVegetable (uint id)
{
	if(id>=_Vegetables.size())
		return;

	_Vegetables[id].Visible ^= true;

	// update 3D view
	refreshVegetableDisplay();
}

// ***************************************************************************
void CVegetableDlg::setShowHideVegetable (uint id, bool visible, bool refreshDisplay)
{
	if(id>=_Vegetables.size())
		return;

	_Vegetables[id].Visible= visible;

	// update 3D view
	if(refreshDisplay)
		refreshVegetableDisplay();
}

// ***************************************************************************
bool CVegetableDlg::isVegetableVisible (uint id)
{
	if(id>=_Vegetables.size())
		return true;

	return _Vegetables[id].Visible;
}