/*------------------------------------------------------------------------------*
 * File Name: SmithChart.c				 										*
 * Creation: JCG 01-23-2002														*
 * Purpose: OriginC Source C file												*
 * Copyright (c) OriginLab Corp. 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007	*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * JCG 12/06/02 QA70-1474 SEMI_COLON_MISSED										*
 * Mouqx/Leo 2005-11-19 QA70-8083 SMITH_CHART_IS_DIFFERENT_FROM_MATLAB			* 
 *	ML QA70-9478 NO_LOCAL_H														*
 *	Fisher 1/8/09 QA80-9003	REINTERPRET_DATA_AS_MAG_ANGLE_IN_SMITH_CHART_DOES_NOT_WORK_IN_O8 
 *------------------------------------------------------------------------------*/
 
#include <origin.h>

//this header file contains string const that can be localized into different languages
// the '$' is placed in front of the file name to indicate that it might have a localization version
// located in the \Localization folder of the Origin installation
///DSC 1/11/07 REMOVE_LOCAL_H #include "$local.h"

//Function: void SmithChartRX2UV( double rr, double xx, double& uu, double& vv )
void SmithChartRX2UV( double rr, double xx, double& uu, double& vv )
{
	uu = ( rr^2 - 1 + xx^2 ) / ( ( rr + 1 )^2 + xx^2 );
	vv = 2 * xx / ( ( rr + 1 )^2 + xx^2 );				
}

//Function: void SmithChartRX2UV( double uu, double vv, double& rr, double& rr )
void SmithChartUV2RX( double uu, double vv, double& rr, double& xx )
{
	rr = ( 1 - uu^2 - vv^2 ) / ( (1 - uu )^2 + vv^2 );	
	xx = 2 * vv / ( ( 1 - uu )^2 + vv^2 );		
}

//Function: BOOL SmithChartSetParameters()
BOOL SmithChartSetParameters()
{
	if ( !IsSmithChartCoordinate() )
		return FALSE;

	double divideby;
	if( !LT_get_var( "layer.y.label.divideby",&divideby ) )
		return FALSE;
	
	string strRtip;
	strRtip.Format("%4.1f", 1 / divideby);
	
	if( !LT_set_str( "SmithChart!Rtip$", strRtip) )
			return FALSE;		

	if( !LT_set_str( "SmithChart!NormFactor$", strRtip) )
			return FALSE;		

	if( !LT_set_var( "SmithChart!Redit.v1", 1 / divideby * 1.2 ) ) //Make sure the R edit is larger that R tip.
			return FALSE;		
	
	return TRUE;
}

//Funciton: BOOL SmithChartNomalize( string strNormEdit )
BOOL SmithChartNomalize( string strNormEdit )
{
	
	if ( !IsSmithChartCoordinate() )
		return FALSE;
	
	if ( !strNormEdit.IsEmpty() )	//Not empty
	{
		double factor;

		if ( !LT_evaluate( strNormEdit , &factor ) ) //Need evaluate the value for given string
			return FALSE;

		if ( 0.0 == factor )
		{
			/// ML QA70-9478 NO_LOCAL_H
			//string strPromptZero = SM_FACTOR_EVAL_AS_ZERO;
			string	strPromptZero = _L("The factor was evaluated as zero.");
			/// end NO_LOCAL_H
			MessageBox( NULL, strPromptZero );
			return FALSE;
		}
		
		//Here test the norm edit string, if = 1 set as 1, if 33.3 set as 3/100 else set as 1/string.
		if( !strNormEdit.Compare("1"))
			; //Null
		else
		if( !strNormEdit.Compare("33.3"))
			strNormEdit = "3/100";
		else
			strNormEdit = "1/" + strNormEdit;
				
		//Set divideby string.	
		if( !LT_set_str( "layer.x.label.divideby$", strNormEdit ) )	//For consistency with plot detail dialog box
			return FALSE;		

		if( !LT_set_str( "layer.y.label.divideby$", strNormEdit ) )  //For consistency with plot detail dialog box
			return FALSE;		
					
		if( is_equal( round( factor, 3 ), round( 1.0, 3 ) ) )
		{
			if( !LT_set_var( "layer.x.decPlaces", 1 ) )
				return FALSE;		

			if( !LT_set_var( "layer.y.decPlaces", 1 ) )
				return FALSE;		
		}
		else
		{
			if( !LT_set_var( "layer.x.decPlaces", 0 ) )
				return FALSE;		

			if( !LT_set_var( "layer.y.decPlaces", 0 ) )
				return FALSE;		
		}

		double divideby;
		if( !LT_get_var( "layer.y.label.divideby",&divideby ) )
			return FALSE;

		if( !LT_set_var( "SmithChart!Redit.v1", 1 / divideby * 1.2 ) ) //Make sure the R edit is larger that R tip.
		return FALSE;		
		
		if( !LT_set_str( "SmithChart!Rtip$", strNormEdit ) )
			return FALSE;		
		
		return TRUE;
	}
	else
	{
		/// ML QA70-9478 NO_LOCAL_H
		//string strPromptEmpty = SM_FACTOR_NOT_EMPTY;
		string		strPromptEmpty = _L("The factor can not be empty.");
		/// end NO_LOCAL_H
		MessageBox( NULL, strPromptEmpty );
	}
	
	return FALSE;
}


