using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;

using System.Collections.Generic;

using Math2D;
using Math2D.Shapes;

namespace MapEditor {
	public enum EditorState {
		normal,
		point,
		polygone,
		newpoly
	}
	
	class MainClass : Form {
		
		[STAThread]
		public static void Main(string[] args) {
			MainClass M = new MainClass();
			Application.Run(M);
		}
		
		public MainClass() {
			DoubleBuffered = true;
			/*
			Polygons.Add(new Polygon2D(
			                           new Vector2D(0, 0),
			                           new Vector2D(80, 0),
			                           new Vector2D(0, 80)));
			Polygons.Add(new Polygon2D(
			                           new Vector2D(90, 90),
			                           new Vector2D(140, 90),
			                           new Vector2D(90, 140)));
			                           */
			#region Menu
			ContextMenu menu = new ContextMenu();
			this.ContextMenu = menu;
			menu.MenuItems.Add("Добавить полигон", delegate {
					newPoly = new List<Point>();
					State = EditorState.newpoly;
					Invalidate();
				});
			menu.MenuItems.Add("Удалить полигон", delegate {
				if (aPoly != null) {
					Polygons.Remove(aPoly);
					aPoly = null;
					Invalidate();
				}
				});
			menu.MenuItems.Add("Сохранить карту...", delegate {
				FileDialog dlg = new SaveFileDialog();
				if (dlg.ShowDialog(this) == DialogResult.OK) {
					SaveMap(dlg.FileName);		
				}	
				});
			menu.MenuItems.Add("Сохранить", delegate {
			
				});
			menu.MenuItems.Add("Загрузить карту...", delegate {
				FileDialog dlg = new OpenFileDialog();
				if (dlg.ShowDialog(this) == DialogResult.OK) {
					BackgroundImage = new Bitmap(dlg.FileName);
					Invalidate();
				}
				});
			menu.MenuItems.Add("Загрузить изображение...", delegate {
				FileDialog dlg = new OpenFileDialog();
				if (dlg.ShowDialog(this) == DialogResult.OK) {
					BackgroundImage = new Bitmap(dlg.FileName);
					Invalidate();
				}
				});
			menu.MenuItems.Add("Темный фон", delegate {
				BackgroundBrush = Color.DarkGray;
				Invalidate();});
			menu.MenuItems.Add("Светлый фон", delegate {
				BackgroundBrush = Color.LightGray;
				Invalidate();});
			#endregion menu
		}
		
		List<Polygon2D> Polygons = new List<Polygon2D>();
		
		Color BackgroundBrush = Color.LightGray;
		Bitmap BackgroundImage = null;
		protected override void OnPaintBackground (System.Windows.Forms.PaintEventArgs e) {
			e.Graphics.Clear(BackgroundBrush);
			if (BackgroundImage != null) {
				e.Graphics.DrawImage(BackgroundImage, 0, 0);
				Color c = Color.FromArgb(
				                         0xe0,
				             			 BackgroundBrush.R,            
				                         BackgroundBrush.G,
				                         BackgroundBrush.B);
				e.Graphics.FillRectangle(new SolidBrush(c), ClientRectangle);
			}
		}
		
		
		protected override void OnPaint (System.Windows.Forms.PaintEventArgs e) {
			foreach (Polygon2D poly in Polygons) {
				PointF[] p = new PointF[]{
					new	PointF(poly.P1.X, poly.P1.Y),
					new	PointF(poly.P2.X, poly.P2.Y),
					new	PointF(poly.P3.X, poly.P3.Y)
				};				
				if (poly == aPoly) {
					e.Graphics.DrawPolygon(new Pen(Color.FromArgb(127, 255, 0, 0)), p);
					e.Graphics.FillPolygon(new SolidBrush(Color.FromArgb(64, 255, 0, 0)), p);
				}
				else {
					e.Graphics.DrawPolygon(new Pen(Color.FromArgb(127, 0, 0, 255)), p);
					e.Graphics.FillPolygon(new SolidBrush(Color.FromArgb(64, 0, 0, 255)), p);
				}
				foreach (PointF pt in p) {
					if (poly == aPoly)
						e.Graphics.DrawRectangle(Pens.Red, pt.X-2, pt.Y-2, 5, 5);
					else
						e.Graphics.DrawRectangle(Pens.Blue, pt.X-2, pt.Y-2, 5, 5);
				}
			}
			
			if (State == EditorState.newpoly) {
				foreach (Point p in newPoly) {
					e.Graphics.FillRectangle(Brushes.Black,
					                       p.X-3, p.Y-3,
					                       7, 7);
				}
				e.Graphics.DrawLine(Pens.Black,
				                    MouseX, 0,
									MouseX, ClientSize.Height);					
				e.Graphics.DrawLine(Pens.Black,
				                    0, MouseY,
									ClientSize.Width, MouseY);
			}			
		}
		
