using System;
using System.Collections;
using System.IO;
using System.Windows.Forms;
using System.Text;
using System.Drawing;
using VG;
using C1.C1Pdf;
namespace XYPlots
{
	/// 
	/// Summary description for XYPlot.
	/// 
	public class XYPlot
	{
//		private int ConvertToTwips = 1440;
		private double ConvertToTwips = 4.8;
		static long HP3_HPGL_COMPENSATEX = 1016L; /* OK, so you don't believe it */
		static long  HP3_HPGL_COMPENSATEY = 1016L;/* OK, so you don't believe it */
		static long PRINTAPLOT_COMPENSATE = 1020L;/* but these resolve differently*/
		static int MAX_XY_STACK = 8;		/* this is max of CIE cursor/font stack */
		static int DPI = 1440; //300;
		static int CWIDEDOTS = 120; //25;
		static int CHIGHDOTS = 240; //50;
		static int STRAIGHT = 0;
		static int CURVE = 1;
		static int DASH = 2;
		static int X = 0;
		static int Y = 1;
		static int Dimensions = 2;
		static int USER = 0;
		static int PLOT = 1;
		static double PI=3.141592653;
		static double Zero=0.0;
		static double ANGLELIMIT=1.0;
		// !!!! NEED REAL SUPERSCRIPT ON/OFF TOKENS
		static string []SuperScript = {"##","##"};
		static string []SubScript = {"~~","~~"};
		FileStream XYPlotFile;
		int []SavedX;
		int []SavedY;
		int stack;
		int HPGLMode;
		long HP_FudgeX = HP3_HPGL_COMPENSATEX;
		long HP_FudgeY = HP3_HPGL_COMPENSATEY;
		string GoodOldStringX;
		string GoodOldStringY;
		public int LinesUsed;
		string valuestring;
		string powerstring;
		int GridOnFlag,Visible,ShadowFlag;
		char[] type = new char[Dimensions];
		double FontPitch = 10.0;
		double[] minimum = new double[Dimensions];
		double[] maximum = new double[Dimensions];
		double[] userunits = new double[Dimensions];
		int[] printerunits = new int[Dimensions];
		int[] Position = new int[Dimensions];
		double[,] Scale = new double[2,Dimensions];
		double[,] Offset = new double[2,Dimensions];
		double[] delta = new double[Dimensions];
		int[] cycles = new int[Dimensions];
		int[] onecycle =  new int[Dimensions];
		int[] minor = new int[Dimensions];
		int[] spcminor = new int[Dimensions];
		string[] AxisTitles = new string[Dimensions];
		int[] AxisLabel =  new int[Dimensions];// = {1,1};  /* 1 for YES(default), 0 for NO*/
		string LineBuff;
		int CurPenWidth, DrawDirection, LineFlag, LineDiv;
		int EndFlag = 0;
		public string Buff; //[4096],*BuffPtr;
		int BuffPtr = 0;
		//double (*f[2][2])(double);
		bool [,]doLOG10 = {{false,false},{false,false}};
		struct point 
		{
			public int[] xyValue; //new int[Dimensions];
		}
		struct BoxList 
		{
			public int Shadow;
			public string BoxText;
			public point BoxMinimum;
			public point BoxMaximum;
			//BoxList *NextBox;
		};
		ArrayList AllBoxes = new ArrayList();
		struct ActiveBoxList 
		{
			public ArrayList BoxPtr;
			//ActiveBoxList *NextActiveBox;
		};
		ArrayList AllActiveBoxes = new ArrayList();
		class PointList 
		{
			private point m_APoint;
			private double m_slope;		/* slope of tangent to circle at this point */
			public point APoint
			{
				get{return m_APoint;}
				set{m_APoint=value;}
			}
			public double slope
			{
				get{return m_slope;}
				set{m_slope=value;}
			}
			//PointList *NextPoint;
		};
//		public ArrayList PointListArray = new ArrayList();
		struct LineList 
		{
			public int PlotType;
			public int PlotDivisions;
			//			public PointList PlotPoint;
			public ArrayList PlotPointsList;
//			public LineList NextPlot;
		};
		ArrayList AllPlots = new ArrayList();
		int YLandScape=0;				/* y axis title is horizontal */
		point YTitleOrigin;		/* y axis title origin if vertical */
		double FixAngle(double a1) 
		{
			double retval;
			int sign;
			if(a1 < 0) 
			{
				a1=-a1;
				sign=-1;
			} 
			else
				sign=1;
			retval=sign*Math.Floor(0.5+a1);
			return(retval);
		}
		double dsquare(int val) 
		{
			double result;
			result = (double)(val*val);
			return( result );
		}
		double FMin(double f1,double f2) 
		{
			return((f1>=f2)?f2:f1);
		}
		double FMax(double f1,double f2) 
		{
			return((f1>=f2)?f1:f2);
		}
		double atan_deg(double x) 
		{
			return( Math.Atan(x) * 180.0/PI );
		}
		double cos_deg(double x) 
		{
			return( Math.Cos(x*PI/180.0) );
		}
		double tan_deg(double x) 
		{
			return( Math.Tan(x*PI/180.0) );
		}
		double sin_deg(double x) 
		{
			return( Math.Sin(x*PI/180.0) );
		}
		/*
		** the following function is pointed to by a function pointer
		** and is provided for compatibility with log10() function usage
		*/
		double linear(double x) 
		{
			return(x);
		}
		bool isWhiteSpace(char cptr) 
		{
			bool rtnval = false;
			if (!cptr.Equals(null))
			{
				int idx = "\t\n\r\f ".IndexOf(cptr);
				rtnval = (idx > -1);
			}
			return rtnval;
			//			return((c) ? strchr("\t\n\r\f ",c):NULL);
		}
		//		int NextPiece() 
		string NextPiece() 
		{
			string rtnval;
			//			char *ptr;
			int ptr;
//			int buflen = Buff.Length;
			while(BuffPtr >= 0 && Buff[BuffPtr] != 0 && isWhiteSpace(Buff[BuffPtr]))BuffPtr++;
//			while(BuffPtr < buflen && Buff[BuffPtr] != 0 && isWhiteSpace(Buff[BuffPtr]))BuffPtr++;
			ptr=BuffPtr;
			while(BuffPtr >= 0 && Buff[BuffPtr] != 0 && !isWhiteSpace(Buff[BuffPtr]))BuffPtr++;
//			while(BuffPtr < buflen && Buff[BuffPtr] != 0 && !isWhiteSpace(Buff[BuffPtr]))BuffPtr++;
			if ( EndOfCommand() ) EndFlag=1;
			rtnval = Buff.Substring(ptr,BuffPtr-ptr);
			BuffPtr++;
			return rtnval;
		}
		bool EndOfCommand() 
		{
			int tmpPtr = BuffPtr;
//			if (BuffPtr >= Buff.Length)
//				return true;
			while (!Buff[tmpPtr].Equals('\0') && Buff[tmpPtr].Equals(' ')) tmpPtr++;
			if (!Buff[tmpPtr].Equals('\0') && !isWhiteSpace(Buff[tmpPtr])) 
				return false;
			else if (Buff[tmpPtr] == '\r' || Buff[tmpPtr] == '\n' || Buff[tmpPtr] == '\0')
				return true;
			else
				return false;
		}
		bool LoadBuff(string FileName) 
		{
			if (!File.Exists(FileName))
			{
				// File does not exist, show error message
				MessageBox.Show(String.Format("X/Y Plot File {0} Does Not Exist",FileName),"Error Opening X/Y Plot File");
				return false;
			}
			// Open the X/Y Plot file
			try 
			{
				XYPlotFile = File.OpenRead(FileName);
			}
			catch (Exception e)
			{
				// cannot open the x/y plot file
				MessageBox.Show(e.Message,String.Format("Error Opening {0} for Reading",FileName));
				return false;
			}
			int blen = (int)XYPlotFile.Length;
			int bread = 0;
			
			// initialize a byte array to read into
			byte []bbuf = new byte[blen+1];
			for (int i=0; i\r\n<",ptr)) > 0)
			{
				// blank out ">"
				Buff = Buff.Remove(ptr,1);
				Buff = Buff.Insert(ptr," ");
				// remove "<"
				Buff = Buff.Remove(ptr+3,1); 
				// if command on next line is blank,
				// combine with the previous line
				if (Buff[ptr+3] == ' ')
					Buff = Buff.Remove(ptr,3);
			}
			ptr = Buff.Length-5;
//			if (Buff.EndsWith(">>\r\n"))
			if (Buff.IndexOf(">>\r\n",ptr) > 0)
			{
				Buff = Buff.Remove(ptr,2);
				Buff = Buff.Insert(ptr,"  ");
//				Buff[ptr] = ' ';
//				Buff[ptr+1] = ' ';
			}
		}
		void CloseGraph() 
		{
			/* Send back number of lines used assuming 6 lines per inch */
			if( LinesUsed==0 )
				LinesUsed=(int)(1.5 * CHIGHDOTS);		/* adjust for x axis tics */
			LinesUsed += printerunits[Y];
			LinesUsed = LinesUsed/CHIGHDOTS;
		}
		void GetScaleInfo() 
		{
			GridOnFlag=getint();
			userunits[X]=getdouble();
			userunits[Y]=getdouble();
//			f[USER][X]=linear;			/* f is a function pointer */
//			f[USER][Y]=linear;			/* linear is a function    */
			printerunits[X]=(int)(DPI*userunits[X]);
			printerunits[Y]=(int)(DPI*userunits[Y]);
			minimum[X]=getdouble();
			maximum[X]=getdouble();
			minimum[Y]=getdouble();
			maximum[Y]=getdouble();
			type[X]=getchr();
			type[Y]=getchr();
			if(EndFlag == 0) delta[X]=getdouble();
			if(EndFlag == 0) delta[Y]=getdouble();
			if(EndFlag == 0) spcminor[X]=getint();
			if(EndFlag == 0) spcminor[Y]=getint();
			Offset[USER,X]=0;
			Offset[USER,Y]=0;
			Scale[USER,X]=DPI;
			Scale[USER,Y]=DPI;
			/*
				  in the following if blocks, the array variable f is a function
				  pointer which is set to either the function linear or log10.
			*/
			/* X-axis function generation and scaling */
			if(type[X] != 'L') 
			{ 
				// Linear
				doLOG10[PLOT,X]=false; 
				LinearScale(X);
				Scale[PLOT,X] = printerunits[X] / (maximum[X]- minimum[X]);
				Offset[PLOT,X] =- Scale[PLOT,X] * minimum[X];
			}
			else
			{ 
				// Log10
				doLOG10[PLOT,X]=true;  
				LogScale(X); 
				Scale[PLOT,X] = printerunits[X] /
					(Math.Log10(maximum[X])- Math.Log10(minimum[X]));
				Offset[PLOT,X] =- Scale[PLOT,X] * Math.Log10(minimum[X]);
			}
			/* Y-axis function generation and scaling */
			if(type[Y] != 'L') 
			{
				// Linear
				doLOG10[PLOT,Y]=false; 
				LinearScale(Y);
				Scale[PLOT,Y]=printerunits[Y]/ (maximum[Y] - minimum[Y]);
				Offset[PLOT,Y] =- Scale[PLOT,Y] * minimum[Y];
			}
			else               
			{ 
				// Log10
				doLOG10[PLOT,Y]=true;  
				LogScale(Y); 
				Scale[PLOT,Y]=printerunits[Y]/
					(Math.Log10(maximum[Y]) - Math.Log10(minimum[Y]));
				Offset[PLOT,Y] =- Scale[PLOT,Y] * Math.Log10(minimum[Y]);
			}
		}
		void GetAxisTitle(int flag) 
		{
			AxisTitles[flag]=GetString();
		}
		string stripSuperSub(string instr)
		{
			StringBuilder sb = new StringBuilder(instr);
			sb.Replace(SuperScript[0],"");
			sb.Replace(SuperScript[1],"");
			sb.Replace(SubScript[0],"");
			sb.Replace(SubScript[1],"");
			return sb.ToString();
		}
		point DetermineBoxMax(BoxList boxptr) 
		{
			
			point newval = new point();
			newval.xyValue = new int[Dimensions];
			string tmp;
			int pos = 0, prevPos = 0;
			int nl = 0, xmax = 0, ilen = 0;
			tmp = stripSuperSub(boxptr.BoxText);
			while ((pos = tmp.IndexOf('\n',pos)) > -1)
			{
				ilen = pos - prevPos; //  -1; this will fix an arythmatic bug
				xmax = Math.Max(xmax,ilen);
				prevPos = pos;
				pos++;
				nl++;
			}
			ilen = tmp.Substring(prevPos+1).Length;
			xmax = Math.Max(xmax,ilen) + 2;
//			nl += 2;
			newval.xyValue[X] = boxptr.BoxMinimum.xyValue[X]+(xmax*CWIDEDOTS);
			newval.xyValue[Y] = boxptr.BoxMinimum.xyValue[Y]-(nl*CHIGHDOTS)-(int)(30 * ConvertToTwips);
//						newval.xyValue[Y] = boxptr.BoxMinimum.xyValue[Y]+(nl*CHIGHDOTS)-(int)(30 * ConvertToTwips);
//			boxptr.BoxMaximum = newval;
			return newval;
		}
		void GetBoxParameters() 
		{
			BoxList NewBox = new BoxList();
//			point Origin =  new point();
//			Origin.xyValue = new int[Dimensions];
			point Origin;
			Origin = GetPair(USER);
			string str = GetString();
			NewBox.BoxText = str;
			NewBox.BoxMinimum = Origin;
			NewBox.Shadow = ShadowFlag;
			ShadowFlag = 0;
			NewBox.BoxMaximum = DetermineBoxMax(NewBox);
			// jsj
			point minPoint = new point();
			minPoint.xyValue = new int[Dimensions];
			point maxPoint = new point();
			maxPoint.xyValue = new int[Dimensions];
			minPoint.xyValue[X] = Origin.xyValue[X];
			minPoint.xyValue[Y] = NewBox.BoxMaximum.xyValue[Y];
			maxPoint.xyValue[X] = NewBox.BoxMaximum.xyValue[X];
			maxPoint.xyValue[Y] = Origin.xyValue[Y];
			NewBox.BoxMinimum = minPoint;
			NewBox.BoxMaximum = maxPoint;
			//jsj
			AllBoxes.Add(NewBox);
		}
		void GetLineParameters() 
		{
			//			PointList NewPlotData;
			//			int curptr, prevptr;
			ArrayList PointListArray = new ArrayList();
			int pointcount;
			pointcount = EndFlag = 0;
			while (EndFlag == 0)
			{
				PointList pl = new PointList();
				pl.APoint = new point();
				//pl.APoint.xyValue = new int[Dimensions];
				pl.APoint = GetPair(PLOT);
				pointcount++;
				PointListArray.Add(pl);
			}
			if (LineFlag == CURVE && pointcount > 2)
				CalculateSlopes(PointListArray);
			else
				LineFlag = STRAIGHT;
#if DEBUG
			ShowPoints(PointListArray);
#endif
			AddAPlot(PointListArray);
		}
#if DEBUG
		void ShowPoints(ArrayList al)
		{
			foreach(PointList pl in al)
			{
				Console.WriteLine("x={0},y={1},slope={2}",pl.APoint.xyValue[0],pl.APoint.xyValue[1], pl.slope);
			}
		}
#endif
		double FindSlope(point first, point last) 
		{
			double dx, dy, result;
			dx = last.xyValue[X] - first.xyValue[X];
			dy = (last.xyValue[Y] - first.xyValue[Y]);
//			dy = first.xyValue[Y] - last.xyValue[Y];
			if (dx == 0.0)
			{
				if (dy > 0)
					result = Convert.ToDouble("1.E99");
				else
					result = Convert.ToDouble("-1.E99");
			}
			else
				result = dy/dx;
			return result;
		}
		double FindEndSlope(point first, point last,double s1) 
		{
			double result;
			result = 2.0 * FindSlope (first,last) - s1;
			if (result * s1 < 0.0)
				result = 0.0;
			return result;
		}
		void CalculateSlopes(ArrayList PlAry) 
		{
			PointList thispt, prevpt, firstpt;
			long yval, y1, y3;
			int PlAryIdx = 0;
			int PlAryNumItems = PlAry.Count;
			prevpt = (PointList) PlAry[PlAryIdx];
			PlAryIdx++;
			thispt = (PointList) PlAry[PlAryIdx];
			while (PlAryIdx + 1 < PlAry.Count)
			{
				thispt.slope = Zero;
				yval = thispt.APoint.xyValue[Y];
				y1 = prevpt.APoint.xyValue[Y];
				y3 = ((PointList)PlAry[PlAryIdx +1]).APoint.xyValue[Y];
				if ((yval-y1)*(y3-yval) > 0)
//				if ((yval-y1)*(y3-yval) < 0) // jsj
					thispt.slope = FindSlope(prevpt.APoint,((PointList)PlAry[PlAryIdx +1]).APoint);
				prevpt = thispt;
				PlAryIdx++;
				thispt = (PointList)PlAry[PlAryIdx];
			}
			firstpt = (PointList)PlAry[0];
			firstpt.slope = FindEndSlope(firstpt.APoint,((PointList)PlAry[1]).APoint,((PointList)PlAry[1]).slope);
			thispt.slope = FindEndSlope(thispt.APoint,prevpt.APoint,prevpt.slope);
		}
		void AddAPlot(ArrayList ptr) 
		{
			LineList NewLine = new LineList();
			NewLine.PlotType = LineFlag;
			NewLine.PlotDivisions = LineDiv;
			NewLine.PlotPointsList = ptr;
			AllPlots.Insert(0,NewLine);
		}
		void GenerateGrid(VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			AllActiveBoxes.Clear();
			SetPenDiameter(5);
			Position[X]= 0; 
			Position[Y]= 0; // printerunits[Y];
			SavePosition();
			BoxRelative(printerunits[X],printerunits[Y],CurPenWidth,pg,pdf);
			if(GridOnFlag == 0) Visible=0;
			DrawDirection=Y;
			DoGrid(X,pg,pdf);
			DrawDirection=X;
			DoGrid(Y,pg,pdf);
			Visible=1;
			RecallPosition();
		}
		void DoGrid(int flag,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			if( type[flag] != 'L' )
				DoLinearGrid(flag,pg,pdf);
			else
				DoLogGrid(flag,pg,pdf);
		}
		void DoLinearGrid(int flag,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int i,n,ns,subminor;
//			int i,n,ns,x1,x2,y1,y2,subminor;
			int ptval;
			n = (int)(0.5 + (maximum[flag] - minimum[flag]) / delta[flag]);
			ns = n * minor[flag];
			if ((minor[flag] % 2) != 0)
				subminor = minor[flag];
			else
				subminor = minor[flag] / 2;
			for(i=0; i <= ns; i++) 
			{
				SetPenDiameter((((i % minor[flag])!=0) ? (((i % subminor)!=0) ? 1 : 2) : 3));
				ptval = ((int)printerunits[flag]) * i / ns;
				if (flag ==Y)
					ptval = printerunits[Y] - ptval;
				MoveAbsolute(((flag == X)? ptval : 0),((flag == Y)? ptval : 0));
//				MoveAbsolute(((flag == X)? ptval : 0),((flag == Y)? ptval : printerunits[Y]));
				if(i % minor[flag] == 0)
					WriteValue(flag,minimum[flag] + i * delta[flag] / minor[flag],false,pg,pdf);
//				DrawGridLine(!flag,ptval);
				DrawGridLine((flag==0)?1:0,ptval,pg,pdf);
			}
		}
		void DoLogGrid(int flag,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			double showval;
			int gs,ge,gd;
			int i,ptval;
//			int i,x1,x2,y1,y2,ptval;
			showval  =minimum[flag];
			for (i=0; i < cycles[flag]; i++) 
			{
				gs = gd = 100;
				ge = 1000;
				ptval=((int)printerunits[flag]) * i / cycles[flag];
				if (flag ==Y)
					ptval = printerunits[Y] - ptval; //jj
				MoveAbsolute(((flag == X)? ptval : 0),((flag == Y)? ptval : 0));
				SetPenDiameter(3);
				WriteValue(flag,showval,false,pg,pdf);
				GenGrid(flag,gs,ge,gd,onecycle[flag],2,i * onecycle[flag],pg,pdf);
				showval *= 10.0;
			}
			ptval=((int)printerunits[flag]) * i / cycles[flag];
			if (flag ==Y)
				ptval = printerunits[Y] - ptval; //jj
			MoveAbsolute(((flag == X)? ptval : 0),((flag == Y)? ptval : 0));
			SetPenDiameter(3);
			WriteValue(flag,showval,false,pg,pdf);
		}
		void WriteValue(int flag, double val, bool SubLogValue, VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int size;
			size=GenNumberString(val);
			SavePosition();
			if (flag == X) 
			{
				MoveRelative(0,-printerunits[Y]);
//				DrawGridRelative(0,30,pg,pdf);
//				DrawGridRelative(0,(int)(-30 * ConvertToTwips) - printerunits[Y],pg,pdf);
				if (!SubLogValue)
					DrawGridRelative(0,(int)(-30 * ConvertToTwips),pg,pdf);
				//				MoveRelative((int)((-150 * size / (int)FontPitch) * ConvertToTwips), (int)(60 * ConvertToTwips));
				MoveRelative((int)((-130 * size / (int)FontPitch) * ConvertToTwips), (int)(-60 * ConvertToTwips));
				if ((AxisLabel[0])!=0) 
				{
					if (SubLogValue)
					{
						StringBuilder sb = new StringBuilder();
						sb.Append(SuperScript[0]);
						sb.Append(valuestring);
						sb.Append(SuperScript[1]);
						valuestring = sb.ToString();
						MoveRelative(30,30);
					}
					GraphText(valuestring,pg,pdf);
				}
			} 
			else 
			{
//				DrawGridRelative(-30,0,pg,pdf);
				if (!SubLogValue)
					DrawGridRelative((int)(-30 * ConvertToTwips),0,pg,pdf);
//				MoveRelative((int)(-(15 + 300 * size / (int)FontPitch) * ConvertToTwips), (int) (15 * ConvertToTwips));
				MoveRelative((int)(-(15 + 300 * size / (int)FontPitch) * ConvertToTwips), (int) (-15 * ConvertToTwips));
				if((AxisLabel[1])!=0) 
				{
					if (SubLogValue)
					{
						StringBuilder sb = new StringBuilder();
						sb.Append(SuperScript[0]);
						sb.Append(valuestring);
						sb.Append(SuperScript[1]);
						valuestring = sb.ToString();
						MoveRelative(90,-90); //jj
					}
					GraphText(valuestring,pg,pdf);
				}
			}
			RecallPosition();
		}
		int GenNumberString(double x) 
		{
			int power,size,sign;
			double mantissa;
			if(x==0.0) return(savenumber(x));
			if(x<0.0) 
			{
				x=-x;
				sign=1;
			} 
			else
				sign=0;
			mantissa=Math.Log10(x);
			power=0;
			while(mantissa < 0.999) 
			{
				power--;
				mantissa++;
			}
			while(mantissa >= 0.999) 
			{
				power++;
				mantissa--;
			}
			if(mantissa < 0)
				mantissa=0;
			if(power > -5 && power < 5)
				size=savenumber(x);
			else 
			{
				size = savenumber(Math.Pow(10.0,mantissa));
				size += addpower(power);
				if (valuestring.StartsWith("1x"))
				{
					size -= 2;
					valuestring = valuestring.Remove(0,2);
				}
			}
			if(sign != 0) 
			{
				valuestring = "-" + valuestring;
				size++;
			}
			return(size);
		}
		int savenumber(double x) 
		{
			//			valuestring = x.ToString("F");
			valuestring = x.ToString("G");
			return valuestring.Length;
		}
		int addpower(int i) 
		{
			int tlen;
			powerstring = string.Format("x10{0}{1}{2}",SuperScript[1],i.ToString(),SuperScript[2]);
			valuestring = valuestring + powerstring;
			tlen=SuperScript[0].Length + SuperScript[1].Length;
			return(powerstring.Length - tlen);
		}
		void DoAxisTitles(VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int len,frommargin;
//			int axismax,axismin;
			string str;
			//			string []newstr = {"",""};
			SavePosition();
			if((AxisTitles[X] != null) && (len=AxisTitles[X].Length) > 0 ) 
			{
				frommargin=(int)((0.5 * (printerunits[X])) - (0.5 * (len * CWIDEDOTS)));
//				MoveAbsolute(frommargin, -3 * CHIGHDOTS);
				MoveAbsolute(frommargin, (3 * CHIGHDOTS) + printerunits[Y]);
				PrintText(AxisTitles[X],pg,pdf);
				LinesUsed += (3 * CHIGHDOTS);
				//				Zfree(&AxisTitles[X]);
				AxisTitles[X] = null;
			}
			if((AxisTitles[Y] != null) && (len=AxisTitles[Y].Length) > 0)
			{
				if(YLandScape > 0)
				{
					int strIdx = 0;
					//					newstr[1] = null;
					MoveTo(YTitleOrigin);
					str = AxisTitles[Y];
					while(strIdx < str.Length)
					{
						//						newstr[0] = *str;
						//						PrintText( newstr );
						PrintText (str[strIdx].ToString(),pg,pdf);
						MoveRelative(0,-CHIGHDOTS);
						strIdx ++;
						//						str++;
					}
				} 
				else 
				{
//					MoveAbsolute(-3 * CWIDEDOTS, printerunits[Y] + CHIGHDOTS);
					MoveAbsolute(-3 * CWIDEDOTS, - CHIGHDOTS);
					PrintText(AxisTitles[Y],pg,pdf);
				}
				//				Zfree(&AxisTitles[Y]);
				AxisTitles[Y] = null;
			}
			RecallPosition();
		}
		void DoBoxes(VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int dx,dy;
			BoxList current;
			string str;
			//string nextstr;
			SavePosition();
			int BoxIdx = 0;
			SetPenDiameter(5);
			while(BoxIdx < AllBoxes.Count) 
			{
				current=(BoxList)AllBoxes[BoxIdx];
				MoveTo(current.BoxMinimum);
				dx=current.BoxMaximum.xyValue[X] - current.BoxMinimum.xyValue[X];
//				dy=current.BoxMinimum.xyValue[Y] - current.BoxMaximum.xyValue[Y];
				dy=current.BoxMaximum.xyValue[Y] - current.BoxMinimum.xyValue[Y];
				if( current.Shadow != 2 ) BoxRelative(dx,dy,CurPenWidth,pg,pdf);
				if( current.Shadow == 1 ) 
				{
					int savePenWidth = CurPenWidth;
					SavePosition();
					SetPenDiameter(10);
					MoveRelative((int)(10 * ConvertToTwips),-(dy+(int)(5*ConvertToTwips)));
					DrawRelative(dx,0,pg,pdf);
//					BlockRelative(dx,(int)(10 * ConvertToTwips),pg,pdf);
					MoveRelative(-(int)(3 * ConvertToTwips),-(int)(5*ConvertToTwips));
//					BlockRelative((int)(10 * ConvertToTwips),dy,pg,pdf);
					DrawRelative(0,dy,pg,pdf);
					CurPenWidth = savePenWidth;
//					MoveRelative(dx + (int)(10 * ConvertToTwips),0);
//					BlockRelative(-dx,(int)(10 * ConvertToTwips),pg,pdf);
//					BlockRelative((int)(-10 * ConvertToTwips),dy + (int)(10 * ConvertToTwips),pg,pdf);
					RecallPosition();
				}
//jj				MoveRelative((CWIDEDOTS * (3/2)),dy + (CHIGHDOTS * (5/4)));
				MoveRelative((CWIDEDOTS * (3/2)),-(CHIGHDOTS * (5/4)));
				str=current.BoxText;
				int stridx = 0;
				while(stridx < str.Length) 
				{
					string tstr = str;
					int idx;
					if ((idx = str.IndexOf("\n",stridx)) >= 0)
					{
						tstr = str.Substring(stridx,idx-stridx);
						stridx = idx + 1;
					}
					//					if( (nextstr=strchr(str,'\n')) != NULL ) *nextstr++=0;
					PrintText(tstr,pg,pdf);
					MoveRelative(0,-CHIGHDOTS);
					//					str=nextstr;
				}
				//				current=current->NextBox;
				BoxIdx++;
			}
			RecallPosition();
		}
		void DrawLines(VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int PlotsIdx = 0;
			PointList curpoint;
			LineList current;
			SavePosition();
			//	if( HPGL_Command[0] ) {
			//		if( UsePP ) {  /* PRINTAPLOT third party software */
			//			if( (PRT=fopen("HPGL.tmp","wb")) == NULL )
			//				{fprintf(stderr,"Could not open HPGL.tmp");PRT=stdprn;return;}
			//			HP_FudgeX=PRINTAPLOT_COMPENSATE;
			//			HP_FudgeY=PRINTAPLOT_COMPENSATE;
			//
			//		} else {	/* standard HPGL */
			//			PRT=stdprn;
			//			HP_FudgeX=HP3_HPGL_COMPENSATEX;
			//			HP_FudgeY=HP3_HPGL_COMPENSATEY;
			//		}
			//		HPGLMode=1;
			//		ANGLELIMIT=2.0;
			//		fprintf(PRT,HPGL_Command[0]); /* Initialization */
			//
			//	} else {		/* All other printers */
			//PRT=stdprn;
			//HPGLMode=0;
			SetPenDiameter(8);
			//	}
			/* begin plotting the graph lines, which may be straight or curved */
			while(PlotsIdx < AllPlots.Count) 
			{
				current=(LineList)AllPlots[PlotsIdx];
				int pntListIdx = 0;
				LineDiv=current.PlotDivisions;
				if( current.PlotType == STRAIGHT ) 
				{			/* straight plot */
					curpoint=(PointList)current.PlotPointsList[pntListIdx];
					MoveTo(curpoint.APoint);
					//			while( (curpoint=curpoint->NextPoint) != 0 )
					while( ++pntListIdx < current.PlotPointsList.Count )
					{
						curpoint = (PointList)current.PlotPointsList[pntListIdx];
						DrawLineTo(curpoint.APoint,pg,pdf);
					}
				} 
				else 
				{
					DrawCurve(current,pg,pdf);						/* curved plot */
				}
				/* HP printers seem to have a bug (or this code does) which */
				/* requires that each plot or curve be redrawn relative to the */
				/* origin, or plot offsetting occurs. */
				//		if(HPGLMode && !UsePP) {
				//			Graphics(0);
				//			RecallPosition();
				//			SavePosition();
				//			Graphics(1);
				//			fprintf(PRT,HPGL_Command[0]); /* Initialization */
				//		}
//				current=current.NextPlot;			/* point to next curve */
				PlotsIdx++;
//				if (PlotsIdx < AllPlots.Count)
//					current=(LineList)AllPlots[PlotsIdx];
			}  /* repeat for each plot (while) */
			//	if(HPGLMode) {
			//		fprintf(PRT,HPGL_Command[1]); 		/* Cleanup */
			//		if( UsePP ) { fclose(PRT); PRT=stdprn; }
			//	}
			RecallPosition();
		}
		point FindCenterOfArc( point StartPoint, double Slope1, point EndPoint, double Slope2) 
		{
			point center = new point();
			double s1,s2;
			int x1,y1,x2,y2;
			center.xyValue = new int[Dimensions];
			s1 = tan_deg(FixAngle(atan_deg(Slope1)));
			s2=tan_deg(FixAngle(atan_deg(Slope2)));
			x1=StartPoint.xyValue[X];
			y1=StartPoint.xyValue[Y];
			x2=EndPoint.xyValue[X];
			y2=EndPoint.xyValue[Y];
			center.xyValue[X]=(int)(((s2*s1)*(y2-y1)+(s1*x2)-(s2*x1))/(s1-s2));
			if(s1==0.0)
				center.xyValue[Y] = (int)(y2-((center.xyValue[X]-x2)/s2));
			else
				center.xyValue[Y] = (int)(y1-((center.xyValue[X]-x1)/s1));
			return(center);
		}
		point FindModifiedCenter(double rprime,point PtOnArc, double ang) 
		{
			point newcenter = new point();
			newcenter.xyValue = new int[Dimensions];
			newcenter.xyValue[X] = (int)(PtOnArc.xyValue[X] - rprime * cos_deg(ang));
			newcenter.xyValue[Y] = (int)(PtOnArc.xyValue[Y] - rprime * sin_deg(ang));
			return(newcenter);
		}
		int AddMidPoint(ArrayList ptLstAry, int pt1Idx,int pt2Idx) 
		{
			PointList midpt;
			PointList pt1, pt2;
			point pt;
			double so;
			int x1,y1,x2,y2;
			pt1 = (PointList)ptLstAry[pt1Idx];
			pt2 = (PointList)ptLstAry[pt2Idx];
			x1=pt1.APoint.xyValue[X];
			y1=pt1.APoint.xyValue[Y];
			x2=pt2.APoint.xyValue[X];
			y2=pt2.APoint.xyValue[Y];
			midpt = new PointList();
			pt=new point();
			pt.xyValue = new int[Dimensions];
			so=FindSlope(pt1.APoint,pt2.APoint);
			midpt.slope = (4.0 * so - pt1.slope - pt2.slope)/2.0;
			pt.xyValue[X]=x1+(x2-x1)/2;
			pt.xyValue[Y]=y1+(y2-y1)/2;
			midpt.APoint=pt;
			ptLstAry.Insert(pt1Idx+1,midpt);
			//midpt->NextPoint=pt2;
			return(pt1Idx+1);
		}
		double FindTheta(point Endpoint, point Centerpoint) 
		{
			double dy,dx,result;
			dx = Endpoint.xyValue[X] - Centerpoint.xyValue[X];
			dy = Endpoint.xyValue[Y] - Centerpoint.xyValue[Y];
			result=90.0 - atan_deg((dy/dx));
			if( dx<0 ) result+=180.0;
			return(result);
		}
		double FindRadius(point Endpoint, point Centerpoint) 
		{
			double dy,dx,r;
//			double dy,dx,ddx,ddy,r;
			dx = Centerpoint.xyValue[X] - Endpoint.xyValue[X];
			dy = Centerpoint.xyValue[Y] - Endpoint.xyValue[Y];
			r = Math.Sqrt(((dx*dx)+(dy*dy)));
			return(r);
		}
		void DrawCurve(LineList linestart, VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			//PointList curpoint,pt2;
			int pltptListIdx = -1;
//			int debug = 1; //jj
			//curpoint=(PointList)linestart.PlotPointsList[pltptListIdx];
			while( ++pltptListIdx < linestart.PlotPointsList.Count -1 ) 
			{
				DoSubArcs(linestart.PlotPointsList,pltptListIdx,pg,pdf);
//				pltptListIdx = linestart.PlotPointsList.Count * debug; // jj
//				debug++; //jj
				//DoSubArcs(curpoint);
				//curpoint=(PointList)linestart.PlotPointsList[pltptListIdx];
			}
		}
		double GetAngle(double s1) 
		{
			double t1;
			t1=atan_deg(s1);
			return(t1);
		}
		double GetAngleBetweenPoints(point pt1, point pt2) 
		{
			double retval;
			retval=GetAngle(FindSlope(pt1,pt2));
			if(pt2.xyValue[X] < pt1.xyValue[X]) 
			{
				if(retval<0)
					retval+=180;
				else
					retval-=180;
			}
			return(retval);
		}
		double SpecialGetAngleBetweenPoints(point pt1,point pt2, double s1) 
		{
			double retval;
			if(s1==0.0) 
			{
				if(pt1.xyValue[Y] < pt2.xyValue[Y])
					s1=Convert.ToDouble("1.E99");
				else
					s1=Convert.ToDouble("-1.E99");
			} 
			else
				s1 = -1/s1;
			retval=GetAngle(s1);
			if(pt2.xyValue[X] < pt1.xyValue[X]) 
			{
				if(retval<0)
					retval+=180;
				else
					retval-=180;
			}
			return(retval);
		}
		double GetArcAngle(double s1, double s2) 
		{
			double result,t1,t2;
			t1=GetAngle(s1);
			t2=GetAngle(s2);
			result=t1-t2;
			return(result);
		}
		void DoSubArcs(ArrayList ptListAry,int aryIdx, VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			bool debug = false; //jsj
			int x,y,x1,x2,y1,y2;
			PointList pt1 = (PointList)ptListAry[aryIdx];
			PointList pt2 = (PointList)ptListAry[aryIdx+1];
#if DEBUG
			Console.WriteLine("pt1={0},{1},{2}",pt1.APoint.xyValue[0],pt1.APoint.xyValue[1],pt1.slope);
			Console.WriteLine("pt2={0},{1},{2}",pt2.APoint.xyValue[0],pt2.APoint.xyValue[1],pt2.slope);
#endif
			double theta,delta1,delta2,r1,r2,t1,t2,theta1,theta2,thetaa,t3,t4;
			double c1,c2,s1,s2;
//			point cp,cp1,cp2;
			point cp1,cp2;
			t3=FixAngle(GetAngle(pt1.slope));
			t4=FixAngle(GetAngle(pt2.slope));
			thetaa=GetAngleBetweenPoints(pt1.APoint,pt2.APoint);
			if((t3-thetaa)*(t4-thetaa) >= 0.0) 
			{
				double tprime;
				tprime=FixAngle(thetaa);
				if (Math.Abs(tprime-t3) < ANGLELIMIT ) 
				{
					MoveTo(pt1.APoint);
					DrawTo(pt2.APoint,pg,pdf);
					return;
				} 
				else 
				{
					pt2=(PointList)ptListAry[AddMidPoint(ptListAry,aryIdx,aryIdx+1)];
					t4=FixAngle(GetAngle(pt2.slope));
					thetaa=GetAngleBetweenPoints(pt1.APoint,pt2.APoint);
				}
			}
//			if (debug) //jsj
//				return;
			if(thetaa < t3)
				t1=t3+90;
			else
				t1=t3-90;
			if(thetaa > t4)
				t2=t4+90;
			else
				t2=t4-90;
			theta=t2-t1;
			theta1=FixAngle(thetaa-t3);
			theta2=theta-theta1;
			if(Math.Abs(theta1) < Math.Abs(theta2)) 
			{
				if(Math.Abs(theta1) < ANGLELIMIT ) 
				{
					theta1=0;
					theta2=theta;
				}
			} 
			else if(Math.Abs(theta2) < Math.Abs(theta1)) 
			{
				if(Math.Abs(theta2) < ANGLELIMIT ) 
				{
					theta2=0;
					theta1=theta;
				}
			}
			x1=pt1.APoint.xyValue[X];
			y1=pt1.APoint.xyValue[Y];
			x2=pt2.APoint.xyValue[X];
			y2=pt2.APoint.xyValue[Y];
			s1=sin_deg(t1+180);
			s2=sin_deg(t2+180);
			c1=cos_deg(t1+180);
			c2=cos_deg(t2+180);
			if(s1 == 0.0) 
			{
				r2=(x1-x2)/s2;
				r1=(y2+r2*c2-y1)/c1;
			} 
			else if(s2 == 0.0) 
			{
				r1=(x2-x1)/s1;
				r2=(y1+r1*c1-y2)/c2;
			} 
			else if(c1 == 0.0) 
			{
				r2=(y1-y2)/c2;
				r1=(x2+r2*s2-x1)/s1;
			} 
			else if(c2 == 0.0) 
			{
				r1=(y2-y1)/c1;
				r2=(x1+r1*s1-x2)/s2;
			} 
			else 
			{
				r2=(((x2-x1)/c1) - ((y2-y1)/s1)) / (s2/s1 - c2/c1);
				r1=(y2-y1+r2*s2)/s1;
			}
			MoveTo(pt1.APoint);
			if (debug) //jsj
			{
				DrawTo(pt2.APoint,pg,pdf);
				return;
			}
			if(Math.Abs(theta1)>ANGLELIMIT && Math.Abs(theta2)>ANGLELIMIT) 
			{
				delta1=(r2-r1)/(
					(1.0-cos_deg(theta1)) + 
					(1.0-cos_deg(theta2))*sin_deg(theta1)/sin_deg(theta2));
				r1=Math.Floor(0.5+r1+delta1);
				cp1=FindModifiedCenter(r1,pt1.APoint,t1);
//				cp1 = FindCenterOfArc(pt1.APoint,pt1.slope,pt2.APoint,pt2.slope); // jj
				x=(int)(cp1.xyValue[X]+r1*cos_deg(t1+theta1));
				y=(int)(cp1.xyValue[Y]+r1*sin_deg(t1+theta1));
				delta2=delta1*sin_deg(theta1)/sin_deg(theta2);
//				x = pt2.APoint.xyValue[X]; //jj
//				y = pt2.APoint.xyValue[Y]; //jj
				r2=Math.Floor(0.5+r2-delta2);
				cp2=FindModifiedCenter(r2,pt2.APoint,t2);
#if DEBUG
				Console.WriteLine("DrawArc1");
#endif
				DrawArc(r1,t1,t1+theta1,cp1,x,y,pg,pdf);
				MoveTo(pt2.APoint);
				if(r2 > 15000)
				{
#if DEBUG
					Console.WriteLine("DrawAbs1 {0},{1}",x,y);
#endif
					DrawAbsolute(x,y,pg,pdf);
				}
				else
				{
#if DEBUG
					Console.WriteLine("DrawArc2");
#endif
					DrawArc(r2,t2,t2-theta2,cp2,x,y,pg,pdf);
				}
//					//		Zfree(&cp1);
//					//		Zfree(&cp2);
			} 
			else if(Math.Abs(theta1)>ANGLELIMIT) 
			{
				delta1=(r2-r1)/(1.0-cos_deg(theta1));
				r1=Math.Floor(0.5+r1+delta1);
				cp1=FindModifiedCenter(r1,pt1.APoint,t1);
//				cp1=FindCenterOfArc(pt1.APoint,pt1.slope,pt2.APoint,pt2.slope); //jj
				x=(int)(cp1.xyValue[X]+r1*cos_deg(t1+theta1));
				y=(int)(cp1.xyValue[Y]+r1*sin_deg(t1+theta1));
				if(r1 > 15000)
				{
#if DEBUG
					Console.WriteLine("DrawAbs2");
#endif
					DrawAbsolute(x,y,pg,pdf);
				}
				else
				{
#if DEBUG
					Console.WriteLine("DrawArc3");
#endif
					DrawArc(r1,t1,t1+theta1,cp1,x,y,pg,pdf);
				}
				MoveAbsolute(x,y);
#if DEBUG
				Console.WriteLine("DrawTo1");
#endif
				DrawTo(pt2.APoint,pg,pdf);
//			x = pt2.APoint.xyValue[X]; //jj
//			y = pt2.APoint.xyValue[Y]; //jj
#if DEBUG
				Console.WriteLine("DrawArc4");
#endif
				DrawArc(r1,t1,t1+theta1,cp1,x,y,pg,pdf);
				//		Zfree(&cp1);
			} 
			else if(Math.Abs(theta2)>ANGLELIMIT) 
			{
				delta2=(r2-r1)/(1.0-cos_deg(theta2));
				r2=Math.Floor(0.5+r2-delta2);
				cp2=FindModifiedCenter(r2,pt2.APoint,t2);
//				cp2=FindCenterOfArc(pt1.APoint,pt1.slope,pt2.APoint,pt2.slope); //jj
				x=(int)(cp2.xyValue[X]+r2*cos_deg(t2-theta2));
				y=(int)(cp2.xyValue[Y]+r2*sin_deg(t2-theta2));
#if DEBUG
				Console.WriteLine("DrawAbs3");
#endif
				DrawAbsolute(x,y,pg,pdf);
				MoveTo(pt2.APoint);
				if(r2 > 15000)
				{
#if DEBUG
					Console.WriteLine("DrawAbs4");
#endif
					DrawAbsolute(x,y,pg,pdf);
				}
				else
				{
#if DEBUG
					Console.WriteLine("DrawArc5");
#endif
					DrawArc(r2,t2,t2-theta2,cp2,x,y,pg,pdf);
				}
//				x = pt2.APoint.xyValue[X]; //jj
//				y = pt2.APoint.xyValue[Y]; //jj
#if DEBUG
				Console.WriteLine("DrawArc6");
#endif
				DrawArc(r2,t2,t2-theta2,cp2,x,y,pg,pdf);
			//		Zfree(&cp2);
		} 
			else 
			{
#if DEBUG
				Console.WriteLine("DrawTo2");
#endif
				DrawTo(pt2.APoint,pg,pdf);
				pt2.slope=FindSlope(pt1.APoint,pt2.APoint);
			}
			return;
		}
		void Graphics(int flag) 
		{
			//			if(graph_GraphicsStr[flag])
			//				fprintf(stdprn,"%s",graph_GraphicsStr[flag]);
		}
		void SetPenDiameter(int pd) 
		{
			if ((pd * ConvertToTwips) != CurPenWidth) 
			{
				CurPenWidth= (int)(pd * ConvertToTwips);
			}
		}
		void PrintStackError(string relation, int limit) 
		{
			MessageBox.Show(String.Format("Position Stack Pointer {0} {1}",relation,limit.ToString()),"Print Stack Error");
			//			printf("Position Stack Pointer %s %d",relation,limit);
			//			spc_exit(3);
		}
		void SavePosition() 
		{
			if(stack >= MAX_XY_STACK) PrintStackError(">=",MAX_XY_STACK);
			SavedX[stack]=Position[X];
			SavedY[stack++]=Position[Y];
		}
		void RecallPosition() 
		{
			if(stack <= 0) PrintStackError(" <",0);
			Position[X]=SavedX[--stack];
			Position[Y]=SavedY[stack];
		}
		void MoveTo(point pnt) 
		{
			MoveAbsolute(pnt.xyValue[X],pnt.xyValue[Y]);
		}
		void DrawTo(point pnt, VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			DrawAbsolute(pnt.xyValue[X],pnt.xyValue[Y],pg,pdf);
		}
		void MoveAbsolute(int ptx, int pty) 
		{
			int x,y;
			x=ptx-Position[X];
			y=Position[Y]-pty;
			MoveRelative(x,y);
		}
		void DrawAbsolute(int ptx,int pty, VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int x,y;
			x=ptx-Position[X];
			y=Position[Y]-pty;
			DrawRelative(x,y,pg,pdf);
		}
		void DrawGridAbsolute(int ptx,int pty,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int x,y;
			x=ptx-Position[X];
			y=Position[Y]-pty;
			DrawGridRelative(x,y,pg,pdf);
		}
		void relval(string ptr,int i) 
		{
			ptr = string.Format("+{0}",i.ToString());
		}
		long DotsToPlotterUnitsX(int x) 
		{
			long retval;
			retval = (long)((1.0*x*HP_FudgeX) / 300.0 + .5);
			return( retval );
		}
		long DotsToPlotterUnitsY(int y) 
		{
			long retval;
			retval = (long)((1.0*y*HP_FudgeY) / 300.0 + .5);
			return( retval );
		}
		void MoveRelative(int x,int y) 
		{
			long xl,yl;
			Position[X]+=x;
			Position[Y]-=y;
		}
		void DrawRelative(int x,int y,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
//			long xl,yl;
			if(Visible == 0)
				MoveRelative(x,y);
			else 
			{
				int toX, toY;
				toX = Position[X]+x;
				toY = Position[Y]-y;
//				toY = Position[Y]+y;
				VG_Line RelLine = new VG_Line(Position[X],Position[Y],toX,toY,CurPenWidth,pg);
//				VG_Line RelLine = new VG_Line(Position[X],Position[Y],x,-y,CurPenWidth,pg);
				Position[X]+=x;
				Position[Y]-=y;
//				Position[Y]+=y;
				RelLine.ToPdf(pdf);
//				if(HPGLMode != 0) 
//				{
//					xl=DotsToPlotterUnitsX(x);
//					yl=DotsToPlotterUnitsY(y);
//					// !!! OUTPUT DRAW RELATIVE COMMAND
//					MessageBox.Show("!!! OUTPUT DRAW RELATIVE COMMAND 1","DrawRelative()");
//					//					fprintf(PRT,HPGL_Command[3],-xl,yl);	/*	*/
//				} 
//				else
//					MessageBox.Show("!!! OUTPUT DRAW RELATIVE COMMAND 2","DrawRelative()");
//				// !!! OUTPUT DRAW RELATIVE COMMAND
//				//					fprintf(PRT,graph_DrawRelative,x,y);
			}
		}
		void DrawGridRelative(int x, int y,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			if(Visible == 0)
				MoveRelative(x,y);
			else 
			{
/***
				if(StupidHP == 2) 
				{			//StupidHP==5 is RTF driver
					if(x==0) BlockRelative(PrevPen,y);
					else if(y==0) BlockRelative(x,PrevPen);
					MoveRelative(x,y);
				} 
				else
***/
					DrawRelative(x,y,pg,pdf);
			}
		}
		void MoveForArc(point pnt) 
		{
			Position[X]+=pnt.xyValue[X];
			Position[Y]-=pnt.xyValue[Y];
		}
		void DrawArc(double radius,double Sangle,double Eangle,point cp,int x, int y, VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
#if DEBUG
			Console.WriteLine("r={0} sAngle={1} eAngle={2} cp={3},{4} x={5} y={6}",radius,Sangle,Eangle,cp.xyValue[0],cp.xyValue[1],x,y);
#endif
			//	double inc=2000.,r1;
			int dx,dy;
			long radchk;
			radchk=(long)radius;
//			if(radchk > 15000L) 
			if(radchk > 72000L) 
			{
				DrawAbsolute(x,y,pg,pdf);
				return;
			}
			dx = x - cp.xyValue[X]; //jj
//			dx=cp.xyValue[X]-Position[X];
//			dy=cp.xyValue[Y]-Position[Y];
			dy=Math.Abs(cp.xyValue[Y]-Position[Y]); //jj
			//r1=radius;
			/*
			** for the HP series of printers we recalculate the the x and y positions
			** because of a rounding error that will propagate every time
			** an arc segment is drawn.  This has the nasty effect of incorrectly
			** drawing curves.
			*/
//			if( HPGLMode != 0 ) 
//			{
//				Position[X] += (int)((radius*cos_deg(Eangle) - radius*cos_deg(Sangle)));
//				Position[Y] -= (int)((radius*sin_deg(Sangle) - radius*sin_deg(Eangle)));
//			}
//			Sangle=90-Sangle;
//			Eangle=90-Eangle;
//			Sangle=180-Sangle; //jj
//			Eangle=180-Eangle; //jj
//			if(HPGLMode != 0) 
//			{
//				long xl,yl;
//				xl=DotsToPlotterUnitsX(dx);
//				yl=DotsToPlotterUnitsY(dy);
				//		fprintf(PRT,HPGL_Command[4],-xl,-yl,(int)(Sangle-Eangle));
//			VG_Arc arc = new VG_Arc(cp.xyValue[X]-dx,cp.xyValue[Y]+dy,dx*2,dy*2,(float)Sangle,(float)(Sangle - Eangle),5,pg);
//			VG_Arc arc = new VG_Arc(cp.xyValue[X]-dx,cp.xyValue[Y]-dy,dx*2,dy*2,(float)Sangle,(float)(Sangle - Eangle),CurPenWidth,pg);
			radius=radius;
			float x1=cp.xyValue[X]-(float)radius;
			float y1=cp.xyValue[Y]-(float)radius;
			float w1=(float) radius * 2;
			VG_Arc arc = new VG_Arc(x1,y1,w1,w1,(float)Sangle,(float)(Eangle - Sangle),CurPenWidth,pg);
			//VG_Arc arc = new VG_Arc(0,0,5000,5000,(float)Sangle,(float)(Eangle - Sangle),CurPenWidth,pg);
#if DEBUG
			Console.WriteLine("arc {0},{1},{2},{3},{4},{5}",x1,y1,w1,w1,(float)Sangle,(float)(Eangle - Sangle));
#endif
			arc.ToPdf(pdf);
//				MessageBox.Show("!!! HPGL_COMMAND[4]","DrawArc()");
//			} 
//			else 
//			{
//				SavePosition();
//				if(dx>0)
//					MessageBox.Show("!!! graph_MoveRelativeXPos","DrawArc()");
//					//			fprintf(PRT,graph_MoveRelativeXPos,dx);
//				else
//					MessageBox.Show("!!! graph_MoveRelativeXNeg","DrawArc()");
//				//			fprintf(PRT,graph_MoveRelativeXNeg,-dx);
//				if(dy>0)
//					MessageBox.Show("!!! graph_MoveRelativeYPos","DrawArc()");
//					//			fprintf(PRT,graph_MoveRelativeYPos,dy);
//				else
//					MessageBox.Show("!!! graph_MoveRelativeYNeg","DrawArc()");
//				//			fprintf(PRT,graph_MoveRelativeYNeg,-dy);
//				MessageBox.Show("!!! graph_ArcFunction1","DrawArc()");
//				//		fprintf(PRT,graph_ArcFunction1,
//				//			radius-4,(radius+4),FMin(Sangle,Eangle),FMax(Sangle,Eangle));
//				RecallPosition();
//			}
		}
		void DrawGridLine(int flag,int val,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			ActiveBoxList curbox;
			int v1,v2;
			int BoxesIdx = 0;
			int BoxPtrIdx = 0;
//			FindBoxesinArea(val, !flag);
			FindBoxesinArea(val,(flag==0)?1:0);
			v1=Position[flag];
			if (AllActiveBoxes.Count > 0)
			{
				curbox=(ActiveBoxList)AllActiveBoxes[BoxesIdx];
				while(BoxesIdx < AllActiveBoxes.Count) 
				{
					int my_x, my_y;
					v2=((BoxList)curbox.BoxPtr[BoxPtrIdx]).BoxMinimum.xyValue[flag];
					my_x = (flag==X)? ( (v2 < printerunits[flag])? v2 : printerunits[flag] )
						: val;
					my_y = (flag==Y) ? 
						( (v2 < printerunits[flag]) ? v2 : printerunits[flag] )
						: val;
					DrawGridAbsolute(my_x,my_y,pg,pdf);
					v1=((BoxList)curbox.BoxPtr[BoxPtrIdx]).BoxMaximum.xyValue[flag];
					while((BoxesIdx < AllActiveBoxes.Count) && (((BoxList)curbox.BoxPtr[BoxPtrIdx]).BoxMinimum.xyValue[flag] < v1))
					{
						v1=(((BoxList)curbox.BoxPtr[BoxPtrIdx]).BoxMaximum.xyValue[flag]);
						BoxesIdx++;
						if (BoxesIdx < AllActiveBoxes.Count)
							curbox=(ActiveBoxList)AllActiveBoxes[BoxesIdx];
					}
					MoveAbsolute((flag==X?v1:val),(flag==Y?v1:val));
				}
			}
			v2=printerunits[flag];
			if (v1 < v2) DrawGridAbsolute((flag==X?v2:val),(flag==Y?v2:val),pg,pdf);
			FreeActiveBoxes();
		}
		void LogScale(int flag) 
		{
			double newminimum, newmaximum, maxlimit=maximum[flag]*.9;
//			int i;
			newminimum=1.0;
			while(newminimum < minimum[flag])newminimum *= 10.0;
			while(newminimum > minimum[flag])newminimum /= 10.0;
			newmaximum=10.0 * newminimum;
			cycles[flag]=1;
			while( newmaximum < maxlimit ) 
			{
				newmaximum *= 10.0;
				cycles[flag]++;
			}
			onecycle[flag]=printerunits[flag]/cycles[flag];
			minimum[flag]=newminimum;
			maximum[flag]=newmaximum;
		}
		void LinearScale(int flag) 
		{
			double mantissa,nx;
			double newminimum, newmaximum;
			int power=0;
			if( spcminor[flag] == 0 )
				minor[flag]=10;
			else
				minor[flag]=spcminor[flag];
			if( delta[flag] == 0 ) 
			{
				delta[flag]=maximum[flag]-minimum[flag];
				mantissa=Math.Log10(delta[flag]);
				while(mantissa < 1.2) 
				{
					mantissa++;
					power--;
				}
				while(mantissa > 1.2) 
				{
					mantissa--;
					power++;
				}
				if(mantissa < 0)mantissa=0;
				nx=Math.Pow(10.0,mantissa);
				if(nx > 5.0) 
				{
					delta[flag]=1.0;
				} 
				else if(nx > 3.001) 
				{		// allow for roundoff
					delta[flag]=0.5;
				} 
				else if(nx > 2.001) 
				{		// allow for roundoff
					delta[flag]=0.25;
				} 
				else 
				{
					delta[flag]=0.2;
					if(spcminor[flag] == 0) minor[flag]=8;
				}
				while(power>0) 
				{
					power--;
					delta[flag] *= 10.0;
				}
				while(power<0) 
				{
					power++;
					delta[flag] /= 10.0;
				}
			}
			if(GridOnFlag==0 || GridOnFlag==1)
				minor[flag]=1;
			else if(GridOnFlag==2)
				minor[flag] /= 2;
			newminimum=((int)(0.01+minimum[flag]/delta[flag])) * delta[flag];
			if(newminimum > minimum[flag]+(delta[flag] * 0.001))
				newminimum-=delta[flag];
			newmaximum=((int)(maximum[flag]/delta[flag])) * delta[flag];
			if(newmaximum < maximum[flag]-(delta[flag] * 0.001))
				newmaximum+=delta[flag];
			minimum[flag]=newminimum;
			maximum[flag]=newmaximum;
		}
		void err_exit(string msg,string msg2) 
		{
			MessageBox.Show(msg + "\n" + msg2 + "\n\n This p=Process Will Terminate","\n## ERROR ## - ");
			Environment.Exit(255);
		}
		void FindBoxesinArea(int ptval,int flag) 
		{
			BoxList cptr;
			int BoxesIdx =0;
			while (BoxesIdx < AllBoxes.Count) 
			{
				cptr= (BoxList)AllBoxes[BoxesIdx];
				if ( cptr.BoxMinimum.xyValue[flag] <= ptval &&
					cptr.BoxMaximum.xyValue[flag] >= ptval )
					AddBoxToActiveList(cptr);
				BoxesIdx++;
			}
		}
		void AddBoxToActiveList(BoxList bptr) 
		{
			ActiveBoxList NewActiveBox = new ActiveBoxList();
			int prevboxIdx = -1;
			ActiveBoxList cbox;
			NewActiveBox.BoxPtr = new ArrayList();
			NewActiveBox.BoxPtr.Add(bptr);
			int AllActBoxIdx = 0;
			if( AllActiveBoxes.Count > 0 ) 
			{
				cbox = (ActiveBoxList)AllActiveBoxes[AllActBoxIdx];
				prevboxIdx = 0;
				while ( AllActBoxIdx < AllActiveBoxes.Count && 
					(cbox.BoxPtr.Count > 0 && (bptr.BoxMinimum.xyValue[DrawDirection] > 
					((BoxList)cbox.BoxPtr[AllActBoxIdx]).BoxMinimum.xyValue[DrawDirection])) ) 
				{
					prevboxIdx=AllActBoxIdx;
					AllActBoxIdx++;
					if (AllActBoxIdx < AllActiveBoxes.Count)
						cbox=(ActiveBoxList)AllActiveBoxes[AllActBoxIdx];
					else
						prevboxIdx = -1; // will append to end of list
				}
				if (AllActBoxIdx < AllActiveBoxes.Count)
					AllActiveBoxes.Insert(AllActBoxIdx,NewActiveBox);
			}
			if(prevboxIdx == -1)
				AllActiveBoxes.Add(NewActiveBox);
		}
		void FreeActiveBoxes() 
		{
			AllActiveBoxes.Clear();
		}
		void GenGrid(int flag,int ss,int ee,int dd,int w,int lw,int goffset,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			int val,wn,valn;
			double p2;
//			double p2,size;
			int n,dn,MinorGrid=0;
			if((GridOnFlag * lw)<=1)return;
			if (ee/ss == 10) MinorGrid=2;
			n=ss;
			p2=n;
//			w = (int)(Math.Log10(ee/p2) / w); //jj
			w = (int)(w / Math.Log10(ee/p2)); //jj
//			w /= (int)Math.Log10(ee/p2);
			val=(int)(Math.Log10(p2/ss)*w + goffset);
			MoveAbsolute((flag==X?val:0),(flag==Y?val:0));
			DrawGridLine((flag==0)?1:0,val,pg,pdf);
			if((GridOnFlag * lw) == 2)return;
			SetPenDiameter(lw);
			while(n < ee) 
			{
				n+=dd;
				p2=n;
				valn=(int)(Math.Log10(p2/ss)*w + goffset);
				wn=valn-val;
				if(wn > DPI/20 && lw > 1) 
				{
					if(wn > DPI*2/5)dn=dd/10;
					else if(wn > DPI/5) dn=dd/5;
					else dn=dd/2;
					GenGrid(flag,n-dd,n,dn,wn,lw-1,val,pg,pdf);
					wn=0;
				}
				val=valn;
				if (flag ==Y)
					val = printerunits[Y] - val; //jj
				MoveAbsolute((flag==X?val:0),(flag==Y?val:0));
				if((MinorGrid != 0) && (MinorGrid < 10)) 
				{
//					SavePosition();
//					double SaveFontPitch = FontPitch; //jj
					//					fprintf(PRT,graph_MinorMark[flag],MinorGrid++);
//					if (flag == 0)
//						MoveRelative((int)(15 * ConvertToTwips),(int)(60 * ConvertToTwips)); // these numbers are in dots
//					else
//						MoveRelative((int)(-30 * ConvertToTwips),(int)(9 * ConvertToTwips));
//					FontPitch = 5.0; //jj
//					if (flag == 0)
//						MoveRelative(0,160); // these numbers are in dots
////						MoveRelative(0,40); // these numbers are in dots
//					else
//						MoveRelative(-30,0);
//					SavePosition();
//					if (flag == 0)
//						MoveRelative(30,0); // these numbers are in dots
//					else
//						MoveRelative(0,0);
					WriteValue(flag,MinorGrid++,true,pg,pdf); //these numbers are in dots
					//					FontPitch = SaveFontPitch; //jj
//					RecallPosition();
				}
				DrawGridLine((flag==0)?1:0,val,pg,pdf);
			}
		}
		void PrintText(string txt,VG.Page pg, C1.C1Pdf.C1PdfDocument pdf) 
		{
			StringBuilder tstr = new StringBuilder(txt);
//			int ptr,sptr;
			int ptr;
			SavePosition();	/* 'cause TEXT...,E screws up position! */
			ptr=0;
//			sptr=0;
			while (ptr < tstr.Length)
//			while(ptr < txt.Length) 
			{
				if ("`øòó".IndexOf(tstr[ptr]) >= 0)
//				if("`øòó".IndexOf(txt[ptr]) >= 0 ) 
				{
					string SpecialChar="";
//					int len = 0;
					switch ( (byte)tstr[ptr])
//					switch ( (byte)txt[ptr] ) 
					{
						case 0x60 :					/* backquote */
						case 0xF8 :	SpecialChar = "\u00B0";	/* degree symbol */
							break;
						case 0xF2 :	SpecialChar= "\u2265";	/* greaterthanequal */
							break;
						case 0xF3 :	SpecialChar= "\u2264";	/* lessthanequal */
							break;
					}
					tstr.Remove(ptr,1);
					tstr.Insert(ptr,SpecialChar);
					ptr++;
//					len = txt.Substring(sptr,ptr-sptr).Length;
//					GraphText( txt.Substring(sptr,ptr-sptr),pg,pdf);
//					MoveRelative(len * CWIDEDOTS,0);
//					sptr = ++ptr;
//					GraphText(SpecialChar,pg,pdf);
//					MoveRelative(CWIDEDOTS,0);
//					//!!! ADD CALLS TO OUTPUT THESE STRINGS
//					MessageBox.Show("ADD CALLS TO OUTPUT SPECIAL CHARS","PrintText()");
//					//					fprintf(PRT,graph_PrntStr[2]);
//					//					fprintf(PRT,"%c",GraphicChar&0x7F);
//					//					fprintf(PRT,graph_PrntStr[3]);
				} 
				else 
				{
					ptr++;
				}
			}
			GraphText(tstr.ToString(),pg,pdf);
//			if( ptr > sptr ) GraphText( txt.Substring(sptr,ptr-sptr),pg,pdf);
			RecallPosition();
		}
		void FreeBoxList() 
		{
			AllBoxes.Clear();
		}
		void FreeLineList() 
		{
			AllPlots.Clear();
		}
//		void FreePointList(PointList ptr) 
//		{
//			PointListArray.Clear();
//			// struct PointList *bptr,*nptr;
//			//   bptr=ptr;
//			//   while(bptr) 
//			// {
//			//   nptr=bptr->NextPoint;
//			//   Zfree(&bptr->APoint);
//			//   Zfree(&bptr);
//			//   bptr=nptr;
//			// }
//		}
		void Init_Graphic_Vars() 
		{
			int i;
			SavedX = new int[MAX_XY_STACK];
			SavedY = new int[MAX_XY_STACK];
			LinesUsed=0;		/* Number lines used by graph, in dots */
			Visible=1;
			ShadowFlag = 0;
			//			_setmem(valuestring,100,'\0');
			//			_setmem(powerstring,100,'\0');
			CurPenWidth = 0;
			DrawDirection = -1;
			AxisTitles[X] = null;
			AxisTitles[Y] = null;
			AxisLabel[0] = 1;
			AxisLabel[1] = 1;
			EndFlag=0;
			for (i=0;i -1)
				{
					// print text up to the superscript
					tstr = txt.Substring(sidx,tidx-sidx);
					drawText = new VG_Text(Xpos,Ypos,(int)FontPitch,tstr,"Letter Gothic","","","",pg);
					drawText.ToPdf(pdf);
					Xpos+= (CWIDEDOTS * tstr.Length);
					tidx+= SuperScript[0].Length;
					idx = tidx;
					sidx = idx;
					tidx = txt.IndexOf(SuperScript[1],idx);
					if (tidx > 0)
					{
						// switch font pitch, move up some, and print the superscript text
						tstr = txt.Substring(sidx,tidx - sidx);
//						Xpos+= (CWIDEDOTS * tstr.Length);
						Ypos -= (CHIGHDOTS / 2); // move up half a char heigth
						drawText = new VG_Text(Xpos,Ypos,(int)(FontPitch/2),tstr,"Letter Gothic","","","",pg);
						drawText.ToPdf(pdf);
						Ypos += (CHIGHDOTS / 2); // move back down
						Xpos += ((CWIDEDOTS/2) * tstr.Length); // positon half the width of the string
						tidx += SuperScript[1].Length;
						idx = tidx;
						sidx = idx;
						continue; // go back to beginning of while loop
					}
				}
				else if ((tidx = txt.IndexOf(SubScript[0],idx)) > -1)
				{
					// print text up to the superscript
					tstr = txt.Substring(sidx,tidx-sidx);
					drawText = new VG_Text(Xpos,Ypos,(int)FontPitch,tstr,"Letter Gothic","","","",pg);
					drawText.ToPdf(pdf);
					Xpos+= (CWIDEDOTS * tstr.Length);
					tidx+= SubScript[0].Length;
					idx=tidx;
					sidx = idx;
					tidx = txt.IndexOf(SubScript[1],idx);
					if (tidx > 0)
					{
						// switch font pitch, move up some, and print the superscript text
						tstr = txt.Substring(sidx,tidx - sidx);
//						Xpos+= (CWIDEDOTS * tstr.Length);
//						Ypos += (CHIGHDOTS / 2); // move down half a char heigth
						drawText = new VG_Text(Xpos,Ypos,(int)(FontPitch/2),tstr,"Letter Gothic","","","",pg);
						drawText.ToPdf(pdf);
//						Ypos -= (CHIGHDOTS / 2); // move back up
						Xpos += ((CWIDEDOTS/2) * tstr.Length); // positon half the width of the string
						tidx += SubScript[1].Length;
						idx = tidx;
						sidx = idx;
						continue; // go back to beginning of while loop
					}
				}
				else
				{
					idx++;
				}
			} // end while
			if (sidx < txt.Length)
			{
				tstr = txt.Substring(sidx);
				drawText = new VG_Text(Xpos,Ypos,(int)FontPitch,tstr,"Letter Gothic","","","",pg);
				drawText.ToPdf(pdf);
			}
		}
//		public XYPlot()
//		{
//			//
//			// TODO: Add constructor logic here
//			//
//			AxisLabel[0] = 1;
//			AxisLabel[1] = 1;
//		}
		public XYPlot(string fname, string PdfFileName)
		{
			char Command, PrevCommand = ' ';
			Init_Graphic_Vars();
			LoadBuff(fname);
			FixBuffIfNeeded();
			GetScaleInfo();
			C1.C1Pdf.C1PdfDocument c1pdf = new C1.C1Pdf.C1PdfDocument();
			c1pdf.FontType = C1.C1Pdf.FontTypeEnum.Embedded; // embed fonts
	
			VG.Page pg = new Page(true,(float)(1440),(float)(1440));
			while ((Command = char.ToUpper(getchr())) != '\0')
			{
				LineDiv = 0;
				LineFlag = CURVE;
				ShadowFlag = 0;
				switch (Command)
				{
					case 'T':	
						ShadowFlag+=2; // 2 for no box
						GetBoxParameters();
						break;
					case 'W':	
						ShadowFlag++; // 1 for shadow box
						GetBoxParameters();
						break;
					case 'B':	
						GetBoxParameters(); // 0 for box
						break;
					case 'D':	
						LineDiv = getint();
						LineFlag = STRAIGHT;
						GetLineParameters();
						break;
					case 'L':	
						LineFlag = STRAIGHT;
						GetLineParameters();
						break;
					case 'C':	
						GetLineParameters();
						break;
					case 'X':	
						GetAxisTitle(X);
						break;
					case 'Y':	
						GetAxisTitle(Y);
						break;
					case 'Z':	
						YLandScape = 1;
						YTitleOrigin = GetPair(USER);
						GetAxisTitle(Y);
						break;
					case 'A':	
						AxisLabel[0] = getint();
						AxisLabel[1] = getint();
						break;
					default:
						if (PrevCommand.Equals(null))
							MessageBox.Show("Check the first line of the X/Y Plot definition.","Unrecognized Graph Command");
						else
							MessageBox.Show(string.Format("Problem with the X/Y Plot Command after {0}",PrevCommand.ToString()),"Unrecognized Graph Command");
						//							sprintf(LineBuff,"Unrecognized Graph Command: '%c'",command);
						//							err_exit(LineBuff,0);
						break;
				}
				PrevCommand = Command;
			}
			Graphics(1);
			GenerateGrid(pg,c1pdf);
			DoAxisTitles(pg,c1pdf);
			DoBoxes(pg,c1pdf);
			DrawLines(pg,c1pdf);
			Graphics(0);
			c1pdf.Save(PdfFileName);
			FreeBoxList();
			FreeLineList();
			CloseGraph();
//			return(LinesUsed);
		}
	}
}