using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectDraw;


namespace GenericGraph
{
	/// <summary>
	/// Summary description for Class.
	/// </summary>
	public class GGraph
	{

		private System.Windows.Forms.Panel panel;
		private Microsoft.DirectX.DirectDraw.Device draw = null; // Holds the DrawDevice object.
		private SurfaceDescription description;
		private SurfaceDescription description2;
		private Surface primary = null; // Holds the primary destination surface.
		private Surface offscreen = null; // Holds the offscreen surface that the bitmap will be loaded on.
		private Clipper clip = null; // Holds the clipper object.
		private Rectangle destination = new Rectangle();
		private Font font = null;//screen text font;
		private Font font2 = null;//screen text font;
		private Font fontRot = null;
		private Size size;
		private bool negative = false;


		public Color BackgroundColor;
		public Color ForeColor;
		public string xlabel = string.Empty;
		public string ylabel = string.Empty;
		public string title = string.Empty;
		public ArrayList listLines;
		//	public ArrayList listPts;
		public Modes Mode;
		public enum Modes {	XY,X};
		public bool bFFT = false;



		public GGraph()
		{
			panel = null;
			BackgroundColor = Color.Black;
			ForeColor = Color.Red;
			//			listPts = new ArrayList();
			listLines = new ArrayList();
			Mode = Modes.X;
		}

