/*------------------------------------------------------------------------------*
 * File Name:	ImageProfile.h 													*
 * Creation: 																	*
 * Purpose: OriginC Head file													*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Kyle 07/14/2010 ORG-572-P1 SET_GRAPH_NOCLICK_AND_RESET_NOCLICK_ON_CLOSE		*
 *------------------------------------------------------------------------------*/
 
#ifndef _IMAGE_PROFILE_H
#define _IMAGE_PROFILE_H

#include <ocTriContour.h>


#define ImageProfileOutput(_output)		out_str(_output)

#ifdef _IMAGE_PROFILE_DEBUG
#include <Profiler.h>
#define TIME_PROFILER Profiler junk
#else
#define TIME_PROFILER
#endif _IMAGE_PROFILE_DEBUG

/* class structure

ImageProfileDlg <= ImageProfileManager


ImageProfileHolder <= ImageProfileManager <= ImageProfilerPath <= GraphObject -- ImageProfileLine -- ImageProfileHVLine
													|		 |<= GraphLayer						|-- ImageProfileAbitraryLine
													|		 |<= Worksheet						|-- ImageProfilePolyLine
													|
								--------------------------------------------
								|					|						|
				ImageProfilerHVPath		ImageProfilerPolyLinePath	ImageProfilerAbitraryLinePath
*/


#define WM_USER_IMAGE_PROFILE_UPDATE					(WM_USER + 1200)

#define STR_IMAGE_PROFILE_OBJ_EVENT_LT_SCRIPT			"run.section(graph_controls, ImageProfile, %1);"
#define STR_IMAGE_PROFILE_READ_OUT_LT_SCRIPT			"run.section(graph_controls, ImageProfile_ReadOut, %1);"

#define STR_IMAGE_PROFILE_STORAGE						"IProfileStorate"
#define STR_IMAGE_PROFILE_PATH_INDEX_ATTRIB				"PathIndex"			///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP

#define STR_PROFILE_GRAPH		"ProfilePlot"
#define STR_PROFILE_BOOK		"ProfileData"
#define STR_PROFILE_SHEET		"Profile"

enum {
	GRAPH_SOURCE_LAYER,
	GRAPH_VLINE_LAYER,
	GRAPH_HLINE_LAYER
};

struct TemplateLayerInfo
{
	int nMainLayer;
	int nVLineLayer;
	int nHLineLayer;
};

#define STR_OUT_WKS_UDL_VLINE		_L("X Value")
#define STR_OUT_WKS_UDL_HLINE		_L("Y Value")

/*----------------------------------------------------------------------------*/
/* Image Profile Update Event
/*----------------------------------------------------------------------------*/
enum
{
	IPUPDATE_NO_CHANGE,						///Kyle 06/09/2010 ORG-98 CENTRALIZE_EVENT_HANDLING
	IPUPDATE_ACTIVE_PROFILE_CHANGE,
	IPUPDATE_ACTIVE_PATH_CHANGE,

	IPUPDATE_LAYOUT_MODE_CHANGE,

	///Kyle 06/09/2010 ORG-98 CENTRALIZE_EVENT_HANDLING
	// events should be handled in ImageProfileHolder
	IPUPDATE_PROFILE_DELETED,
	///End CENTRALIZE_EVENT_HANDLING

	///Kyle 06/17/2010 ORG-98 ADD_DIRTY_BITS_FOR_GUI_UPDATE
	//IPUPDATE_PATH_CONTENT,
	IPUPDATE_PATH_CONTENTS				= 0xFFF00000,
	IPUPDATE_PATH_CONTENT_COLOR			= 0x10000000,
	IPUPDATE_PATH_CONTENT_WIDTH			= 0x20000000,
	IPUPDATE_PATH_CONTENT_POSITION		= 0x40000000,
	///End ADD_DIRTY_BITS_FOR_GUI_UPDATE
};

/*----------------------------------------------------------------------------*/
/* Profile Type
/*----------------------------------------------------------------------------*/
#define	STR_PROFILE_TYPE_LIST				_L("Crossed Lines|Arbitrary Line|Polyline")
enum{
	//CROSSED_LINES_IMAGE_PROFILE,
	VERTICAL_LINE_IMAGE_PROFILE,
	HORIZONTAL_LINE_IMAGE_PROFILE,
	ARBITRARY_LINE_IMAGE_PROFILE,

	POLYLINE_IMAGE_PROFILE,

	//others...
	
	TOTAL_IMAGE_PROFILE
};

#define IS_VALID_PATH_TYPE(_TYPE)		(0 <= (_TYPE) && (_TYPE) < TOTAL_IMAGE_PROFILE)

///Kyle 06/22/2010 ORG-355 CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
/*
#define CROSSED_LINE_VERTICAL			1
#define CROSSED_LINE_HORIZONTAL			2
*/
enum
{
	LTYPE_POLYLINE,

	LTYPE_CROSSED_LINE_VERTICAL,
	LTYPE_CROSSED_LINE_HORIZONTAL,
	
	LTYPE_ABITRARY_LINE_VERTICAL,
	LTYPE_ABITRARY_LINE_HORIZONTAL,
};
///End CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE

/*----------------------------------------------------------------------------*/
/* Layout Mode
/*----------------------------------------------------------------------------*/
enum
{
	IMAGE_PROFILE_LAYOUT_SAME_GRAPH_CLINE,
	IMAGE_PROFILE_LAYOUT_SAME_GRAPH_VLINE,
	IMAGE_PROFILE_LAYOUT_SAME_GRAPH_HLINE,

	IMAGE_PROFILE_LAYOUT_SEPARATE_GRAPH		= 0x00001000,
};

enum
{
	IPROFILE_PROTECT_SOURCE 			= 0x00000001,
};

///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
enum
{
	
	IPROFILE_PATH_WIDTH_UNITS		= 0x00000007,
	IPROFILE_PATH_WIDTH_PIXEL		= 0,
	IPROFILE_PATH_WIDTH_SCALE		= 1,
	//IPROFILE_PATH_WIDTH_CUSTOM		= 0x00000008,			///Kyle 06/17/2010 ORG-98-S40 NEW_WIDTH_CONTROL_WITHOUT_DROP_DOWN

};

#define SET_WIDTH_UNIT(_dw, _nn)		(((_dw) & ~IPROFILE_PATH_WIDTH_UNITS) | ((_nn) & IPROFILE_PATH_WIDTH_UNITS))
///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE

#define STR_REOPEN_TEXT_BOX_NAME		"ProfileButton"
///Kyle 07/16/2010 ORG-584-S1 RENAME_REOPEN_BUTTON_AND_GIVE_BETTER_POSITION
//#define STR_REOPEN_TEXT_BOX_LABEL		_L("Profile")
#define STR_REOPEN_TEXT_BOX_LABEL		_L("Profile...")
///End RENAME_REOPEN_BUTTON_AND_GIVE_BETTER_POSITION

enum 
{
	TEXT_LOC_LEFT,
	TEXT_LOC_RIGHT
};

enum 
{
	TEXT_LOC_TOP,
	TEXT_LOC_BOTTOM
};

#define TEXT_LOC_DEFAULT 	TEXT_LOC_LEFT

//class ImageProfilePathInfo;
/*----------------------------------------------------------------------------*/
/* ImageProfileLine
/*----------------------------------------------------------------------------*/
class ImageProfileLine : public GraphObject
{
public:
	ImageProfileLine()
	{
	}
	/// Iris 6/08/2010 ORG_98-P12 FIX_DUPLICATE_PATH_NOT_INCLUDED_VALUE_TEXT
	ImageProfileLine(GraphObject& go) : GraphObject(go)
	{
	}
	///End FIX_DUPLICATE_PATH_NOT_INCLUDED_VALUE_TEXT
	~ImageProfileLine()
	{
	}
	/// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT
	/*
	virtual bool Create(GraphLayer& gl, double dLineWidth, int nColor, bool bVertical, double dPos) {ASSERT(0); return false;}
	
	virtual bool AddReadOut(GraphLayer& gl, bool bVertical, double dPos) {ASSERT(0); return false;}
	*/
	virtual bool Create(GraphLayer& gl, double dLineWidth, int nColor, bool bVertical, double dPos, int nTextObjectLocation = TEXT_LOC_DEFAULT) {ASSERT(0); return false;}
	
	virtual bool AddReadOut(GraphLayer& gl, bool bVertical, double dPos, int nTextObjectLocation = TEXT_LOC_DEFAULT) {ASSERT(0); return false;}	
	///End NEW_SUGGESTION_FOR_TEXT_OBJECT
};

/*----------------------------------------------------------------------------*/
/* ImageProfileHVLine
/*----------------------------------------------------------------------------*/
#define STR_HORIZONTAL_NAME_PREFIX		"HLine"
#define STR_VERTICAL_NAME_PREFIX		"VLine"
class ImageProfileHVLine : public ImageProfileLine
{
public:
	ImageProfileHVLine() : ImageProfileLine()
	{
	}
	/// Iris 6/08/2010 ORG_98-P12 FIX_DUPLICATE_PATH_NOT_INCLUDED_VALUE_TEXT
	ImageProfileHVLine(GraphObject& go) : ImageProfileLine(go)
	{
	}
	///End FIX_DUPLICATE_PATH_NOT_INCLUDED_VALUE_TEXT
	~ImageProfileHVLine()
	{
	}
	
	/// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT
	/*
	//virtual
	bool Create(GraphLayer& gl, double dLineWidth, int nColor, bool bVertical, double dPos);

	bool AddReadOut(GraphLayer& gl, bool bVertical, double dPos);
	*/	
	//virtual
	bool Create(GraphLayer& gl, double dLineWidth, int nColor, bool bVertical, double dPos, int nTextObjectLocation = TEXT_LOC_DEFAULT);

	bool AddReadOut(GraphLayer& gl, bool bVertical, double dPos, int nTextObjectLocation = TEXT_LOC_DEFAULT);	
	///End NEW_SUGGESTION_FOR_TEXT_OBJECT
};


