// MapView program: show the map and tracker position 
// --------------------------------------------------------
// June 20,2004 
// By Xiaotao Shu.

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

using TrackingController;

namespace tools
{
	public class MapView : System.Windows.Forms.Form
	{
		/// <summary>
		/// MapView show a map and trackees, it is refresh when the trackees move
		/// </summary>
		private string m_imageFile;
		private Image m_background = null;                           //background image
		private VectorMap m_vectorMap = null;                        //store a vector map (APRS's map file format)
		private System.ComponentModel.Container components = null;
		private Controller m_controller = null;                                //data controller
		//public bool isFillObject = true;                             //whether or not fill the object, when draw the map

		//attributes for zoom 
		private double  m_scaleX = 0.0 ;
		private double  m_scaleY = 0.0 ;
		private double  m_currentZoom = 1.0 ;
		private double m_latOffset = 0.0;
		private double m_lonOffset = 0.0;
		private bool m_resetDrawOffset = true;
		private Position m_capturePos = null;

		//constrcutor
		public MapView( mainform parent )
		{
			InitializeComponent();
			//set view's parent
			this.MdiParent = parent; 
			//set double buffer,for avoiding screen twinkling.
			SetStyle(ControlStyles.ResizeRedraw|ControlStyles.AllPaintingInWmPaint|ControlStyles.DoubleBuffer,true);
		}
		

		//loadImage method: load an image from a image file 
		public void LoadImage( string imagefile )
		{
			m_resetDrawOffset = true;
			try
			{
				if ( (imagefile.IndexOf(".map") > 0) || (imagefile.IndexOf(".MAP") > 0) )
				{
					//clear old vectorMap.
					if (m_vectorMap != null)
						m_vectorMap = null;
					m_vectorMap = new VectorMap(imagefile);
					//create a bitmap from vector map
					setBackground();
				}
				else
				{
					m_vectorMap = null;
					if (m_background != null)
						m_background = null;
					m_background = Image.FromFile(imagefile);
				}
				//set scrollbar if the image is too big
				this.AutoScroll = true;
				this.AutoScrollMinSize = m_background.Size;
			}
			catch(Exception e)
			{
				MessageBox.Show(e.ToString());
				m_background = null;
				m_vectorMap = null;
			}
		}


		//loadImage method: load an image from a image file 
		public void LoadImage( string imagefile,double top,double left,double right, double bottom )
		{
			LoadImage(imagefile);
			//calculate the scale of the Bimmap 
			if (m_vectorMap == null)
			{
				if (right-left >0 && bottom-top>0)
				{
					m_scaleX = (double)m_background.Width / (right-left);
					m_scaleY = (double)m_background.Height / (bottom-top);
					m_latOffset = top;
					m_lonOffset = left;
					m_currentZoom = 1.0;
				}
				else //lat=90 to -90 and lon=-180 to 180
				{
					m_scaleX = (double)m_background.Width / 360;
					m_scaleY = (double)m_background.Height / 180;
					m_latOffset = 90;
					m_lonOffset = -180;
					m_currentZoom = 1.0;
				}
			}
		}


		//declaring controller property
		public Controller Controller
		{
			set	{	m_controller = value;	}
			get	{	return m_controller;		}
		}
		public string ImageFile
		{
			set	{	m_imageFile = value;	}
			get	{	return m_imageFile;		}
		}
		