		bool GetPointXY(int x, int y, out Vector2D point) {
			foreach (Polygon2D poly in Polygons) {
				foreach (Vector2D vec in poly.P) {
					if (Math.Abs(x-vec.X)<=5 &&
					    Math.Abs(y-vec.Y)<=5) {
						PolyBringToTop(poly);
						point = vec;
						return true;
					}
				}
			}
			point = null;
			return false;
		}
		
		bool GetPolygonXY(int x, int y, out Polygon2D polygon) {
			foreach (Polygon2D poly in Polygons) {
				if (poly.CheckXY(x, y)) {
					PolyBringToTop(poly);
					polygon = poly;
					return true;
				}
			}
			polygon = null;
			return false;
		}
		
		EditorState State;
		Vector2D aPoint;
		Polygon2D aPoly;	
		Vector2D aMoveStart;
		List<Point> newPoly;
		
		void PolyBringToTop(Polygon2D poly) {
			Polygons.Remove(poly);
			Polygons.Insert(0, poly);
		}
		
		void PolySendToBack(Polygon2D poly) {
			Polygons.Remove(poly);
			Polygons.Add(poly);
		}
		
		protected override void OnMouseDown (System.Windows.Forms.MouseEventArgs e) {			
			if (State == EditorState.newpoly) {
				newPoly.Add(new Point(e.X, e.Y));
				if (newPoly.Count == 3) {
					Polygons.Insert(0, new Polygon2D(
					                           new Vector2D(newPoly[0].X, newPoly[0].Y),
					                           new Vector2D(newPoly[1].X, newPoly[1].Y),
					                           new Vector2D(newPoly[2].X, newPoly[2].Y))
					             );
					State = EditorState.normal;						 
				}
				Invalidate();
				return;	
			}
			
			aMoveStart = new Vector2D(e.X, e.Y);
			if (GetPointXY(e.X, e.Y, out aPoint)) {
				State = EditorState.point;
				return;
			}
			if (GetPolygonXY(e.X, e.Y, out aPoly)) {
				if (e.Button == MouseButtons.Middle) {
					PolySendToBack(aPoly);	
					aPoly = null;
					return;
				}
				State = EditorState.polygone;
				return;
			}			
		}
		
		protected override void OnMouseUp (System.Windows.Forms.MouseEventArgs e) {
			if (State == EditorState.newpoly) return;
			State = EditorState.normal;
			Invalidate();
		}
		
		int MouseX = 0;
		int MouseY = 0;
		protected override void OnMouseMove (System.Windows.Forms.MouseEventArgs e) {						
			switch (State) {
			case EditorState.point:
				aPoint.Set(e.X, e.Y);					
				Invalidate();
				break;
			case EditorState.polygone:
				Vector2D newV = new Vector2D(e.X, e.Y);
				aPoly.Offset(newV - aMoveStart);
				aMoveStart = newV;
				Invalidate();			
				break;			
			case EditorState.newpoly:
				MouseX = e.X;
				MouseY = e.Y;
				Invalidate();
				break;
			}
		}
		
		void SaveMap(string fileName) {
			FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate);
			BinaryWriter bw = new BinaryWriter(fs);
			bw.Write((Int32)Polygons.Count);
			foreach(Polygon2D poly in Polygons) {
				foreach(Vector2D v in poly.P) {
					bw.Write((Int32)v.X);	
					bw.Write((Int32)v.Y);
				}
			}
		}
		
		void LoadMap(string fileName) {
			
		}
	}
}