/*----------------------------------------------------------------------------*/
/* ImageProfileAbitraryLine
/*----------------------------------------------------------------------------*/
#define STR_ABITRARY_NAME_PREFIX		"ALine"
class ImageProfileAbitraryLine : public ImageProfileLine
{
public:
	ImageProfileAbitraryLine() : ImageProfileLine()
	{
	}
	~ImageProfileAbitraryLine()
	{
	}
	bool Create(GraphLayer& gl, double dLineWidth, int nColor);
};

/*----------------------------------------------------------------------------*/
/* ImageProfilePolyLine
/*----------------------------------------------------------------------------*/
#define STR_POLYLINE_NAME_PREFIX		"PLine"
class ImageProfilePolyLine : public ImageProfileLine
{
public:
	ImageProfilePolyLine()
	{
	}
	~ImageProfilePolyLine()
	{
	}
	bool Create(GraphLayer& gl, double dLineWidth, int nColor, const vector& vx, const vector& vy);
};

/*----------------------------------------------------------------------------*/
/* ImageProfileCalculator
/*----------------------------------------------------------------------------*/

enum
{
	PROFILE_SRC_TYPE_INVALID		= -1,
	PROFILE_SRC_TYPE_MATRIX,
	PROFILE_SRC_TYPE_VMATRIX,
	PROFILE_SRC_TYPE_XYZ,

	PROFILE_SRC_TYPE_COUNT
};

class ImageProfileCalculator
{
public:
	ImageProfileCalculator()
	{
		ResetCalculator();
	}
	
	void	ResetCalculator()
	{
		if( m_dpSource.IsValid() )
			m_dpSource.Detach();

		m_nProfileSrcType = PROFILE_SRC_TYPE_INVALID;

		m_matSource.SetSize(0, 0);

		m_dXMin = NANUM;
		m_dYMin = NANUM;
		m_dXMax = NANUM;
		m_dYMax = NANUM;

		m_vX.SetSize(0);
		m_vY.SetSize(0);
	}

	bool	CheckInitSource(DataPlot& dpSrc)
	{
		if( !is_good_plot_for_profile(dpSrc) )
			return false;
		if( IsSourceValid() )
		{
			if( m_dpSource.GetUID(TRUE) == dpSrc.GetUID() )
				return true;
		}
		ResetCalculator();

		m_dpSource = dpSrc;
		switch( m_dpSource.GetPlotType() )
		{
		case IDM_PLOT_CONTOUR:
		case IDM_PLOT_MATRIX_IMAGE:
			{
				DataRange rng;
				if( !m_dpSource.GetDataRange(rng) || !rng )
					return false;

				int c1, c2;
				MatrixLayer ml;
				rng.GetRange(ml, c1, c2);

				MatrixObject mo(ml, c1);
				if(mo)
				{
					if( ml.HasImage() && !mo.HasData() )
						return false;

					m_bUniformlySpaced = true;
					mo.GetXY(m_dXMin, m_dYMin, m_dXMax, m_dYMax);

					m_matSource = mo.GetDataObject();

					m_nProfileSrcType = PROFILE_SRC_TYPE_MATRIX;
				}
				else
				{
					// virtual matrix
					mo.Attach(rng);
					if( !mo )
						return false;

					Worksheet wks;
					int r1, r2;

					int nZIndex = rng.GetRange("Z", r1, c1, r2, c2, wks);
					if( nZIndex < 0 )
						return false;
					if( !rng.GetData(m_matSource, 0, nZIndex) )
						return false;
					
					int nXIndex = rng.GetRange("X", r1, c1, r2, c2, wks);
					int nYIndex = rng.GetRange("Y", r1, c1, r2, c2, wks);
					if( nXIndex >= 0 && nYIndex >= 0 )
					{
						m_bUniformlySpaced = false;

						DWORD dwPlotID;
						rng.GetData(DRR_GET_MISSING | DRR_NO_FACTORS | DRR_NO_WEIGHTS | DRR_BY_ROWS, nXIndex, &dwPlotID, NULL, &m_vX);
						rng.GetData(&m_vY, nYIndex);
					}
					else
					{
						m_bUniformlySpaced = true;

						m_dXMin = 1;		m_dXMax = 10;
						m_dYMin = 1;		m_dYMax = 10;
					}
					m_nProfileSrcType = PROFILE_SRC_TYPE_VMATRIX;
				}
			}
			break;
			
		case IDM_PLOT_TRI_CONTOUR:
			{
				/*
				vector vx, vy, vz;
				if( !rng.GetData(vz, vy, vx) )			// error if from ogg, use m_dp.GetDataPoints(0, -1, vx, vy, vz) instead
					return false;
				*/
				m_nProfileSrcType = PROFILE_SRC_TYPE_XYZ;
			}
			break;

		default:
			ASSERT(0);
			return false;
		}

		return IsSourceValid();
	}

	///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	//bool DoLineProfile(	vector& vxOutput, vector& vyOutput, vector& vzOutput, int nOutputSize,
	//					const vector& vxVertices, const vector& vyVertices, double dProfileWidth)
	///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	//bool DoLineProfile(	vector& vxOutput, vector& vyOutput, vector& vzOutput, int nOutputSize,
	//					const vector& vxAPoints, const vector& vyAPoints, double dLineWidth)
	bool DoLineProfile(	vector& vxOutput, vector& vyOutput, vector& vzOutput, int nOutputSize,
						const vector& vxAPoints, const vector& vyAPoints, double dLineWidth, int nWidthUnit)
	///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	{
		if( !IsSourceValid() )
			return false;
		

		///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
		//if( vxVertices.GetSize() != vyVertices.GetSize() || dProfileWidth <= 0 )
		if( vxAPoints.GetSize() != vyAPoints.GetSize() || vxAPoints.GetSize() < 2 )
		///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
			return false;

		if( nOutputSize < 0 )
			nOutputSize = CalcAutoOutputSize(dLineWidth, nWidthUnit, vxAPoints, vyAPoints);

		if( nOutputSize <= 0 )
			return false;

		///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
		//int nWidth = nint(dProfileWidth);
		//if( nWidth < 1 )
		//	nWidth = 1;
		///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH

		vxOutput.SetSize(nOutputSize);
		vyOutput.SetSize(nOutputSize);
		vzOutput.SetSize(nOutputSize);

		switch( m_nProfileSrcType )
		{
		case PROFILE_SRC_TYPE_MATRIX:
		case PROFILE_SRC_TYPE_VMATRIX:
			{
				///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
				/*
				///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
				//linearTransform(vxVertices, true, false);
				//linearTransform(vyVertices, false, false);
				double dWidth;
				vector vxVertices, vyVertices;
				if( !scaleToCoordinate(dLineWidth, vxAPoints, vyAPoints, dWidth, vxVertices, vyVertices) )
					return false;

				int nWidth = nint(dWidth);
				if( nWidth < 1 )
					nWidth = 1;
				///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
				*/
				double dWidth;
				vector vxVertices, vyVertices;
				if( IPROFILE_PATH_WIDTH_SCALE == nWidthUnit )
				{
					if( !scaleToCoordinate(dLineWidth, vxAPoints, vyAPoints, dWidth, vxVertices, vyVertices) )
						return false;
				}
				else
				{
					ASSERT( IPROFILE_PATH_WIDTH_PIXEL == nWidthUnit );
					dWidth = dLineWidth;
					vxVertices = vxAPoints;
					vyVertices = vyAPoints;
					linearTransform(vxVertices, true, false);
					linearTransform(vyVertices, false, false);
				}

				int nWidth = nint(dWidth);
				if( nWidth < 1 )
					nWidth = 1;
				///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE

				int nRet = ocmath_image_lines_profile(	m_matSource.GetNumRows(), m_matSource.GetNumCols(), m_matSource,
														vxVertices.GetSize(), vxVertices, vyVertices,
														vxOutput.GetSize(), vxOutput, vyOutput, vzOutput, NULL,
														nWidth);
				if( OE_NOERROR != nRet )
					return false;

				linearTransform(vxOutput, true, true);
				linearTransform(vyOutput, false, true);
				
			}
			break;

		case PROFILE_SRC_TYPE_XYZ:
			{
				///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
				//int nRet = ocmath_image_xyz_profile(m_dpSource.GetTriangulationData(),
				//									vxVertices.GetSize(), vxVertices, vyVertices, 
				//									vxOutput.GetSize(), vxOutput, vyOutput, vzOutput, NULL,
				//									nWidth);
				ASSERT( IPROFILE_PATH_WIDTH_SCALE == nWidthUnit );		///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE, to do, should allow width in scale unit only
				if( dLineWidth < 1 )
					dLineWidth = 1;
				int nRet = ocmath_image_xyz_profile(m_dpSource.GetTriangulationData(),
													vxAPoints.GetSize(), vxAPoints, vyAPoints, 
													vxOutput.GetSize(), vxOutput, vyOutput, vzOutput, NULL,
													dLineWidth);
				///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
				if( OE_NOERROR != nRet )
					return false;
			}
			break;

		default:
			ASSERT(0);
			return false;
		}

