//#define UIELEMENT
using System;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using agree;

namespace agree.Wpf.Util
{
	using Math = System.Math;

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class TfsVisualHost : 
#if UIELEMENT
		UIElement
#else
		FrameworkElement
#endif
	{
		public readonly TfsControl owner;
		public TdeConstraint viz;
		List<Visual> visuals = new List<Visual>();
		public IDictionary<Edge,ReentrancyFinder.Entry> dict_corefs;
		public Tfs tfs_highlight;

		public TfsVisualHost(TfsControl owner, Tfs e)
		{
			visuals = new List<Visual>();

			this.owner = owner;
			this.Focusable = true;
			this.IsHitTestVisible = true;
			this.Visibility = Visibility.Visible;
			this.tfs_highlight = owner._TfsEdgeHighlight;

			this.dict_corefs = e.Reentrancies;

			viz = new TdeConstraint(this, e.Edge);

			this.AddVisualTfs(viz);
//			viz.Render();
		}


		public void AddVisualTfs(Visual tfs_viz)
		{
#if UIELEMENT
#else
			this.AddLogicalChild(tfs_viz);
			this.AddVisualChild(tfs_viz);
#endif
			visuals.Insert(0, tfs_viz);
		}

		protected override Visual GetVisualChild(int index)
		{
			return visuals[index];
		}

		protected override int VisualChildrenCount
		{
			get { return visuals.Count; }
		}

		public TdeConstraint FindVisualForEdge(Edge e)
		{
			return visuals.OfType<TdeConstraint>().First(v => v.Edge.Equals(e));
		}

		IEnumerable<Visual> VisualChildren
		{
			get
			{
				for (int i=0; i < VisualChildrenCount; i++)
					yield return GetVisualChild(i);
			}
		}

#if UIELEMENT
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Size of this element is based on its single visual content
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		protected override Size MeasureCore(Size availableSize)
		{
			return viz.Rectangle.Size;
		}
#else

		protected override Size MeasureOverride(Size availableSize)
		{
			//using (DrawingContext dc = viz.RenderOpen())
				//return viz.Render(dc);
			return viz.m_size;
//			return viz.Rectangle.Size;
		}
#endif



		protected void mbeh(Object o, MouseButtonEventArgs e)
		{
			Debug.WriteLine("mbeh {0} {1} {2} {3} {4}", o, e.RoutedEvent, e.Source, e.OriginalSource, e.GetPosition(this));
			//base.OnMouseLeftButtonDown(e);
		}
		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			Debug.WriteLine("TfsVisualHost.omlbd {0} {1} {2}", e.Source, e.OriginalSource, e.GetPosition(this));
			//base.OnMouseLeftButtonDown(e);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			var htr = VisualTreeHelper.HitTest(this, e.GetPosition(this));
			TdeConstraint tdec = htr.VisualHit as TdeConstraint;
			if (tdec != null)
				Debug.WriteLine("TfsVisualHost.omm {0}", htr.VisualHit);
			else
				Debug.WriteLine("TfsVisualHost.omm {0} {1}", tdec.Edge, htr.VisualHit);

			base.OnMouseMove(e);
		}
#if false
		protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
		{
			Debug.WriteLine("TfsVisualHost.htc {0} IsEnabled:{1} IsVisible:{2} Visibility:{3} Focusable:{4} IsFocused:{5}", 
				hitTestParameters.HitPoint, IsEnabled, IsVisible, Visibility, Focusable, IsFocused);
			return base.HitTestCore(hitTestParameters);
		}
#endif

	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// Provides a font and stuff for TfsHost
	/// This is not combined with the UIElement derived class because WPF seems to crash when I add my own
	/// Visual-derived objects to a Control-derived object, but it's ok with a (single) UIElement-derived
	/// object.
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class TfsControl : Control
	{
		public bool f_brackets = true;
		public bool f_marks = true;

		public Tfs _TfsEdge
		{
			get { return (Tfs)GetValue(TfsEdgeProperty); }
			set { SetValue(TfsEdgeProperty, value); }
		}
		public Tfs _TfsEdgeHighlight
		{
			get { return (Tfs)GetValue(TfsEdgeHighlightProperty); }
			set { SetValue(TfsEdgeHighlightProperty, value); }
		}

		public TfsVisualHost host;

		public static readonly DependencyProperty TfsEdgeProperty;
		public static readonly DependencyProperty TfsEdgeHighlightProperty;

		static TfsControl()
		{
			{
				FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(
					default(Tfs),
					FrameworkPropertyMetadataOptions.None,
					(dobj, e) =>
					{
						TfsControl tfsc = (TfsControl)dobj;
						Tfs te = (Tfs)e.NewValue; 

						tfsc.host = new TfsVisualHost(tfsc, te);
						FocusManager.SetFocusedElement(tfsc, tfsc.host);
					});

				TfsEdgeProperty = DependencyProperty.Register("_TfsEdge", typeof(Tfs), typeof(TfsControl), metadata);
			}
			{
				FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(
					default(Tfs),
					FrameworkPropertyMetadataOptions.None,
					null);

				TfsEdgeHighlightProperty = DependencyProperty.Register("_TfsEdgeHighlight", typeof(Tfs), typeof(TfsControl), metadata);
			}
		}


		public TfsControl()
		{
			this.Focusable = true;
			this.IsHitTestVisible = true;
			this.Visibility = Visibility.Visible;

			//this.SnapsToDevicePixels = true;
			this.FontFamily = new FontFamily("Arial");
			this.FontSize = 13;
		}

		protected override System.Collections.IEnumerator LogicalChildren
		{
			get { yield return host; }
		}
		protected override int VisualChildrenCount { get { return 1; } }
		protected override Visual GetVisualChild(int index) { return host; }


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public void Print(PrintDialog pd)
		{
			TdeConstraint tdec = new TdeConstraint(this.host, _TfsEdge.Edge);
			Size sz = tdec.m_size;
			Debug.WriteLine("tfs size={0},{1}", sz.Width, sz.Height);

			Size page = new Size(pd.PrintableAreaWidth - 72, pd.PrintableAreaHeight - 72);
			Debug.WriteLine("page size={0},{1}", page.Width, page.Height);

			double scale = Math.Max(page.Width / sz.Width, page.Height / sz.Height);
			scale = Math.Min(scale, 1.0);
			scale = Math.Max(scale, 0.45);
			Transform trx = new ScaleTransform(scale, scale);
			Debug.WriteLine("scaling={0}", scale);

			tdec.Transform = trx;


			sz = new Size(sz.Width * scale, sz.Height * scale);

			if (sz.Height < page.Height)
			{
				using (DrawingContext dc = tdec.RenderOpen())
				{
					tdec.Offset = new Vector(36, 36);
					//dc.PushClip(new RectangleGeometry(new Rect(36, 36, page.Width, page.Height)));
					//dc.PushTransform(new TranslateTransform(36 + (page.Width / 2 - sz.Width / 2), 36 + (page.Height / 2 - sz.Height / 2)));
//					dc.PushTransform(trx);

					dc.DrawDrawing(tdec.Drawing);

//					dc.Pop();
					//dc.Pop();
					//dc.Pop();
				}
				pd.PrintVisual(tdec, "Grammar composer");
			}
			else
			{
				for (double top=0; top < sz.Height; top += page.Height)
				{
					tdec.Offset = new Vector(36, -top + 36);
					using (DrawingContext dc = tdec.RenderOpen())
					{
//						dc.PushClip(new RectangleGeometry(new Rect(36, 36, page.Width, page.Height)));
//						dc.PushTransform(new TranslateTransform(0, -top));
//						dc.PushTransform(new TranslateTransform(36, 36));
//						dc.PushTransform(trx);


						dc.DrawDrawing(tdec.Drawing);

//						dc.Pop();
//						dc.Pop();
//						dc.Pop();
//						dc.Pop();
					}

					Debug.WriteLine("printing top={0}", top);
					pd.PrintVisual(tdec, "Grammar composer");
				}
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		Typeface _typeface = null;
		public Typeface TypeFace
		{
			get
			{
				if (_typeface == null)
					_typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
				return _typeface;
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		protected override void OnRender(DrawingContext dc)
		{
			if (Background != null)
			{
				dc.DrawRectangle(Background, null, new Rect(new Point(host.viz.Offset.X,host.viz.Offset.Y),host.viz.m_size));
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public Size ContentSize
		{
			get
			{
				return host.viz.m_size;// Rectangle.Size;
			} 
		}

		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			Debug.WriteLine("TfsControl.omlbd {0} {1} {2}", e.Source, e.OriginalSource, e.GetPosition(this));
			//base.OnMouseLeftButtonDown(e);
		}
#if false
		protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
		{
			Debug.WriteLine("TfsControl.htc {0}", hitTestParameters.HitPoint);
			return base.HitTestCore(hitTestParameters);
		}
#endif
	};

}