//Function: BOOL SmithChartReverse( )
BOOL SmithChartReverse( )
{
	if ( !IsSmithChartCoordinate() )
		return FALSE;

	double reverse;
	if( !LT_get_var( "layer.x.reverse",&reverse ) )
		return FALSE;

	if ( reverse == 1 )
	{
		if( !LT_set_var( "layer.x.reverse", 0 ) )
			return FALSE;		
	}
 	else
 	{
		if( !LT_set_var( "layer.x.reverse", 1 ) )
			return FALSE;		
	}

	return TRUE;
}

//Function: BOOL SmithChartConvert(string strCurve, UINT opt)
// Arg: if opt = CONVERT_DATA_TO_MAGANG, convert current data to R+jX format			
// 		if opt = REINTERPRET_DATA_AS_MAGANG, caculate the MAG/ANG data from R and X value	

enum{ CONVERT_DATA_TO_MAGANG = 0, REINTERPRET_DATA_AS_MAGANG };

BOOL SmithChartConvert(string strCurve, UINT nOpt)
{
	if ( !IsSmithChartCoordinate() )
		return FALSE;

	if ( !SmithChartCheckCurveName( strCurve ) )
		return FALSE;
	
	
	Curve cc(strCurve);
	
	string	strYdataName;
	if(!cc.GetName(strYdataName))
		return FALSE;
	
	Dataset xData;
	
	if(!cc.AttachX(xData)) 
		return FALSE;
	
	string strWksName;
	string strColName;
	
	int		nUnderScorePos = strYdataName.Find( '_' );
	
	if ( -1 == nUnderScorePos || 0 == nUnderScorePos )
		return FALSE;
	
	
	strWksName = strYdataName.Left( nUnderScorePos );
	strColName = strYdataName.Right( strYdataName.GetLength() - nUnderScorePos - 1 );
	
	Worksheet wks(strWksName);	
	int		nYDataColNum = wks.Columns(strColName).GetIndex();
	
	string strMagCol, strAngCol;
	strMagCol = "Mag";
	strAngCol = "Angle";
	
	if( !wks.InsertCol(nYDataColNum + 1, strMagCol, strMagCol ) )
		return FALSE;
	
	if ( !wks.Columns( nYDataColNum + 1 ).SetType(OKDATAOBJ_DESIGNATION_X ) )
		return FALSE;
	
	if( !wks.InsertCol(nYDataColNum + 2, strAngCol, strAngCol ) )
		return FALSE;

	if ( !wks.Columns( nYDataColNum + 2).SetType(OKDATAOBJ_DESIGNATION_Y ) )
		return FALSE;

	
	UINT nRows = xData.GetUpperBound() + 1;

	double rr, xx, uu,vv;
	
	Dataset mag( strWksName,nYDataColNum + 1);
	Dataset angle( strWksName,nYDataColNum + 2 );
	
	mag.SetSize(nRows);
	angle.SetSize(nRows);
	
	// assume we are working on current graph layer
		
	double divideby;
	if(!LT_get_var("layer.y.label.divideby",&divideby))
		return FALSE;

	UINT ii;
	
	if( nOpt == CONVERT_DATA_TO_MAGANG )
	{
		for ( ii = xData.GetLowerBound(); ii < nRows; ii++ )
		{
			rr = xData[ii];
			xx = cc[ii];
			
			// rr can not be -1 and at the same time xx equal 0			
			if( -1 != rr && 0 != xx )
			{
	
				SmithChartRX2UV( rr, xx, uu, vv );
				
				mag[ii] = sqrt( ( uu^2 + vv^2 ) ) / divideby;
				
				if(0 != uu )
					angle[ii] = atan( vv / uu ) * 180 / PI;
				else
				{
					if(0 != vv )
						angle[ii] = 90;
					else
						angle[ii] = 0;
				}	
			}
			else
			{
				mag[ii] = 0; //-1 maybe the negative plot
				angle[ii] = 0;
			}
		}
	}

	if( nOpt == REINTERPRET_DATA_AS_MAGANG )
	{
		//First backup the original data
		for ( ii = xData.GetLowerBound(); ii < nRows; ii++ )
		{						
			mag[ii] = xData[ii];
			angle[ii] = cc[ii];		
		}
	
		//The mag must bein the range of -1 and 1
		//and the angle is in the unit of degree.	
		//After the conversion the norlization values are set as 1
		
		for ( ii = xData.GetLowerBound(); ii < nRows; ii++ )
		{
			///Mouqx/Leo 2005-11-19 QA70-8083 SMITH_CHART_IS_DIFFERENT_FROM_MATLAB
			//uu = mag[ii] * cos ( angle[ii] * PI / 180 );
			//vv = mag[ii] * sin ( angle[ii] * PI / 180 );
			/// Fisher 1/8/09 QA80-9003	REINTERPRET_DATA_AS_MAG_ANGLE_IN_SMITH_CHART_DOES_NOT_WORK_IN_O8 
			//uu=xData[ii];
			//vv=cc[ii];
			uu = mag[ii] * cos ( angle[ii] * PI / 180 );
			vv = mag[ii] * sin ( angle[ii] * PI / 180 );
			/// End REINTERPRET_DATA_AS_MAG_ANGLE_IN_SMITH_CHART_DOES_NOT_WORK_IN_O8
			///End SMITH_CHART_IS_DIFFERENT_FROM_MATLAB
			
			//uu can not be 1 and at the same time vv equal 0
			if( 1 == uu  && 0 == vv )
			{ 
				xData[ii] = 0;
				cc[ii] = 1;
			}
			else
			{
				SmithChartUV2RX( uu, vv, xData[ii], cc[ii] );
			}	
		}

		//At last the divideby must set as 1;		
		if( !LT_set_str( "layer.x.label.divideby$","1" ) )
			return FALSE;		
			
		if( !LT_set_str( "layer.y.label.divideby$","1" ) )
			return FALSE;

		//Also shold set the decimal places at 1;
		if( !LT_set_var( "layer.x.decPlaces", 1 ) )
			return FALSE;		

		if( !LT_set_var( "layer.y.decPlaces", 1 ) )
			return FALSE;		

	}
	
	string strActivate = "win -a ";
	strActivate += strWksName;
	LT_execute(strActivate, 0);
	return TRUE;
}

	
BOOL SmithChartSWR( string strCurve, double ptR, double ptX )
{
	if ( !IsSmithChartCoordinate() )
		return FALSE;
	
	string strWksSWRName = "SWRData";
		
	Worksheet wks( strWksSWRName );	
	
	if ( !wks.IsValid() )
	{	
		if ( !wks.Create( NULL , CREATE_HIDDEN) ) //If SWRData is not exist create a new one
			return FALSE;
		
		Page pp;;
		pp = wks.GetPage();
		
		if ( !pp.Rename( strWksSWRName ) ) // Rename the new one as SWRData
			return FALSE;
	
		//ASSERT( 2 == wks.GetNumCols() )   //2 cols by default.
		ASSERT( 2 == wks.GetNumCols() );   //2 cols by default. ///JCG 12/06/02 QA70-1474 SEMI_COLON_MISSED
	
		while( wks.DeleteCol(0) );
		
		ASSERT( 0 == wks.GetNumCols() );

	}

	double divideby;
	if( !LT_get_var( "layer.y.label.divideby",&divideby ) )
		return FALSE;
	
	if( ptR <= 1 / divideby )
	{
		string strRtip;
		
		strRtip.Format("%4.1f", 1 / divideby);		
		
		/// ML QA70-9478 NO_LOCAL_H
		//string strPrompt = SM_RVAL_LARGER_THAN + strRtip;
		string	strPrompt = _L("R value should be larger than ") + strRtip;
		/// end NO_LOCAL_H
		
		MessageBox( NULL, strPrompt );
		
		return TRUE;
	}
		
	ptR *= divideby;
	ptX *= divideby;
	
	double uu,vv, mag;
	
	SmithChartRX2UV( ptR, ptX, uu, vv );
	
	mag = sqrt( ( uu^2 + vv^2 ) );

	string strRadius;
	strRadius.Format("%4.2f", mag );
						
	string strSWRRCol, strSWRXCol;
	strSWRRCol = "SWRR" + strRadius;
	strSWRXCol = "SWRX" + strRadius;
	
	if( wks.Columns( strSWRRCol) == NULL )
	{
		if ( wks.AddCol( strSWRRCol, strSWRRCol ) < 0 )
			return FALSE;
	}

	if ( !wks.Columns( strSWRRCol).SetType(OKDATAOBJ_DESIGNATION_X ) )	//Set column type as X i.e. R for smith chart
		return FALSE;

	if( wks.Columns( strSWRXCol) == NULL )
	{
		if ( wks.AddCol( strSWRXCol, strSWRXCol ) < 0 )
			return FALSE;
	}
	
	if ( !wks.Columns( strSWRXCol).SetType(OKDATAOBJ_DESIGNATION_Y ) )	//Set column type as Y i.e. X for smith chart
		return FALSE;

	 
	if( !wks.Columns( strSWRRCol).SetWidth( strSWRRCol.GetLength() + 4  ) ) // 4 is for the width of "(X2)" 
		return FALSE;

	if( !wks.Columns( strSWRXCol).SetWidth( strSWRXCol.GetLength() + 4  ) ) // 4 is for the width of "(X2)" 
		return FALSE;

	Dataset SWRR( strWksSWRName, wks.Columns(strSWRRCol).GetIndex() );
	Dataset SWRX( strWksSWRName, wks.Columns(strSWRXCol).GetIndex() );

	double dbPointDensity;
	if( !LT_get_var( "SmithChart!PointDensity",&dbPointDensity ) )
		return FALSE;
	
	double angleStep = ( 4 - dbPointDensity ) / mag / 5; // 1 degree for High, 2 degree for Medium, 3 degree for low 
	
	int nPts = 360 / angleStep;	

	angleStep *= PI / 180;
				 	
	if ( nPts > wks.GetNumRows() ) // Append rows if not enough
	{
		if( !wks.AppendRows( nPts - wks.GetNumRows() ) )
			return FALSE;
	}

	SWRR.SetSize( nPts + 1 ); //Allocate memory here and Make sure the cirlce is closed
	SWRX.SetSize( nPts + 1);

	for( UINT ii = 0; ii < nPts; ii++ )	
	{
		uu = mag * cos ( ii * angleStep );
		vv = mag * sin ( ii * angleStep );

		if( 1 == uu  && 0 == vv )
		{ 
			SWRR[ii] = 0;
			SWRX[ii] = 1 / divideby;  // Use current user selected normalize value
		}
		else
		{
			SmithChartUV2RX( uu, vv, SWRR[ii], SWRX[ii] );
	
			SWRR[ii] /= divideby;	// Use current user selected normalize value
			SWRX[ii] /= divideby;	// Use current user selected normalize value	
		}
	}
	
	SWRR[ nPts ] = SWRR[0];
	SWRX[ nPts ] = SWRX[0];
	
	char	szGraphName[20];
	if( !LT_get_str( "%H", szGraphName, 20 ) ) 	// Get current graph name by labtalk
		return FALSE;
		
	Curve	ccswr( strWksSWRName + "_" + strSWRRCol, strWksSWRName + "_" + strSWRXCol);
	if ( ccswr.IsValid() )
	{
		GraphLayer	graph( szGraphName );
		int			nCurveColor = 1;// need to get from DDK, 1=Black, 2 = Red, 3 = Blue
		int nPlot = graph.AddPlot( ccswr, IDM_PLOT_LINE );
		if ( nPlot < 0 ) // plot SWR data
			return FALSE;
		
		double dbColorIndex;
		if( !LT_get_var( "SmithChart!CircleColor",&dbColorIndex ) )
			return FALSE;

		nCurveColor = dbColorIndex;
		switch(nCurveColor)
		{
		case 1:
			graph.DataPlots(nPlot).SetColorRGB(0,0,0);
			break;
		case 2:	 // Red
			graph.DataPlots(nPlot).SetColorRGB(255,0,0);
			break;
		case 3:	 // Blue
			graph.DataPlots(nPlot).SetColorRGB(0,0,255);
			break;
		}
	}

	return TRUE;
}
	

//Function: BOOL IsSmithChartCoordinate()
BOOL IsSmithChartCoordinate()
{
	char	szGraphName[20];
	if( !LT_get_str( "%H", szGraphName, 20 ) ) 	// Get current graph name by labtalk
		return FALSE;

	GraphLayer	graph( szGraphName );
	if(graph)
	{	
		UINT nCoorType = graph.GetCoordinateType();
		
		if ( FRAME_COOR_SMITH_CHART == nCoorType )
			return TRUE;
	}
	return FALSE;
}

BOOL SmithChartCheckCurveName( string strCurveName )
{
	if( strCurveName.IsEmpty() )
	{
		/// ML QA70-9478 NO_LOCAL_H
		//string strPrompt = SM_NO_CURVE; 
		string		strPrompt = _L("Should have a worksheet to put data in"); 
		/// Mend NO_LOCAL_H
		MessageBox( NULL, strPrompt );
		return FALSE;
	}	
	return TRUE;
}