		return true;
	}

	///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	/*
	bool CalcProfileWidth(double& dWidth, const vector& vxAPoints, const vector& vyAPoints, double dLineWidth)
	{
		if( !IsSourceValid() )
			return false;

		if( vxAPoints.GetSize() != vyAPoints.GetSize() || vxAPoints.GetSize() < 2 )
			return false;

		vector vxVertices, vyVertices;
		return scaleToCoordinate(dLineWidth, vxAPoints, vyAPoints, dWidth, vxVertices, vyVertices);
	}
	*/
	double ConvertWidth(double dWidth, int nSrcUnit, int nDestUnit, const vector& vxAPoints, const vector& vyAPoints)
	{
		if( dWidth < 0 || dWidth == NANUM )
			return NANUM;
		if( nSrcUnit == nDestUnit )
			return dWidth;

		if( !IsSourceValid() )
			return NANUM;

		if( vxAPoints.GetSize() != vyAPoints.GetSize() || vxAPoints.GetSize() < 2 )
			return NANUM;

		double dDestWidth;
		switch( nSrcUnit )
		{
		case IPROFILE_PATH_WIDTH_PIXEL:
			{
				vector vxVertices, vyVertices;
				if( !coordinateToScale(dWidth, vxAPoints, vyAPoints, dDestWidth, vxVertices, vyVertices) )
					dDestWidth = NANUM;
			}
			break;
			
		case IPROFILE_PATH_WIDTH_SCALE:
			{
				vector vxVertices, vyVertices;
				if( !scaleToCoordinate(dWidth, vxAPoints, vyAPoints, dDestWidth, vxVertices, vyVertices) )
					dDestWidth = NANUM;
			}
			break;

		default:
			ASSERT(0);
			dDestWidth = NANUM;
		}

		return dDestWidth;
	}
	///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	
	///Kyle 06/18/2010 ORG-98 BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT
	// input vxAPoints and vyAPoints in scale unit
	int CalcAutoOutputSize(double dWidth, int nWidthUnit, const vector& vxAPoints, const vector& vyAPoints)
	{
		int nPoints = -1;
		if( !IsSourceValid() )
			return nPoints;
		if( vxAPoints.GetSize() != vyAPoints.GetSize() || vxAPoints.GetSize() < 2 )
			return nPoints;

		if( dWidth < 0 || dWidth == NANUM )
			nWidthUnit = IPROFILE_PATH_WIDTH_PIXEL;

		bool bOK = false;
		vector vxVertices, vyVertices;
		switch( nWidthUnit )
		{
		case IPROFILE_PATH_WIDTH_PIXEL:
			{
				vxVertices = vxAPoints;
				vyVertices = vyAPoints;
				linearTransform(vxVertices, true, false);
				linearTransform(vyVertices, false, false);
				bOK = true;
			}
			break;

		case IPROFILE_PATH_WIDTH_SCALE:
			{
				double dWidthInPixel;
				bOK = scaleToCoordinate(dWidth, vxAPoints, vyAPoints, dWidthInPixel, vxVertices, vyVertices);
			}
			break;

		default:
			ASSERT(0);
		}
		if( bOK )
			nPoints = getAutoOutputSize(vxVertices, vyVertices);

		return nPoints;
	}
	///End BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT

	bool GetSourcePlot(DataPlot& dpSrc)
	{
		dpSrc = m_dpSource;
		return dpSrc.IsValid();
	}

	bool IsSourceValid()
	{
		if( !m_dpSource )
			return false;

		switch(m_nProfileSrcType)
		{
		case PROFILE_SRC_TYPE_MATRIX:
		case PROFILE_SRC_TYPE_VMATRIX:
			{
				if( !(m_matSource.GetNumRows() && m_matSource.GetNumCols()) )
					return false;
				if( m_bUniformlySpaced )
				{
					return m_dXMin != NANUM && m_dYMin != NANUM && m_dXMax != NANUM && m_dYMax != NANUM;
				}
				else
				{
					return m_vX.GetSize()==m_matSource.GetNumCols() && m_vY.GetSize()==m_matSource.GetNumRows();
				}
			}
			break;

		case PROFILE_SRC_TYPE_XYZ:
			{
				return true;
			}
			break;

		default:
			return false;
		}

		return true;
	}

	/// Hong 06/11/10 ORG-98 IMPROVE_SPEED
	bool		GetZMinMax(double& dMin, double& dMax)
	{
		if ( !IsSourceValid() )
			return false;
		if ( PROFILE_SRC_TYPE_XYZ == m_nProfileSrcType )
		{
			vector		vZ;
			m_dpSource.GetDataPoints(0, -1, NULL, NULL, vZ);
			vZ.GetMinMax(dMin, dMax);
			return true;
		}
		dMin = m_matSource.GetMin();
		dMax = m_matSource.GetMax();
		return true;
	}
	/// end IMPROVE_SPEED

private:
	///Kyle 06/18/2010 ORG-98 BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT
	// input vxVertices and vyVertices in pixel unit
	int getAutoOutputSize(const vector& vxVertices, const vector& vyVertices)
	{
		if( vxVertices.GetSize() != vyVertices.GetSize() || vxVertices.GetSize() < 2 )
			return -1;

		int nPoints = 0;
		for(int ii = vxVertices.GetSize()-1; ii > 0; ii--)
		{
			int nDX = ceil(fabs(vxVertices[ii] - vxVertices[ii-1])) + 1;
			int nDY = ceil(fabs(vyVertices[ii] - vyVertices[ii-1])) + 1;
			nPoints += ((nDX > nDY) ? nDX : nDY);
		}
		return nPoints;
	}
	///End BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT
	
	///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	// input dWidth in pixel unit
	// input vxAPoints and vyAPoints in scale unit
	// output dWidthInScale in scale unit
	// output vxVertices and vyVertices in pixel unit
	bool coordinateToScale(double dWidthInPixel, const vector& vxAPoints, const vector& vyAPoints, double& dWidthInScale, vector& vxVertices, vector& vyVertices)
	{
		if( !(vxAPoints && vxAPoints && vxAPoints.GetSize()==vyAPoints.GetSize() && vxAPoints.GetSize()>=2) )
			return false;
		ASSERT( IsSourceValid() );
		if( PROFILE_SRC_TYPE_MATRIX!=m_nProfileSrcType && PROFILE_SRC_TYPE_VMATRIX!=m_nProfileSrcType )
			return false;

		vxVertices = vxAPoints;
		vyVertices = vyAPoints;
		linearTransform(vxVertices, true, false);
		linearTransform(vyVertices, false, false);

		vector vxLeft, vyLeft, vxRight, vyRight;
		getOffsetLine(vxVertices, vyVertices, dWidthInPixel, vxLeft, vyLeft, vxRight, vyRight);
		
		linearTransform(vxLeft, true, true);
		linearTransform(vyLeft, false, true);
		linearTransform(vxRight, true, true);
		linearTransform(vyRight, false, true);

		vector vxCenter, vyCenter;
		vxCenter = 0.5 * (vxLeft + vxRight);
		vyCenter = 0.5 * (vyLeft + vyRight);

		dWidthInScale = averageWidth(vxLeft, vyLeft, vxRight, vyRight, vxCenter, vyCenter);
		return true;
	}

	void getOffsetLine(	const vector& vxPoints, const vector& vyPoints, double dWidth,
						vector& vxLeft, vector& vyLeft, vector& vxRight, vector& vyRight)
	{
		double dHalfWidth = fabs(dWidth / 2);

		int nPoints = vxPoints.GetSize();
		vxLeft.SetSize(nPoints);
		vyLeft.SetSize(nPoints);
		vxRight.SetSize(nPoints);
		vyRight.SetSize(nPoints);

		vector vxDiff, vyDiff, vDist;
		vxPoints.Difference(vxDiff);
		vyPoints.Difference(vyDiff);
		vDist = sqrt( vxDiff*vxDiff + vyDiff * vyDiff);

		double dXOffset, dYOffset;
		dXOffset = - dHalfWidth * vyDiff[0] / vDist[0];
		dYOffset = dHalfWidth * vxDiff[0] / vDist[0];
		vxLeft[0] = vxPoints[0] + dXOffset;
		vyLeft[0] = vyPoints[0] + dYOffset;
		vxRight[0] = vxPoints[0] - dXOffset;
		vyRight[0] = vyPoints[0] - dYOffset;

		for(int ii = 1; ii < nPoints; ii++)
		{
			// vector (vxDiff[ii-1], vyDiff[ii-1]) rotate pi/4 is (-vyDiff[ii-1], vxDiff[ii-1]) with length vDist[ii-1], and then make it's length to dHalfWidth
			dXOffset = - dHalfWidth * vyDiff[ii-1] / vDist[ii-1];
			dYOffset = dHalfWidth * vxDiff[ii-1] / vDist[ii-1];

			vxLeft[ii] = vxPoints[ii] + dXOffset;
			vyLeft[ii] = vyPoints[ii] + dYOffset;
			vxRight[ii] = vxPoints[ii] - dXOffset;
			vyRight[ii] = vyPoints[ii] - dYOffset;
		}
	}
	///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	
	///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	// input dLineWidth, vxAPoints and vyAPoints in scale unit
	// output dWidth, vxVertices, and vyVertices in pixel unit
	bool scaleToCoordinate(double dLineWidth, const vector& vxAPoints, const vector& vyAPoints, double& dWidth, vector& vxVertices, vector& vyVertices)
	{
		if( !(vxAPoints && vxAPoints && vxAPoints.GetSize()==vyAPoints.GetSize() && vxAPoints.GetSize()>=2) )
			return false;
		ASSERT( IsSourceValid() );
		if( PROFILE_SRC_TYPE_MATRIX!=m_nProfileSrcType && PROFILE_SRC_TYPE_VMATRIX!=m_nProfileSrcType )
			return false;

		if( dLineWidth <= 0 )		// use thin line
		{
			dWidth = 1;
			vxVertices = vxAPoints;
			vyVertices = vyAPoints;
			linearTransform(vxVertices, true, false);
			linearTransform(vyVertices, false, false);

			return true;
		}

		///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
		/*
		double dHalfWidth = fabs(dLineWidth / 2);
		int nPoints = vxAPoints.GetSize();
		vector vxLeft(nPoints), vyLeft(nPoints), vxRight(nPoints), vyRight(nPoints);

		vector vxDiff, vyDiff, vDist;
		vxAPoints.Difference(vxDiff);
		vyAPoints.Difference(vyDiff);
		vDist = sqrt( vxDiff*vxDiff + vyDiff * vyDiff);

		double dXOffset, dYOffset;
		dXOffset = - dHalfWidth * vyDiff[0] / vDist[0];
		dYOffset = dHalfWidth * vxDiff[0] / vDist[0];
		vxLeft[0] = vxAPoints[0] + dXOffset;
		vyLeft[0] = vyAPoints[0] + dYOffset;
		vxRight[0] = vxAPoints[0] - dXOffset;
		vyRight[0] = vyAPoints[0] - dYOffset;

		for(int ii = 1; ii < nPoints; ii++)
		{
			// vector (vxDiff[ii-1], vyDiff[ii-1]) rotate pi/4 is (-vyDiff[ii-1], vxDiff[ii-1]) with length vDist[ii-1], and then make it's length to dHalfWidth
			dXOffset = - dHalfWidth * vyDiff[ii-1] / vDist[ii-1];
			dYOffset = dHalfWidth * vxDiff[ii-1] / vDist[ii-1];

			vxLeft[ii] = vxAPoints[ii] + dXOffset;
			vyLeft[ii] = vyAPoints[ii] + dYOffset;
			vxRight[ii] = vxAPoints[ii] - dXOffset;
			vyRight[ii] = vyAPoints[ii] - dYOffset;
		}
		*/
		vector vxLeft, vyLeft, vxRight, vyRight;
		getOffsetLine(vxAPoints, vyAPoints, dLineWidth, vxLeft, vyLeft, vxRight, vyRight);
		///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
		linearTransform(vxLeft, true, false);
		linearTransform(vyLeft, false, false);

		linearTransform(vxRight, true, false);
		linearTransform(vyRight, false, false);
		
		vxVertices = 0.5 * (vxLeft + vxRight);
		vyVertices = 0.5 * (vyLeft + vyRight);

		dWidth = averageWidth(vxLeft, vyLeft, vxRight, vyRight, vxVertices, vyVertices);

		return true;
	}

	double averageWidth(const vector& vxLeft, const vector& vyLeft, const vector& vxRight, const vector& vyRight, const vector& vxVertices, const vector& vyVertices)
	{
		vector vDist, vWidth, vxDiff, vyDiff;

		vxVertices.Difference(vxDiff);
		vyVertices.Difference(vyDiff);
		vDist = sqrt(vxDiff*vxDiff + vyDiff * vyDiff);

		vxDiff = vxRight - vxLeft;
		vyDiff = vyRight - vyLeft;
		vWidth = sqrt(vxDiff*vxDiff + vyDiff * vyDiff);

		ASSERT(vWidth.GetSize() == vDist.GetSize() + 1);
		vWidth.RemoveAt(0);				// remove the first one
		vWidth *= vDist;

		double dTotalDist, dTotalWidth;
		vDist.Sum(dTotalDist);
		vWidth.Sum(dTotalWidth);

		return dTotalWidth / dTotalDist;
	}
	///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH

	bool linearTransform(vector& vValues, bool bIsX, bool bIndex2Coordinate)
	{
		if( m_bUniformlySpaced )
		{
			double dMin, dMax;
			int nSize;
			if( bIsX )
			{
				dMin = m_dXMin;
				dMax = m_dXMax;
				nSize = m_matSource.GetNumCols();
			}
			else
			{
				dMin = m_dYMin;
				dMax = m_dYMax;
				nSize = m_matSource.GetNumRows();
			}

			if( bIndex2Coordinate )
			{
				double dFactor = (dMax-dMin) / ((double)nSize - 1.0);
				vValues = vValues * dFactor + dMin;
			}
			else
			{
				ocmath_linear_transform(vValues, 0, vValues.GetSize(), 0, nSize-1, dMin, dMax, LNTR_NO_ROUND_NEAREST_INT);

				double dVMax = nSize - 1;
				for(int ii = vValues.GetSize() - 1; ii >= 0; ii--)
				{
					if( vValues[ii] < 0 )
						vValues[ii] = 0;
					else if( vValues[ii] > dVMax )
						vValues[ii] = dVMax;
				}
			}
		}
		else
		{
			return linearTransform(vValues, bIsX ? m_vX : m_vY, bIndex2Coordinate);
		}

		return true;
	}

	bool linearTransform(vector& vValues, const vector& vCoordinates, bool bIndex2Coordinate)
	{
		int nSize = vCoordinates.GetSize();
		if( nSize < 1 )
			return false;
		
		if( bIndex2Coordinate )
		{
			ocmath_find_nearest_values(vValues, vCoordinates.GetSize(), vCoordinates, vValues.GetSize(), vValues, FINDVAL_NO_ROUND_NEAREST_INDEX);
		}
		else		// coordinate to index, make sure v[ii] in [0, vCoordinate.GetSize()-1]
		{
			for(int ii = vValues.GetSize()-1; ii >= 0; ii--)
			{
				int nNearestLeft, nNearestRight, nNearest;
				if( OE_NOERROR == ocmath_find_nearest_index(vCoordinates, nSize, vValues[ii], &nNearestLeft, &nNearestRight, &nNearest) )
				{
					vValues[ii] = nNearest;
				}
				else if( nNearestLeft >= 0 && nNearestLeft < nSize )
				{
					vValues[ii] = nNearestLeft;
				}
				else if( nNearestRight >= 0 && nNearestRight < nSize )
				{
					vValues[ii] = nNearestRight;
				}
				else
				{
					ASSERT(0);
				}
			}
		}

		return true;
	}