		public void SetPanel(System.Windows.Forms.Panel panelDraw)
		{
			panel = panelDraw;
			draw = new Microsoft.DirectX.DirectDraw.Device(); // Create a new DrawDevice, using the default device.
			draw.SetCooperativeLevel(panel, CooperativeLevelFlags.Normal); // Set the coop level to normal windowed mode.
			SetDescriptions();
			CreateSurfaces();

		}
		public void SetSize(Size s)
		{
			size = s;
		}
		private void SetDescriptions()
		{
			description = new SurfaceDescription(); // Create a new SurfaceDescription struct.
			description.SurfaceCaps.PrimarySurface = true; // The caps for this surface is simply primary.
			description2 = new SurfaceDescription();
			description2.SurfaceCaps.OffScreenPlain = true;
			description2.Height = panel.Height;
			description2.Width = panel.Width;
		}
		private void CreateSurfaces()
		{
			if(primary!=null)
				primary.Dispose();
			primary = new Surface(description, draw); // Create the primary surface.
			clip = new Clipper(draw); // Create a new clipper.
			clip.Window = panel; // The clipper will use the main window handle.
			primary.Clipper = clip; // Assign this clipper to the primary surface.
			offscreen = new Surface(description2, draw); // Create the surface using the specified file.
		}

		
		public void Draw(Point l)
		{
			negative = false;
			try
			{
				if (null == primary)
					return;
				//Height = Height < 50 ? 50 : Height; // Make sure the height is always valid.
            
				// Get the new client size to Draw to.
				destination = new Rectangle(l,size);
				if(font!=null)
					font.Dispose();
				if(font2!=null)
					font2.Dispose();
				if(fontRot!=null)
					fontRot.Dispose();
				font = new Font("Arial",panel.Height/32,FontStyle.Bold);
				font2 = new Font("Arial",panel.Height/20,FontStyle.Bold);

				
							
				
				if(description!=null)
				{
					IntPtr ptr;
					ptr = font.ToHfont();
					offscreen.FontHandle = ptr;
					offscreen.ColorFill(BackgroundColor);
						
					ptr = font.ToHfont();
					offscreen.FontHandle = ptr;
					offscreen.ForeColor = ForeColor;
					offscreen.DrawText(panel.Width/2-10,10,title,false);
					offscreen.DrawText(panel.Width/2-10,panel.Height-15,xlabel,false);
					//offscreen.DrawText(8,panel.Height/2-20,ylabel,false);
					//frame lines
					offscreen.DrawLine(20,10,20,panel.Height-20);
					offscreen.DrawLine(20,panel.Height-20,panel.Width-12,panel.Height-20);
					if(this.listLines.Count>0)
					{
						if(Mode==Modes.X) 
							DrawXGraph();
						else 
							DrawXYGraph();
					}
				}
			
				// Try and Draw the offscreen surface on to the primary surface.
				primary.Draw(destination, offscreen, DrawFlags.Wait);
				
			}
			catch(SurfaceLostException)
			{
				// The surface can be lost if power saving
				// mode kicks in, or any other number of
				// reasons.
				CreateSurfaces(); // Surface was lost. Recreate them.
			}
		}
		private void DrawXGraph()
		{
			IntPtr ptr;
			ptr = font.ToHfont();
			offscreen.FontHandle = ptr;
			int X = FindMaxX();
			double y = 0.0;
			double x = ((double)panel.Width-32 )/ (double)(X);
			double curX = 0.0;
			double Y = FindMaxY();
			int iUpMargin = 20;
			int iLoMargin = 20;
			int DrawHeight = panel.Height-iUpMargin-iLoMargin; // panel.height-upper margin-lower margin

			if(negative==false)
				y = ((double) DrawHeight) / Y;
			else
				y = ((double) DrawHeight )/ (2*Y);
			if(negative==false)
			{
				for (int iTemp=4;iTemp>=0;iTemp--)
				{
					offscreen.DrawText(1,iUpMargin +(int)DrawHeight*iTemp/4,(Y*(4-iTemp)/4).ToString("#####.0"),false);
					offscreen.DrawLine(12,iUpMargin+(int)DrawHeight*iTemp/4,20,iUpMargin+(int)DrawHeight*iTemp/4);
				}
				//offscreen.DrawText(1,(int)(panel.Height-20),"0",false);
				//offscreen.DrawLine(12,(int)(panel.Height-20),20,(int)(panel.Height-20));

			}
			else
			{
				for( int iTemp=4;iTemp>=0;iTemp--)
				{
					offscreen.DrawText(1,iUpMargin+(int)DrawHeight* iTemp /8,(Y*(4-iTemp)/4).ToString("#####.0"),false);
					offscreen.DrawLine(12,iUpMargin+(int)DrawHeight* iTemp/8,20,iUpMargin+(int)DrawHeight*iTemp/8);
				}
				for( int iTemp=3;iTemp>=0;iTemp--)
				{
					offscreen.DrawText(1,iUpMargin+(int)DrawHeight* (8-iTemp) /8,(Y*(iTemp-4)/4).ToString("#####.0"),false);
					offscreen.DrawLine(12,iUpMargin+(int)DrawHeight* (8-iTemp)/8,20,iUpMargin+(int)DrawHeight*(8-iTemp)/8);

				}
				/*
					offscreen.DrawText(1,(int)((panel.Height-20)/2-y*Y),Y.ToString("#####.0"),false);
					offscreen.DrawLine(12,(int)((panel.Height-20)/2-y*Y),20,(int)((panel.Height-20)/2-y*Y));

					offscreen.DrawText(1,(int)(panel.Height-20),"-"+Y.ToString("####.0"),false);
					offscreen.DrawLine(12,(int)((panel.Height-20)/2-y*-1*Y),20,(int)((panel.Height-20)/2-y*-1*Y));

					offscreen.DrawText(1,(int)((panel.Height-20)/2),"0",false);
					offscreen.DrawLine(12,(int)((panel.Height-20)/2),20,(int)((panel.Height-20)/2));
					*/
				
			}

			double lastx = 20;
			double lasty = 0.0;
			int XLabel = 1000;
			double xScale=1;
			/*	int nIdealSamples = listPts.Count*2;
				int nRealSamples = 32768;
				while(nRealSamples<nIdealSamples)
				{
					nRealSamples <<= 1;
				}
				int XLabel = 1000;
				double xScale=1;
				if(bFFT==true)
				{
					XLabel = 1000;
					double xSec = (double)nRealSamples/((double)nIdealSamples);
					xScale = xSec*1000;
				}*/
			
			bool bTick = false;
			foreach(GLine gl in listLines)
			{
				int count = 0;
				lastx = 0;
				lasty = 0.0;
				XLabel = 500;
				curX = 0.0;
				offscreen.ForeColor = gl.ForeColor;
				foreach(double d in gl.listPts)
				{
					count++;
					double xval = curX+20;
					double yval = 0.0;
					if(negative==false)
						yval = panel.Height-20-y*d;
					else
						yval = (panel.Height-20)/2-y*d;
					if(lastx>0)
						offscreen.DrawLine((int)lastx,(int)lasty,(int)xval,(int)yval);
					int z=(int)(count);
					if(bFFT==true)
					{
						z = (int)(z/xScale*1000);
						z=0;
					}
					
					//5000hz marker
					if(z*8>8000&&bTick==false)
					{
						if(listLines.Count>1)
							offscreen.DrawLine((int)xval, panel.Height-18, (int)xval, 0/*panel.Height-40*/);
						bTick=true;
					}
					
					if(z*8>=XLabel && Math.Abs(panel.Width-2*curX)>100)
					{
							offscreen.DrawLine((int)lastx,(int)lasty,(int)lastx,(int)lasty+20);
							offscreen.DrawLine((int)lastx,panel.Height-20,(int)lastx,panel.Height-10);
							/*	double aa = d*0.000000596;
								if(d<100)
									offscreen.DrawText((int)xval,(int)yval,d.ToString("#########.000"),false);
								else
									offscreen.DrawText((int)xval,(int)yval,d.ToString("##########"),false);*/
							if(bFFT == false)
								offscreen.DrawText((int) curX,panel.Height-15,(z*8).ToString(),false);
							else
							{
								offscreen.DrawText((int) curX,panel.Height-15,(z*8).ToString(),false);
							}
							XLabel+=2000;
						
					}

					lastx = xval;
					lasty = yval;
					curX+= x;
				}
			}
		}
		private void DrawXYGraph()
		{
		}
		private double FindMaxY()
		{
			double y = 0.0;
			int nCount = 0;
			int nIt = 0;
			foreach(GLine gl in listLines)
			{
				foreach(double d in gl.listPts)
				{
					nCount++;
					if(nCount*8 > 200)//count only freq > 200
					{
						if(Math.Abs(d)>y)
						{
							y = Math.Abs(d);
							nIt = nCount;
						}
						if(d<0)
							negative = true;
					}
				}
				nCount = 0;
			}
			return y+20;
		}
		
		private int FindMaxX()
		{
			int y=0;
			foreach(GLine gl in listLines)
			{
				if(gl.listPts.Count>y)
					y = gl.listPts.Count;
			}
			return y;
		}
		public void AddPoint(int line, double x)
		{
			((GLine)listLines[line]).listPts.Add(x);
			
		}
		public void AddPoint(double x)
		{
			if(listLines.Count>0)
				((GLine)listLines[0]).listPts.Add(x);
		}
		public void AddLine(Color c)
		{
			GLine gl = new GLine();
			gl.ForeColor = c;
			listLines.Add(gl);
		}
		public void ClearPtList()
		{
			foreach(GLine gl in listLines)
			{
				gl.listPts.Clear();
			}
			listLines.Clear();
			
		}
		
	}
	public class GLine
	{
		public ArrayList listPts;
		public Color ForeColor;
		public GLine()
		{
			listPts = new ArrayList();
			ForeColor = Color.White;
		}
	}
}