		public Image Image
		{
			get	{	return this.m_background;	}
		}
		

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			// 
			// MapView
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.BackColor = System.Drawing.Color.White;
			this.ClientSize = new System.Drawing.Size(600, 301);
			this.Name = "MapView";
			this.Text = "MapView";
			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MouseDownHandler);
			this.Load += new System.EventHandler(this.MapView_Load);
			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MouseMoveHandler);

		}
		#endregion

		//draw the view
		protected override void OnPaint(PaintEventArgs e)
		{
			//If there is an image and it has a location, paint it when the Form is repainted.
			
			//get the Graphics object associated with our form's device context
			Graphics g = e.Graphics;

			//check and see if it is valid
			if (m_background == null) 
			{
				m_imageFile = Controller.WorkDir+"\\earthEquidistant.gif";
				LoadImage(m_imageFile,90,-180,180,-90);
			}
			
			//use the DrawImage function to show the image
			g.DrawImage(m_background,AutoScrollPosition.X,
				AutoScrollPosition.Y,m_background.Width, m_background.Height);
			
			// Draw all the trackees
			TrackeeServant aTrackee = null;
			for (int i = 0; i <Controller.Trackees.Count; i++)
			{
				if(this.Controller.Trackees[i] != null)
				{
					aTrackee = (TrackeeServant)Controller.Trackees[i];
					if (aTrackee.Position !=null)
					{
						// Create solid brush.
						SolidBrush aBrush = new SolidBrush(aTrackee.Color);
						// map the location to a point
						Point aPoint = aTrackee.Position.ToPoint(m_currentZoom*m_scaleX,
							m_currentZoom*m_scaleY, m_latOffset,m_lonOffset);
    				
						// draw the trackee as a filled circle
						g.FillEllipse(aBrush,aPoint.X, aPoint.Y, 6, 6);
						//draw label
						g.DrawString(aTrackee.Label, aTrackee.Font,new SolidBrush(aTrackee.LabelColor),
							aPoint.X+5,aPoint.Y+5);
					}
				}
			}
			//change the status bar current tracker position information
			//if (this.Controller.CurrentTrackerPosition != null)
			if (this.Controller.CurrentTracker != null)
			{
				//((mainform)this.MdiParent).statusBarPanel5.Text = "Tracker: "+this.Controller.CurrentTrackerPosition.LatString();
				//((mainform)this.MdiParent).statusBarPanel6.Text = "Tracker: "+this.Controller.CurrentTrackerPosition.LonString();
				((mainform)this.MdiParent).statusBarPanel5.Text = this.Controller.CurrentTracker.ID+": "+this.Controller.CurrentTracker.Position.LatString();
				((mainform)this.MdiParent).statusBarPanel6.Text = this.Controller.CurrentTracker.ID+": "+this.Controller.CurrentTracker.Position.LonString();
			}
		}

		protected override void OnResize(EventArgs e)
		{
			if (this.m_vectorMap != null)
			{
				//create a bitmap from vector map
				setBackground();
			}
			base.OnResize (e); 
		}

		public void ZoomIn()
		{
			if (m_vectorMap != null)
			{
				// Zoom in  50%
				m_currentZoom = m_currentZoom / 2.0;
				m_latOffset = m_capturePos.Latitude-(m_vectorMap.m_bottom-m_vectorMap.m_top)/(2.0*m_currentZoom);
				m_lonOffset = m_capturePos.Longitude-(m_vectorMap.m_right-m_vectorMap.m_left)/(2.0*m_currentZoom);
				//create a bitmap from vector map
				setBackground();
			}
			else  //zoom the bitmap directly
			{
				m_currentZoom = m_currentZoom/1.2;
				m_background = new Bitmap(m_background, (int)((double)(m_background.Width)/1.2),
					(int)((double)(m_background.Height)/1.2) );
				this.AutoScrollMinSize=m_background.Size;
			}
			Invalidate();
		}

		public void ZoomOut()
		{
			if (m_vectorMap != null)
			{
				// Zoom out to 200%
				m_currentZoom = m_currentZoom* 2.0;
				m_latOffset = m_capturePos.Latitude-(m_vectorMap.m_bottom-m_vectorMap.m_top)/(2.0*m_currentZoom);
				m_lonOffset = m_capturePos.Longitude-(m_vectorMap.m_right-m_vectorMap.m_left)/(2.0*m_currentZoom);
				//create a bitmap from vector map
				setBackground();
			}
			else   //zoom out to 120% the bitmap
			{
				m_currentZoom = m_currentZoom*1.2;
				m_background = new Bitmap(m_background, (int)((double)(m_background.Width)*1.2),
					(int)((double)(m_background.Height)*1.2) );
				this.AutoScrollMinSize = m_background.Size;
			}
			Invalidate();
		}

		public void ZoomHome()
		{
			if (m_vectorMap != null)   
			{
				// Zoom so that the whole image fits; this is calculated
				m_resetDrawOffset = true;
				//create a bitmap from vector map
				setBackground();
			}
			else
			{
				m_currentZoom = 1.0;
				LoadImage(m_imageFile);
			}
			Invalidate();
		}


		//handle the mouse move, current position change
		private void MouseMoveHandler(Object sender,MouseEventArgs e)
		{
			if (e.X > this.ClientRectangle.Left && e.X < this.ClientRectangle.Right
				&& e.Y > this.ClientRectangle.Top && e.Y < this.ClientRectangle.Bottom)
			{
				//change status bar' current position 
				Position currentLoc = new Position(m_latOffset - e.Y /(m_currentZoom*m_scaleY),
					m_lonOffset + e.X /(m_currentZoom*m_scaleX) );
				((mainform)this.MdiParent).statusBarPanel1.Text = currentLoc.LatString();
				((mainform)this.MdiParent).statusBarPanel2.Text = currentLoc.LonString();
			}
		}


		private void MouseDownHandler(Object sender,MouseEventArgs e)
		{
			
			if (e.X > this.ClientRectangle.Left && e.X < this.ClientRectangle.Right
				&& e.Y > this.ClientRectangle.Top && e.Y < this.ClientRectangle.Bottom) 
			{
				// capture the focus position
				double lat = m_latOffset - (double)(e.Y /(m_currentZoom * m_scaleY));
				double lon = m_lonOffset + (double)(e.X /(m_currentZoom * m_scaleX));
				m_capturePos = new Position(lat,lon);

				//change status bar' current position 
				((mainform)this.MdiParent).statusBarPanel3.Text = "Capture Position "+m_capturePos.LatString();
				((mainform)this.MdiParent).statusBarPanel4.Text = "Capture Position "+m_capturePos.LonString();
			}
		}
		

		//create a bimap from this vectormap
		// This is where we draw vector map to bitmap
		public  Image vectorToBitmap()
		{
			if (this.ClientSize.Width<=0 || this.ClientSize.Height <=0)
				return null;

			// Caching this bitmap would be more efficient than creating one every time we repaint the window
			System.Drawing.Image newBitmap = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
			Graphics g = Graphics.FromImage(newBitmap);
			// Fill the background with while.
			g.FillRectangle(Brushes.White,0,0,this.ClientSize.Width, this.ClientSize.Height);
			
			// Make sure the map has some data
			if (m_vectorMap.m_right == m_vectorMap.m_left || m_vectorMap.m_top == m_vectorMap.m_bottom)
			{
				// No data, no map
				return null;
			}

			if (m_resetDrawOffset)
			{
				//calculate the scale of the Bimmap
				double dScaleX = (double)ClientSize.Width / (m_vectorMap.m_right-m_vectorMap.m_left);
				double dScaleY = (double)ClientSize.Height / (m_vectorMap.m_bottom-m_vectorMap.m_top);
				double dScale = Math.Min(Math.Abs(dScaleX), Math.Abs(dScaleY));
				m_scaleX = dScale;
				m_scaleY = dScale;
 					
				m_currentZoom = 1.0;
				
				//set the centre position to capturePos
				//capture the focus position
				double lat = m_vectorMap.m_top + (m_vectorMap.m_bottom - m_vectorMap.m_top) /2.0;
				double lon = m_vectorMap.m_left + ( m_vectorMap.m_right - m_vectorMap.m_left) /2.0;
				m_capturePos = new Position(lat,lon);
				
				//set the screen coordinate (0,0)'s geographical position
				m_latOffset = m_vectorMap.m_top;
				m_lonOffset = m_vectorMap.m_left;

				m_resetDrawOffset = false;
			}

			//string path=Environment.CurrentDirectory+"\\positions1.txt";
			//System.IO.StreamWriter file = new System.IO.StreamWriter(path);
			
			// Draw the map lines
			foreach (MapLineEntry aMapLine in m_vectorMap.m_lines)
			{
				//get the number of the points on this line
				int iNumPts = aMapLine.getPoints().Count;
				
				if  (aMapLine.Brush == null || ((mainform)this.MdiParent).isFillObject == false )//draw normal line
				{
					for (int i=0; i<(iNumPts-1); i++)
					{
						// Get each latitude and longitude of the position from map, and convert
						// it into screen coordinates X and Y
						MapPointEntry aMapPointA =  (MapPointEntry)aMapLine.getPoints()[i];
						Point aPtA =aMapPointA.Position.ToPoint(m_currentZoom*m_scaleX,m_currentZoom*m_scaleY,
							m_latOffset,m_lonOffset);
						// Same for the 2nd point.
						Point aPtB = ((MapPointEntry)aMapLine.getPoints()[i+1]).Position.ToPoint(m_currentZoom*m_scaleX,
							m_currentZoom*m_scaleY, m_latOffset,m_lonOffset);
						g.DrawLine(aMapLine.Pen,aPtA,aPtB);
						
						/*if ( aMapLine.Pen.Color == Color.Magenta)
						{
							file.Write(aMapPointA.Position.Latitude);
							file.Write("\t");
							file.WriteLine(aMapPointA.Position.Longitude);
						}*/
					}
				}
				else  //draw filled object
				{
					//create a graphicsPath 
					GraphicsPath aPath = new GraphicsPath(FillMode.Winding);//.Alternate); 
					//start the path
					aPath.StartFigure();
					
					for (int i=0; i<(iNumPts-1); i++)
					{
						// Get each latitude and longitude of the position from map, and convert
						// it into screen coordinates X and Y
						MapPointEntry aMapPointA =  (MapPointEntry)aMapLine.getPoints()[i];
						Point aPtA = aMapPointA.Position.ToPoint(m_currentZoom*m_scaleX,m_currentZoom*m_scaleY,
							m_latOffset,m_lonOffset);
						// Same for the 2nd point.
						Point aPtB = ((MapPointEntry)aMapLine.getPoints()[i+1]).Position.ToPoint(m_currentZoom*m_scaleX,
							m_currentZoom*m_scaleY, m_latOffset,m_lonOffset);
						//add a line(aPtA to aPtB) to path
						aPath.AddLine(aPtA, aPtB);
						
						/*if ( ((SolidBrush)aMapLine.Brush).Color == Color.Magenta)
						{
							file.Write(aMapPointA.Position.Latitude);
							file.Write("\t");
							file.WriteLine(aMapPointA.Position.Longitude);
						}*/
					}
					//close this figure
					aPath.CloseFigure();
					//first fill object then draw the border line
					if ( aMapLine.Brush != null )
						g.FillPath(aMapLine.Brush, aPath);
					// Draw the broder line
					g.DrawPath(aMapLine.Pen, aPath);
				} //end if
			
			} //end foreach
			//file.Close();
			
			// Build the font we draw the label
			if (((mainform)this.MdiParent).displayLabel || ((mainform)this.MdiParent).displaySymbol)
			{
				Font LabelFont = new Font("Arial Narrow", 7.0f);
				// Draw label
				foreach (MapLabelEntry aMapLabel in m_vectorMap. m_labels)
				{
					if ( (((mainform)this.MdiParent).displayLabel == false && aMapLabel.isSymbol == false) ||
						 (((mainform)this.MdiParent).displaySymbol == false && aMapLabel.isSymbol) )
							continue;	

					Point aPtr = aMapLabel.m_location.ToPoint(m_scaleX*m_currentZoom,m_scaleX*m_currentZoom,m_latOffset,m_lonOffset);
					
					//magnification view level: 256 divided by (number of zoom - 1)
					int dLimitMag =(int)( 256 / m_currentZoom -1);
					if (aPtr.X>0 && aPtr.X <this.ClientSize.Width 
						&& aPtr.Y>0 && aPtr.Y <this.ClientSize.Height)
						if (aMapLabel.m_mag > dLimitMag || aMapLabel.m_mag == 0) 
						{
							if (aMapLabel.isSymbol)
							{
								// draw the trackee as a filled circle
								g.FillEllipse(new SolidBrush(Color.Red),aPtr.X,aPtr.Y, 6, 6);
								int x,y;
								x = aPtr.X -(aMapLabel.m_text.Length*6/2);
								y = aPtr.Y + 5;
								g.DrawString(aMapLabel.m_text, LabelFont, new SolidBrush(aMapLabel.m_color), x,y);
							}
							else
								g.DrawString(aMapLabel.m_text, LabelFont, new SolidBrush(aMapLabel.m_color), aPtr.X,aPtr.Y);
						}
				}
			}

			return newBitmap;
		
		} //the ToBitMap method end


		
		public void SaveImage(string FileName,string FileType)
		{

			ImageFormat iFormat;
			if (FileType == "GIF" || FileType == "gif")
				iFormat = ImageFormat.Gif;
			else if (FileType == "JPG" || FileType == "jpg" ||FileType == "JPEG" || FileType == "jpeg"  )
				iFormat = ImageFormat.Jpeg;
			else if (FileType == "PNG" || FileType == "png" )
				iFormat = ImageFormat.Png;
			else if (FileType == "TIFF" || FileType == "tiff")
				iFormat = ImageFormat.Tiff;
			else if (FileType == "EMF" || FileType == "emf")
				iFormat = ImageFormat.Emf;
			else if (FileType == "WMF" || FileType == "wmf")
				iFormat = ImageFormat.Wmf;
			else
				iFormat = ImageFormat.Bmp;
			
			this.m_background.Save(FileName,iFormat);
		}


		public void setBackground()
		{
			if (m_vectorMap == null)
				return;
			m_background = vectorToBitmap();
		}

		private void MapView_Load(object sender, System.EventArgs e)
		{
		
		}

	}  //the MapView class end: by xiaotao
}