protected:
	int			m_nProfileSrcType;
	
	DataPlot	m_dpSource;

	matrix		m_matSource;	// matrix, v matrix

	bool		m_bUniformlySpaced;

	double		m_dXMin;		// matrix, uniformly spaced v matrix
	double		m_dYMin;		// matrix, uniformly spaced v matrix
	double		m_dXMax;		// matrix, uniformly spaced v matrix
	double		m_dYMax;		// matrix, uniformly spaced v matrix

	vector		m_vX;			// non-uniformly spaced v matrix
	vector		m_vY;			// non-uniformly spaced v matrix
};


/*----------------------------------------------------------------------------*/
/* ImageProfilePathInfo
/*----------------------------------------------------------------------------*/
class ImageProfilePathInfo
{
public:
	GraphLayer 	m_glSource;
	/// Iris 6/21/2010 ORG-355-P2 FIX_AFTER_CHANGE_LAYER_BACKGROUND_COLOR_MOVING_PROFILE_LINE_INVALID
	//DataPlot	m_dpSource;			///Kyle 06/18/2010 ORG-98 KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED
	UINT		m_uSourcePlot;
	///End FIX_AFTER_CHANGE_LAYER_BACKGROUND_COLOR_MOVING_PROFILE_LINE_INVALID
	GraphLayer 	m_glOutput;
	UINT		m_uObjUID;
	DataRange	m_drOutput;
	int			m_nLineType;
	int			m_nNumPoints;

private:
	GraphObject m_goLine;
	DataPlot	m_dpSource;

public:
	ImageProfilePathInfo()
	{
		m_uObjUID = 0;
		m_nLineType = -1;
		m_nNumPoints = -1;
	}

	///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
	//bool InitFromTree(const TreeNode& trMngr)
	bool InitFromTree(const TreeNode& trMngr, GraphLayer& glSource)
	///End NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
	{
		///Kyle 06/18/2010 ORG-98 KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED
		//if( !(trMngr && trMngr.SourceLayer && trMngr.OutputLayer && trMngr.ObjName && trMngr.OutputLayer && trMngr.LineType && trMngr.OutputRange) )
		///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE, because the storage is saved in the source layer
		//if( !(trMngr && trMngr.SourceLayer && trMngr.SourcePlot && trMngr.OutputLayer && trMngr.ObjName && trMngr.OutputLayer && trMngr.LineType && trMngr.OutputRange) )
		if( !(trMngr && trMngr.SourcePlot && trMngr.OutputLayer && trMngr.ObjName && trMngr.OutputLayer && trMngr.LineType && trMngr.OutputRange) )
		///End NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
		///End KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED
			return false;

		///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
		//if( !nameToLayer(trMngr.SourceLayer.strVal, m_glSource) )
		//	return false;
		if( !glSource )
			return false;
		m_glSource = glSource;
		///End NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
		
		///Kyle 06/18/2010 ORG-98 KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED
		/// Iris 6/21/2010 ORG-355-P2 FIX_AFTER_CHANGE_LAYER_BACKGROUND_COLOR_MOVING_PROFILE_LINE_INVALID
		/*
		m_dpSource = m_glSource.DataPlots(trMngr.SourcePlot.nVal);
		if( !m_dpSource )
			return false;
		*/
		DataPlot dpSource = m_glSource.DataPlots(trMngr.SourcePlot.nVal);
		if( !dpSource )
			return error_report("Fail to get source plot in InitFromTree");
		m_uSourcePlot = dpSource.GetUID(true);
		///End FIX_AFTER_CHANGE_LAYER_BACKGROUND_COLOR_MOVING_PROFILE_LINE_INVALID
		///End KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED

		nameToLayer(trMngr.OutputLayer.strVal, m_glOutput);

		m_goLine = m_glSource.GraphObjects(trMngr.ObjName.strVal);
		if( !m_goLine )
			return false;
		m_uObjUID = m_goLine.GetUID(true);

		//DataPlot dpSource = m_glSource.DataPlots();
		//loadRangeFromDataPlot(dpSource, m_drOutput);
		stringTorange(trMngr.OutputRange.strVal, m_drOutput);

		m_nLineType = trMngr.LineType.nVal;

		///Kyle 06/21/2010 ORG-355 DISABLE_MOVE_LABEL_TEXT
		/*
		// disable movable and selectable for lines when close dialog. 
		// so need to cancel disable when reopen dialog.
		disable_go_move(m_goLine, m_nLineType == CROSSED_LINE_HORIZONTAL, m_nLineType == CROSSED_LINE_VERTICAL, true, true);
		set_go_selectable(m_goLine, true);		
		*/
		///End DISABLE_MOVE_LABEL_TEXT
		
		return true;
	}
	
	bool SaveToTree(TreeNode& trMngr)
	{
		if( !trMngr )
			return false;

		//trMngr.SourceLayer.strVal = layerToName(m_glSource);		///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE, because the storage is saved in the source layer

		/// Iris 6/21/2010 ORG-355-P2 FIX_AFTER_CHANGE_LAYER_BACKGROUND_COLOR_MOVING_PROFILE_LINE_INVALID
		//trMngr.SourcePlot.nVal = m_dpSource.GetIndex();		///Kyle 06/18/2010 ORG-98 KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED
		DataPlot dpSource;
		dpSource = (DataPlot)Project.GetObject(m_uSourcePlot);
		trMngr.SourcePlot.nVal = dpSource.GetIndex();
		///End FIX_AFTER_CHANGE_LAYER_BACKGROUND_COLOR_MOVING_PROFILE_LINE_INVALID

		trMngr.OutputLayer.strVal = layerToName(m_glOutput);

		GetLineObject();
		trMngr.ObjName.strVal = m_goLine ? m_goLine.GetName() : "";

		//DataPlot dpSource = m_glSource.DataPlots();
		//saveRangeToDataPlot(dpSource, m_drOutput);
		trMngr.OutputRange.strVal = rangeToString(m_drOutput);

		trMngr.LineType.nVal = m_nLineType;

		return true;
	}

	GraphObject GetLineObject()
	{
		if( !(m_goLine && m_goLine.GetUID()==m_uObjUID) )
			m_goLine = (GraphObject)Project.GetObject(m_uObjUID);
		return m_goLine;
	}
	
	bool GetSourcePlot(DataPlot& dpSrc)
	{
		if( !(m_dpSource && m_dpSource.GetUID()==m_uSourcePlot) )
			m_dpSource = (DataPlot)Project.GetObject(m_uSourcePlot);
		dpSrc = m_dpSource;

		return dpSrc.IsValid();
	}

private:
	
	string rangeToString(const DataRange& dr)
	{
		if( !dr.IsValid() )
			return "";

		Worksheet wks;
		int c1, c2, r1, r2;
		string strName;

		vector<string> vs;
		for(int ii = 0; ii < dr.GetNumRanges(); ii++)
		{
			if( dr.GetRange(ii, r1, c1, r2, c2, wks, &strName) )
			{
				DatasetObject dsObject(wks.Columns(c1));
				if( dsObject )
					vs.Add(strName + ":" + dsObject.GetName());
			}
		}

		string str;
		str.SetTokens(vs, '|');
		return str;
	}

	bool stringTorange(LPCSTR lpcsz, DataRange& dr)
	{
		Worksheet wks;
		int c1, c2;

		vector<string> vs;
		string str(lpcsz);
		str.TrimLeft();
		str.TrimRight();
		str.GetTokens(vs, '|');

		DataRange drOutput;
		for(int ii = 0; ii < vs.GetSize(); ii++)
		{
			string strRange = vs[ii];
			string strName = strRange.Left(1);
			string strDsName = strRange.Mid(2);
	
			DatasetObject dsObject(strDsName);
			if( !dsObject )
				return false;
			
			/// Iris 6/07/2010 ORG-98-P10 FIX_RENAME_TAB_UPDATED_INCORRECT_OUTPUT_COL_COMMENTS
			// get range string with column long name, for same type path, the output column long name is same
			// so replace with getting short name here.
			//dsObject.GetRangeString(strRange);
			dsObject.GetRangeString(strRange, NTYPE_SHORT);
			///End FIX_RENAME_TAB_UPDATED_INCORRECT_OUTPUT_COL_COMMENTS

			DataRange drOneColumn;
			drOneColumn.Add("Range1", strRange);
			if( !drOneColumn.GetRange(wks, c1, c2) )
				return false;
			ASSERT(c1==c2); // only one column
			
			drOutput.Add(wks, c1, strName);
		}
		dr = drOutput;

		return dr.IsValid();
	}
	/*
	bool	saveRangeToDataPlot(DataPlot& dp, const DataRange& dr)
	{
		if( !dp )
			return false;

		if( dr )
		{
			Worksheet wks;
			int c1, c2, r1, r2;
			string strName;
			
			vector<string> vsRelatedDataset;

			for(int ii = 0; ii < dr.GetNumRanges(); ii++)
			{
				if( dr.GetRange(ii, r1, c1, r2, c2, wks, &strName) )
				{
					ASSERT( c1 == c2 );
					DatasetObject dsObject(wks.Columns(c1));

					strName = STR_IMAGE_PROFILE_RELATED_DATASET + strName;
					
					string strRDSName;
					for(int nn = 0; nn <= ii; nn++)
					{
						strRDSName = strName;
						if( nn )
							strRDSName += (string)nn;
						if( vsRelatedDataset.Find(strRDSName) < 0 )
							break;
					}
					
					dp.SetRelatedDataset(strRDSName, dsObject);
					vsRelatedDataset.Add(strName);
				}
			}
		}
		else
		{
			//dp.RemoveRelatedDataset(STR_IMAGE_PROFILE_RELATED_DATASET);
			_clear_related_dataset(dp);
		}

		return true;
	}
	
	bool	loadRangeFromDataPlot(const DataPlot& dp, DataRange& dr)
	{
		if( !dp )
			return false;

		vector<string> vs;
		dp.GetRelatedDatasetNames(vs);
		
		for(int ii = 0; ii < vs.GetSize(); ii++)
		{
			string strName = vs[ii];
			if( strName.Find(STR_IMAGE_PROFILE_RELATED_DATASET) == 0 )
			{
				
				DatasetObject dsObject;
				if( !(dp.GetRelatedDataset(strName, dsObject) && dsObject.IsValid()) )
					return false;

				strName.Mid( strlen(STR_IMAGE_PROFILE_RELATED_DATASET), 1);

				string strRange;
				dsObject.GetRangeString(strRange);

				DataRange dr;
				dr.Add("Range1", strRange);

				Worksheet wks;
				int c1,c2;
				if( !dr.GetRange(wks, c1, c2) )
					return false;
				ASSERT(c1==c2); // only one column

				dr.Add(wks, c1, strName);
			}
		}

		return dr.IsValid();
	}
	*/

	string	layerToName(const Layer& lay)
	{
		string str;
		if( lay )
		{
			Page page = lay.GetPage();
			str = page.GetName() + "|" + lay.GetIndex();
		}
		return str;
	}

	bool	nameToLayer(LPCSTR lpcszValue, Layer& lay)
	{
		string strValue = lpcszValue;
		if( strValue.IsEmpty() )
			return false;

		vector<string> vsValues;
		strValue.GetTokens(vsValues, '|');
		if( vsValues.GetSize() != 2 )
			return false;

		Page page(vsValues[0]);
		if( !page )
			return false;
		lay = page.Layers(atoi(vsValues[1]));

		return lay.IsValid();
	}
};

/*----------------------------------------------------------------------------*/
/* ImageProfilerPath
/*----------------------------------------------------------------------------*/
class ImageProfilerPath
{
//protected:		// ClonePath() will use this members
public:
	int								m_nPathType;
	Array<ImageProfilePathInfo&>	m_arrPathInfo;
	///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	// ///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	// //double							m_dProfileWidth;
	// double							m_dLineWidth;
	// ///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	double							m_dWidthInScale;
	double							m_dWidthInPixel;
	DWORD							m_dwCntrl;
	///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	
	string							m_strPathName;
	bool							m_bKeepOutput;
	bool							m_bRemoveGraphIfEmpty;
	
	int								m_nTextObjectLocation; /// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT
	
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//ImageProfileCalculator			m_profileCalculator;
	ImageProfileCalculator*			m_pCalculator;
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP

public:
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//ImageProfilerPath(int nPathType)
	ImageProfilerPath(int nPathType, ImageProfileCalculator* pCalculator)
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	{
		m_nPathType = nPathType;
		m_arrPathInfo.SetAsOwner(TRUE);
		///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
		// ///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
		// //m_dProfileWidth = 1.0;
		// m_dLineWidth = 0;			// use thin line by default
		// ///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
		m_dWidthInScale = NANUM;
		m_dWidthInPixel = 1.0;
		m_dwCntrl = IPROFILE_PATH_WIDTH_PIXEL;
		///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
		m_strPathName = "Path";

		m_bKeepOutput = false;
		m_bRemoveGraphIfEmpty = false;
		
		m_nTextObjectLocation = 0; /// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT

		///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
		ASSERT(pCalculator);
		m_pCalculator = pCalculator;
		///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	}

	~ImageProfilerPath()
	{
		ClearProfile();
	}
	
	int				GetPathType()								{ return m_nPathType; }
	
	void			BringObjToFront();
	
	bool			CheckResetCalculator(const DataRange& drChange);

	///Iris 6/11/2010 ORG-98-S36 SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	void			SetSourceLayer(GraphLayer& glSource);
	///End SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	GraphLayer		GetSourceLayer();
	///Kyle 06/18/2010 ORG-98 KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED
	void			SetSourcePlot(DataPlot& dpSource);
	bool			GetSourcePlot(DataPlot& dpSource);
	///End KEEP_SOURCE_DATA_PLOT_TO_PREVENT_ACTIVE_PLOT_CHANGED
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//bool			IsRelatedLayer(const GraphLayer& gl);
	bool			IsRelatedLayer(const GraphLayer& gl, bool bCheckSource);
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	bool			IsRelatedGrObj(UINT uObjUID);
	
	bool			GetOutputWP(WorksheetPage& wpOutput);
	bool			GetOutputWks(Worksheet& wksOutput, bool bVertical = true);
	bool			GetOutputLayer(GraphLayer& glOutput, bool bVertical = true);

	virtual void	ClearProfile();

	virtual bool	SetNumPoints(int nPoints, bool bVertical = true);
	int				GetNumPoints(bool bVertical = true, bool* pbAuto = NULL);

	///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	/*
	///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	//double			GetProfileWidth();
	//bool			SetProfileWidth(double dWidth);
	//
	//double			GetLineWidth(bool bVertical);
	double			GetLineWidth();
	virtual bool	SetLineWidth(double dWidth);
	///Kyle 06/11/2010 ORG-98-S33 BETTER_DEFAULT_WIDTH_FOR_H_AND_V_LINE_WIDTH
	//int		GetSuitableWidths(vector& vWidths);
	virtual int		GetSuitableWidths(vector& vWidths)							{ ASSERT(0); return 0; }
	///End BETTER_DEFAULT_WIDTH_FOR_H_AND_V_LINE_WIDTH
	///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	
	bool			GetProfileWidth(double& dWidth, string* pstrHints);		///Kyle 06/11/2010 ORG-98-S34 RESTRICT_LINE_WIDTH_AND_GIVE_HINT_FOR_PROFILE_WIDTH
	*/
	double			GetProfileWidth(int nUnit);
	virtual bool	SetProfileWidth(double dWidth, int nUnit);
	virtual int		GetSuitableWidths(vector<int>& vnWidthInPixel, vector& vdWidthInScale)							{ ASSERT(0); return 0; }
	int				GetProfileWidthUnit();
	///Kyle 06/17/2010 ORG-98-S40 NEW_WIDTH_CONTROL_WITHOUT_DROP_DOWN
	//bool			IsProfileWidthCustom();
	//void			SetProfileWidthCustom(bool bSet);
	///End NEW_WIDTH_CONTROL_WITHOUT_DROP_DOWN
	///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE

	/// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT
	void			SetTextObjectLocation(int nLocation);
	int				GetTextObjectLocation();
	///End NEW_SUGGESTION_FOR_TEXT_OBJECT

	virtual bool	SetLinePosition(const vector& vx, const vector& vy, bool bVertical = true);
	virtual bool	GetLinePosition(vector& vx, vector& vy, bool bVertical = true);

	string			GetPathName();
	bool			SetPathName(LPCSTR lpcszName);
	
	bool			IsKeepOutput()												{ return m_bKeepOutput; }
	void			SetKeepOutput(bool bSet)									{ m_bKeepOutput = bSet; }

	bool			IsRemoveGraphIfEmpty()										{ return m_bRemoveGraphIfEmpty; }
	void			SetRemoveGraphIfEmpty(bool bSet)							{ m_bRemoveGraphIfEmpty = bSet; }

	bool			SetProfileLineColor(int nColor, bool bUpdateCurve);
	int				GetProfileLineColor();

	void			ActiveOutputPlots();

	//virtual int		GetNumProfileLines()										{ return m_arrPathInfo.GetSize(); }
	bool			IsPathEmpty()												{ return 0==m_arrPathInfo.GetSize(); }
	virtual int		AddProfileLine(GraphLayer& glSource, int nColor, DWORD dwOption = 0, const vector& vX = NULL, const vector& vY = NULL)		{ ASSERT(0); return -1; }
	virtual bool	ClonePath(ImageProfilerPath* pSrcPath);

	///Iris 6/11/2010 ORG-98-S36 SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS	
	bool			BackupProfileLineFormatSettings(TreeNode& tr);
	virtual bool 	AddBackProfileLines(TreeNode& tr);
	///End SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS

	bool			OnDeleteSrcLayer();
	int				OnDeleteProfileLine(UINT uObjUID);

	virtual int		OnProfileEvent(int nEvent, UINT uObjUID);
	virtual int		OnReadOutEvent(int nEvent, UINT uObjUID)					{ ASSERT(0); return -1; }
	virtual bool	IsReadOutObj(UINT uObjUID)									{ return false; }

	virtual bool	CheckSetProfileLayer(WorksheetPage& wpOutput, GraphLayer& glVertical, GraphLayer& glHorizontal)		{ ASSERT(0); return false; }
	void			DestroyOutputGraph();
	
	void			RefreshProfilePath(bool bDoProfile = true, bool bRescale = true);

	bool			SavePathToTree(TreeNode& trPath);
	///Kyle 06/21/2010 ORG-355 DISABLE_MOVE_LABEL_TEXT
	//bool			InitPathFromTree(const TreeNode& trPath);
	///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
	//virtual bool	InitPathFromTree(const TreeNode& trPath);
	virtual bool	InitPathFromTree(const TreeNode& trPath, const GraphLayer& glSource);
	///End NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
	///End DISABLE_MOVE_LABEL_TEXT

protected:
	int				GetPathInfoIndex(UINT uObjUID);

	virtual int		GetLineIndex(bool bVertical)											{ ASSERT(0); return -1; }
	
	virtual bool	SetPathColor(const ImageProfilePathInfo& info, int nColor);
	virtual int		GetPathColor(const ImageProfilePathInfo& info);

	virtual bool	SetPathPosition(const ImageProfilePathInfo& info, const vector& vx, const vector& vy);
	virtual bool	GetPathPosition(const ImageProfilePathInfo& info, vector& vx, vector& vy);
	virtual bool	CheckPathPosition(const ImageProfilePathInfo& info, vector& vx, vector& vy, bool* pbModified = NULL);	///Kyle 07/21/2010 ORG-584-P4 PREVENT_MOVE_LINE_OUT_OF_LAYER

	virtual bool	SetPathWidth(const ImageProfilePathInfo& info, double dLineWidth);
	virtual double	GetPathWidth(const ImageProfilePathInfo& info);
	double			ConvertWidth(double dWidth, int nSrcUnit, int nDestUnit);		///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	
	virtual bool	FindOutputWks(Worksheet& wksOutput, WorksheetPage& wpOutput, const ImageProfilePathInfo& info);
	virtual bool	GetPreviewRange(const ImageProfilePathInfo& info, XYRange& xyRange)		{ ASSERT(0); return false; }

	bool			DoProfile(int nIndex);
	
	virtual bool	CalculateProfileData(const ImageProfilePathInfo& info)						{ ASSERT(0); return false; }
	
	//virtual int		GetPathNumPoints(const ImageProfilePathInfo& info, bool& bAuto)				{ ASSERT(0); return 100; }		///Kyle 06/18/2010 ORG-98 BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT

	virtual bool	BeforeDoProfile(ImageProfilePathInfo& info);

	virtual	int		AddRelatedPathInfo(vector<int>& vnIndices)									{ return vnIndices.GetSize(); }

	virtual bool	RemovePathInfoAt(int nIndex, bool bRemoveOutput, bool bRemoveLine = true);

	//virtual double	GetLineWidth(const ImageProfilePathInfo& info)								{ ASSERT(0); return NANUM; }	///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	
	virtual bool	CheckLinePosition(const vector& vx, const vector& vy, bool bVertical = true)	{ ASSERT(0); return false; }
	
	bool			CheckPlotOutput(ImageProfilePathInfo& info);
	
	void			SetOutputWksParametersLabel(Column& col, const vector& vxOutput, const vector& vyOutput, bool bVertical = true);
	
	virtual bool	SetOutputDepColComments(LPCSTR lpcszComments)				{ ASSERT(0); return false; }
	bool 			SetOutputColComments(ImageProfilePathInfo& info, LPCSTR lpcszCol, LPCSTR lpcszComments);

	///Kyle 07/01/2010 ORG-355-S7 OUTPUT_PROFILE_WIDTH
	virtual void	UpdateOutputWidth()																{ ASSERT(0); }
	void			PrepareUserDefinedLabels(Worksheet& wks, const vector<uint>& vnLabels, const vector<string>& vsLabels);
	void			SetOutputWidth(Column& col);			///Kyle 07/01/2010 ORG-355-S7 OUTPUT_PROFILE_WIDTH
	///End OUTPUT_PROFILE_WIDTH

	/// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT
	virtual bool 			GetReadOutObject(const ImageProfilePathInfo& info, GraphObject& goText) { ASSERT(0); return false; }
	///End NEW_SUGGESTION_FOR_TEXT_OBJECT

private:
	///Iris 6/11/2010 ORG-98-S36 SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	TreeNode		backupOneGraphObject(GraphObject& go, TreeNode& tr);
	bool 			addBackGraphObject(GraphLayer gl, GraphObject& go, TreeNode& trSub);
	void			setProfileCurveColor(ImageProfilePathInfo& info, int nColor);
	///End SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
};

/*----------------------------------------------------------------------------*/
/* ImageProfilerPolyLinePath
/*----------------------------------------------------------------------------*/
class ImageProfilerPolyLinePath : public ImageProfilerPath
{
public:
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//ImageProfilerPolyLinePath() : ImageProfilerPath(POLYLINE_IMAGE_PROFILE){}	
	ImageProfilerPolyLinePath(ImageProfileCalculator* pCalculator) : ImageProfilerPath(POLYLINE_IMAGE_PROFILE, pCalculator){}	
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	~ImageProfilerPolyLinePath()	{}

	int		AddProfileLine(GraphLayer& glSource, int nColor, DWORD dwOption = 0, const vector& vx = NULL, const vector& vy = NULL);

	bool	AddAnchorPoints(const vector& vx, const vector& vy);

	bool	CheckSetProfileLayer(WorksheetPage& wpOutput, GraphLayer& glVertical, GraphLayer& glHorizontal);
	
	///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
	//bool	InitPathFromTree(const TreeNode& trPath);		///Kyle 06/21/2010 ORG-355 DISABLE_MOVE_LABEL_TEXT
	bool	InitPathFromTree(const TreeNode& trPath, const GraphLayer& glSource);
	///End NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
protected:
	int		GetLineIndex(bool bVertical)							{ return 0; }

	bool	CheckLinePosition(const vector& vx, const vector& vy, bool bVertical = true);

	bool	GetPreviewRange(const ImageProfilePathInfo& info, XYRange& xyRange);

	bool	CalculateProfileData(const ImageProfilePathInfo& info);

	//int		GetPathNumPoints(const ImageProfilePathInfo& info, bool& bAuto);			///Kyle 06/18/2010 ORG-98 BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT
	
	void	UpdateOutputWidth();								///Kyle 07/01/2010 ORG-355-S7 OUTPUT_PROFILE_WIDTH
};

/*----------------------------------------------------------------------------*/
/* ImageProfilerHVPath
/*----------------------------------------------------------------------------*/

class ImageProfilerHVPath : public ImageProfilerPath
{
public:
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//ImageProfilerHVPath(int nPathType) : ImageProfilerPath(nPathType)
	ImageProfilerHVPath(int nPathType, ImageProfileCalculator* pCalculator) : ImageProfilerPath(nPathType, pCalculator)
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	{
	}

	~ImageProfilerHVPath()	{}

	int		OnProfileEvent(int nEvent, UINT uObjUID);
	int		OnReadOutEvent(int nEvent, UINT uObjUID);
	bool	IsReadOutObj(UINT uObjUID);

	bool	CheckSetProfileLayer(WorksheetPage& wpOutput, GraphLayer& glVertical, GraphLayer& glHorizontal);

	//int		GetNumProfileLines();
	
	int		AddProfileLine(GraphLayer& glSource, int nColor, DWORD dwOption = 0, const vector& vX = NULL, const vector& vY = NULL);

	/// Iris 6/08/2010 ORG_98-P12 FIX_DUPLICATE_PATH_NOT_INCLUDED_VALUE_TEXT
	//virtual 
	bool	ClonePath(ImageProfilerPath* pSrcPath);
	///End FIX_DUPLICATE_PATH_NOT_INCLUDED_VALUE_TEXT

	///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	//bool	SetLineWidth(double dWidth);
	//int		GetSuitableWidths(vector& vWidths);		///Kyle 06/11/2010 ORG-98-S33 BETTER_DEFAULT_WIDTH_FOR_H_AND_V_LINE_WIDTH
	bool	SetProfileWidth(double dWidth, int nUnit);
	int		GetSuitableWidths(vector<int>& vnWidthInPixel, vector& vdWidthInScale);
	///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE

	bool	SetLinePosition(const vector& vx, const vector& vy, bool bVertical = true);
	bool	GetLinePosition(vector& vx, vector& vy, bool bVertical = true);
	
	bool	SetLinePosition(double dValue, bool bVertical);
	bool	GetLinePosition(double& dValue, bool bVertical);
	
	/// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT
	//bool	UpdateReadOutText(bool bShowText); 
	void 	SetReadOutActive(bool bActive);
	
	void	ChangeTextObjectLocation();
	///End NEW_SUGGESTION_FOR_TEXT_OBJECT
	
	//virtual 
	bool 	AddBackProfileLines(TreeNode& tr);
	
	///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
	//bool	InitPathFromTree(const TreeNode& trPath);		///Kyle 06/21/2010 ORG-355 DISABLE_MOVE_LABEL_TEXT
	bool	InitPathFromTree(const TreeNode& trPath, const GraphLayer& glSource);
	///End NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE

protected:
	int		GetReadOutObjPathIndex(UINT uObjUID);
	bool	CheckLinePosition(const vector& vx, const vector& vy, bool bVertical = true);
	
	bool	UpdateReadOut(const ImageProfilePathInfo& info, int nShowText);		// 0=hide, 1=show, -1=update if shown
	
	bool	SetPathColor(const ImageProfilePathInfo& info, int nColor);
	int		GetPathColor(const ImageProfilePathInfo& info);
	
	bool	SetPathPosition(const ImageProfilePathInfo& info, const vector& vx, const vector& vy);
	bool	GetPathPosition(const ImageProfilePathInfo& info, vector& vx, vector& vy);

	bool	SetPathWidth(const ImageProfilePathInfo& info, double dLineWidth);
	double	GetPathWidth(const ImageProfilePathInfo& info);
	
	//double	GetLineWidth(const ImageProfilePathInfo& info);			///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH

	int		GetLineIndex(bool bVertical);
	
	bool	FindOutputWks(Worksheet& wksOutput, WorksheetPage& wpOutput, const ImageProfilePathInfo& info);
	
	bool	RemovePathInfoAt(int nIndex, bool bRemoveOutput, bool bRemoveLine = true);

	int		AddRelatedPathInfo(vector<int>& vnIndices);
	
	bool	GetPreviewRange(const ImageProfilePathInfo& info, XYRange& xyRange);
	
	bool	BeforeDoProfile(ImageProfilePathInfo& info);		///Kyle 07/21/2010 ORG-584-P4 CHECK_RESET_LINE_WIDTH_FOR_LOG_SCALE

	bool	CalculateProfileData(const ImageProfilePathInfo& info);

	//int		GetPathNumPoints(const ImageProfilePathInfo& info, bool& bAuto);			///Kyle 06/18/2010 ORG-98 BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT
	
	// virtual
	bool	SetOutputDepColComments(LPCSTR lpcszComments);

	void	UpdateOutputWidth();			///Kyle 07/01/2010 ORG-355-S7 OUTPUT_PROFILE_WIDTH

	bool 	GetReadOutObject(const ImageProfilePathInfo& info, GraphObject& goText); /// Iris 6/12/2010 ORG-98-S39 NEW_SUGGESTION_FOR_TEXT_OBJECT

};

/*----------------------------------------------------------------------------*/
/* ImageProfilerCrossLinePath
/*----------------------------------------------------------------------------*/
/*
class ImageProfilerCrossLinePath : public ImageProfilerHVPath
{
public:
	ImageProfilerCrossLinePath() : ImageProfilerHVPath(CROSSED_LINES_IMAGE_PROFILE){ m_dIntersectZValue = NANUM; }	
	~ImageProfilerCrossLinePath()	{}
	
	bool CheckSetProfileLayer(WorksheetPage& wpOutput, GraphLayer& glVertical, GraphLayer& glHorizontal);
	
	int AddProfileLine(GraphLayer& glSource, int nColor, DWORD dwOption = 0, const vector& vx = NULL, const vector& vy = NULL);

	bool GetLineIntersection(double& dZValue);

protected:
	bool	RemovePathInfoAt(int nIndex, bool bRemoveOutput, bool bRemoveLine = true);

	bool GetPreviewRange(const ImageProfilePathInfo& info, XYRange& xyRange);

	bool CalculateProfileData(const ImageProfilePathInfo& info);
	
	int GetPathNumPoints(const ImageProfilePathInfo& info, bool& bAuto);

	void UpdateIntersect(const vector& vx, const vector& vy, const vector& vz, bool bVertical);

private:
	double			m_dIntersectZValue;
};
*/

/*----------------------------------------------------------------------------*/
/* ImageProfilerAbitraryLinePath
/*----------------------------------------------------------------------------*/

///Kyle 06/22/2010 ORG-355 CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
/*
#define ABITRARY_LINE_VERTICAL			1
#define ABITRARY_LINE_HORIZONTAL		2
*/
///End CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE

///Kyle 06/22/2010 ORG-355 CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
//class ImageProfilerAbitraryLinePath : public ImageProfilerHVPath
class ImageProfilerAbitraryLinePath : public ImageProfilerPath
///End CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
{
public:
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//ImageProfilerAbitraryLinePath() : ImageProfilerHVPath(ARBITRARY_LINE_IMAGE_PROFILE){}	
	///Kyle 06/22/2010 ORG-355 CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
	//ImageProfilerAbitraryLinePath(ImageProfileCalculator* pCalculator) : ImageProfilerHVPath(ARBITRARY_LINE_IMAGE_PROFILE, pCalculator){}	
	ImageProfilerAbitraryLinePath(ImageProfileCalculator* pCalculator) : ImageProfilerPath(ARBITRARY_LINE_IMAGE_PROFILE, pCalculator)	{}
	///End CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	~ImageProfilerAbitraryLinePath()	{}
	
	bool	CheckSetProfileLayer(WorksheetPage& wpOutput, GraphLayer& glVertical, GraphLayer& glHorizontal);
	
	int		AddProfileLine(GraphLayer& glSource, int nColor, DWORD dwOption = 0, const vector& vx = NULL, const vector& vy = NULL);

	///Kyle 06/22/2010 ORG-355 CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
	/*
	bool	SetLinePosition(const vector& vx, const vector& vy, bool bVertical = true);
	bool	GetLinePosition(vector& vx, vector& vy, bool bVertical = true);
	*/
	///End CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE

	bool	SetNumPoints(int nPoints, bool bVertical = true);

	int		OnProfileEvent(int nEvent, UINT uObjUID);
	
	///Kyle 07/20/2010 ORG-584-P2 NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE
	//bool	InitPathFromTree(const TreeNode& trPath);		///Kyle 06/21/2010 ORG-355 DISABLE_MOVE_LABEL_TEXT
	bool	InitPathFromTree(const TreeNode& trPath, const GraphLayer& glSource);
	///End NO_NEED_TO_SAVE_SOURCE_LAYER_IN_STORAGE

protected:
	bool	CheckLinePosition(const vector& vx, const vector& vy, bool bVertical = true);
	
	///Kyle 06/22/2010 ORG-355 CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
	/*
	bool	SetPathColor(const ImageProfilePathInfo& info, int nColor);
	int		GetPathColor(const ImageProfilePathInfo& info);
	
	bool	SetPathPosition(const ImageProfilePathInfo& info, const vector& vx, const vector& vy);
	bool	GetPathPosition(const ImageProfilePathInfo& info, vector& vx, vector& vy);
	
	bool	SetPathWidth(const ImageProfilePathInfo& info, double dLineWidth);
	double	GetPathWidth(const ImageProfilePathInfo& info);
	
	bool	RemovePathInfoAt(int nIndex, bool bRemoveOutput, bool bRemoveLine = true);
	*/
	///End CENTRALIZE_CODE_AND_CHANGE_CLASS_STRUCTURE
	
	bool	GetPreviewRange(const ImageProfilePathInfo& info, XYRange& xyRange);

	bool	CalculateProfileData(const ImageProfilePathInfo& info);

	//int		GetPathNumPoints(const ImageProfilePathInfo& info, bool& bAuto);		///Kyle 06/18/2010 ORG-98 BETTER_AUTO_NUMBER_OF_POINTS_FOR_OUTPUT
	
	void	UpdateOutputWidth();								///Kyle 07/01/2010 ORG-355-S7 OUTPUT_PROFILE_WIDTH

	int		GetLineIndex(bool bVertical);
};

/*----------------------------------------------------------------------------*/
/* ImageProfileManager
/*----------------------------------------------------------------------------*/

class ImageProfileManager
{
private:
	Array<ImageProfilerPath&>	m_arrProfilePath;
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//GraphPage					m_gpSource;
	GraphLayer					m_glSource;
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP

	int							m_nActivePath;			// to active tab in gui, not saved

	int							m_nLayoutMode;

	DWORD						m_dwOptions;

	bool						m_bKeepGraphsOnClosing;

	bool						m_bIsReady;
	
	ImageProfileCalculator		m_profileCalculator;		///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP

public:
	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//ImageProfileManager(GraphPage& gpSource, int nLayoutMode, DWORD dwOptions);
	ImageProfileManager(GraphLayer& glSource, int nLayoutMode, DWORD dwOptions);
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	~ImageProfileManager();

	void		SetReady(bool bReady = true) { m_bIsReady = bReady; }

	///Kyle 06/17/2010 ORG-98 ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	//GraphPage	GetSourcePage()								{ return m_gpSource; }
	GraphLayer	GetSourceLayer()							{ return m_glSource; }
	///End ONE_LAYER_ONE_PROFILE_AND_SHARE_CALCULATOR_TO_SPEED_UP
	GraphPage	GetSourcePage();			///Kyle 07/14/2010 ORG-572-P1 SET_GRAPH_NOCLICK_AND_RESET_NOCLICK_ON_CLOSE
	bool		IsRelatedLayer(const GraphLayer& gl);

	bool		IsLinkProfileLines();
	void		SetLinkProfileLines(bool bSet);
	
	void		SetKeepGraphsOnClosing(bool bSet)					{ m_bKeepGraphsOnClosing = bSet; }
	bool		IsKeepGraphsOnClosing()								{ return m_bKeepGraphsOnClosing; }
	
	bool		IsLayoutSameGraphAllowed()							{ return !(m_dwOptions & IPROFILE_PROTECT_SOURCE); }

	int			GetLayoutMode();
	///Iris 6/11/2010 ORG-98-S36 SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	//bool		SetLayoutMode(int nMode);
	bool		SetLayoutMode(int nMode, vector<int>* pvnDeletedPathIndeces = NULL, vector<int>* pnPathTypes = NULL);
	///End SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	bool		CanSwitchLayoutModeTo(int nMode);
	
	int			GetActivePath();
	///Kyle 06/11/2010 ORG-98-P13 NO_NEED_TO_BEING_OBJECT_TO_FRONT_ON_SELECT_OBJECT
	//bool		SetActivePath(int nPath);
	bool		SetActivePath(int nPath, bool bBringObjToFront = false);
	///End NO_NEED_TO_BEING_OBJECT_TO_FRONT_ON_SELECT_OBJECT
	
	bool		SetPathName(int nPath, LPCSTR lpcszPathName);
	///Kyle 06/12/2010 ORG-98-S37 SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	/*
	///Kyle 06/07/2010 ORG-98 REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	//bool		SetProfileWidth(int nPath, double dProfileWidth);
	bool		SetLineWidth(int nPath, double dLineWidth);
	///End REMOVE_PROFILE_WIDTH_AND_ONLY_KEEP_LINE_WIDTH
	*/
	bool		SetProfileWidth(int nPath, double dWidth, int nUnit);
	///End SUPPORT_WIDTH_IN_PIXEL_AND_IN_SCALE
	bool		SetNumPoints(int nPoints, int nPath, bool bVertical);
	
	int			GetNumProfilePaths()						{ return m_arrProfilePath.GetSize(); }

	bool		OnDeleteSrcPage();
	int			OnDeleteProfileLine(UINT uObjUID);

	///Kyle 06/09/2010 ORG-98 CENTRALIZE_EVENT_HANDLING
	//int			OnProfileEvent(int nEvent, UINT uObjUID);
	int			OnProfileEvent(int nEvent, UINT uObjUID, int* pnPath = NULL);
	///End CENTRALIZE_EVENT_HANDLING
	int			OnReadOutEvent(int nEvent, UINT uObjUID, int* pnPath = NULL);

	int			GetPathIndex(UINT uObjUID);

	int			AddProfilePath(int nPathType, const vector& vX = NULL, const vector& vY = NULL);
	bool		CanAddProfilePath(int nPathType);

	ImageProfilerPath* GetProfilePath(int nIndex);
	bool		DeleteProfilePath(int nIndex);
	int			DuplicateProfilePath(int nIndex);

	bool		SaveToStorage();
	bool		InitFromStorage();
	///Iris 6/11/2010 ORG-98-S36 SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	// changed to clearAllStorage
	//bool		ClearStorage();
	///End SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS

protected:
	void		ClearProfilePath(bool bOnDestroy);

	string		GetNextPathName(int nPathType, LPCSTR lpcszPrefix = NULL);
	int			GetNextLineColor();
	bool		FindBestLocation(vector& vx, vector& vy, const GraphLayer& gl, int nPathType);
	void		RefreshAllProfile();

	bool		CheckSetProfileLayer(int nPath);

	bool		FindOutputWP(WorksheetPage& wpOutput);
	
	bool		PrepareOuptutLayer(int nPathType, GraphLayer& glSource, GraphLayer& glVertical, GraphLayer& glHorizontal);
	
	bool		RemovePathAt(int nIndex);

	bool		ReloadTemplate();
	bool		GetSrcPlot(DataPlot& dpSrc);
	
	string		GetLayoutTemplate(int nLayoutMode, int nPlotType, TemplateLayerInfo* pstTemplateInfo = NULL);

private:

	ImageProfilerPath* newPath(int nPathType);
	
	bool		addReopenTextButton(bool bRefresh = true, bool bVisible = true);
	
	///Iris 6/11/2010 ORG-98-S36 SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	bool		clearAllStorage();
	bool 		clearStorages(const vector<int>& vnPathIndeces);
	
	void		removeInvalidProfilePath(int nOldLayoutMode, int nNewLayoutMode, vector<int>& vnDeletedPathIndeces);
	///End SWITCH_MODE_NEED_KEEP_MEANINGFUL_PATHS
	
	bool		checkProfilePathTypeWithLayoutMode(int nLayoutMode, int nPathType);
	
};


/*----------------------------------------------------------------------------*/
/* ImageProfileHolder
/*----------------------------------------------------------------------------*/
class ImageProfileHolder
{
private:
	ImageProfileHolder()
	{
		m_arrProfileMngr.SetAsOwner(TRUE);
		m_pParentWnd = NULL;
		m_nActiveProfileIndex = -1;

		m_bIsUpdatingHolder = false;
	}
	~ImageProfileHolder()
	{
	}
	
private:
	Array<ImageProfileManager&>	m_arrProfileMngr;

	int 						m_nActiveProfileIndex;

	Window* 					m_pParentWnd;

	bool						m_bIsUpdatingHolder;

public:
	int		StartProfile(GraphPage& gp, int nLayoutMode = 0, DWORD dwOptions = IPROFILE_PROTECT_SOURCE);
	bool 	RemoveProfile(int nIndex = -1);
	bool 	ClearAllProfile();
	int		GetNumProfiles()						{ return m_arrProfileMngr.GetSize(); }

	///Kyle 07/21/2010 ORG-584-P2 CHECK_SHOW_DIALOG_AFTER_LOADING_PROFILE
	//int 	CheckLoadProfile(GraphLayer& gl, bool bLoadProfile);
	int 	CheckLoadProfile(GraphLayer& gl, bool bLoadProfile, bool* pbIsActive = NULL);
	///End CHECK_SHOW_DIALOG_AFTER_LOADING_PROFILE

	bool	OnActiveLayerChange();
	bool	OnDataModify(const DataRange& drChange);
	///Kyle 07/01/2010 ORG-355-P11 FIX_PROFILE_IS_NOT_REMOVED_ON_CLOSE_PAGE_WHEN_THERE_IS_NO_PATH
	bool	OnLayerDestroy(GraphLayer& gl);
	bool	OnPageDestroy(GraphPage& gp);
	///End FIX_PROFILE_IS_NOT_REMOVED_ON_CLOSE_PAGE_WHEN_THERE_IS_NO_PATH

	bool 	OnImageProfileEvent(int nEvent, UINT uPageUID, UINT uObjUID);
	bool	OnProfileReadOutEvent(int nEvent, UINT uPageUID, UINT uObjUID);

	const 	ImageProfileManager* GetActiveProfile();

	void	SetParentWnd(Window* pParentWnd);
	void 	ResetParentWnd();

	bool	IsUpdatingHolder()						{ return m_bIsUpdatingHolder; }
	void	SetUpdatingHolder(bool bSet = true)		{ m_bIsUpdatingHolder = bSet; }

private:
	void	sendMessage(DWORD wParam, DWORD lParam = 0);
	const 	ImageProfileManager* getProfileByIndex(int nIndex);			///Kyle 06/09/2010 ORG-98 CENTRALIZE_EVENT_HANDLING
	
	bool	onSrcLayerDestroy(GraphLayer& glSrc, bool& bActive);		///Kyle 07/01/2010 ORG-355-P11 FIX_PROFILE_IS_NOT_REMOVED_ON_CLOSE_PAGE_WHEN_THERE_IS_NO_PATH
	
	bool	checkSetPageNoClick(GraphPage& gp, bool bSetNoClick, bool bIgnorePageInProfiling = false);			///Kyle 07/14/2010 ORG-572-P1 SET_GRAPH_NOCLICK_AND_RESET_NOCLICK_ON_CLOSE
};

class ImageProfileHolderUpdateHelper
{
public:
	ImageProfileHolderUpdateHelper(ImageProfileHolder* pHolder)
	{
		ASSERT( pHolder );
		m_pHolder = pHolder;
		m_bIsUpdatingHolder = m_pHolder->IsUpdatingHolder();
		m_pHolder->SetUpdatingHolder();
	}
	
	~ImageProfileHolderUpdateHelper()
	{
		m_pHolder->SetUpdatingHolder(m_bIsUpdatingHolder);
	}
private:
	ImageProfileHolder*		m_pHolder;
	bool					m_bIsUpdatingHolder;
};

#define		HOLDER_BEFORE_UPDATE(_pHolder)	\
	if( _pHolder->IsUpdatingHolder() )	\
		return false;	\
	ImageProfileHolderUpdateHelper updateHelper(_pHolder)

#define		HOLDER_BEFORE_UPDATE_NO_CHECK(_pHolder)	\
	ImageProfileHolderUpdateHelper updateHelper(_pHolder)


/*----------------------------------------------------------------------------*/
/* global
/*----------------------------------------------------------------------------*/
bool	is_good_layer_for_profile(const GraphLayer& gl);

bool	is_good_plot_for_profile(const DataPlot& dp);

ImageProfileHolder* get_image_profile_holder();

bool	page_arrange_profile_layer(GraphPage& gp, int nMainLayer, int nVLayer = -1, int nHLayer = -1, int nVPercent = 0, int nHPercent = 0, bool bUndo = false);


#endif//_IMAGE_PROFILE_H
