using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ActiproSoftware.Windows.Controls.Docking;
using glue.Extensions.Enumerable;
using glue.Extensions.String;
using glue.WpfUtil;
using agree;
using agree.Parse;
using agree.Wpf.Util;

using glue;

#pragma warning disable 0649

namespace WpfClient
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class AgreeDocument : DocumentWindow
	{
		public AgreeDocument()
			: base(MyDockSite.g_docksite)
		{
			this.CanRaft = true;
		}

		public virtual void Print(PrintDialog pd) { }
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	abstract public class AgreeGrammarDocument : AgreeDocument
	{
		public AgreeGrammarDocument(Grammar g)
		{
			this.g = g;
		}
		protected Grammar g;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	class ExpandedWindow : AgreeGrammarDocument
	{
		readonly agree.ISysObj so;

		public agree.ISysObj Inst { get { return so; } }

		public ExpandedWindow(agree.Instance t)
			: base(t.mgr.g)
		{
			this.so = t;
			uc_tfs stg = new uc_tfs();
			stg.TfsControl._TfsEdge = t.Expanded;

			Entry ex = t as Entry;
			if (ex != null)
			{
				stg.entry_name.Text = t.Name;
				stg.entry_name.Visibility = System.Windows.Visibility.Visible;
				stg.split_line.Visibility = System.Windows.Visibility.Visible;
			}

			this.Title = String.Format("{0}: expanded", t.Name);
			this.Description = "Expanded typed feature structure for ";
			this.Content = stg;

			//		stg.TfsControl.SizeChanged += new SizeChangedEventHandler(TfsControlSizeChanged);

			this.KeyDown += (sender, e) =>
				{
					if (e.Key == Key.Escape)
						this.Close();
				};
		}

		public ExpandedWindow(TfsEdge tfs)
			: base(tfs.Tray.tm.g)
		{
			this.so = tfs;
			uc_tfs stg = new uc_tfs();
			stg.TfsControl._TfsEdge = tfs;

			this.Title = String.Format("{0}", tfs.ToString());
			this.Description = "typed feature structure";
			this.Content = stg;

			//		stg.TfsControl.SizeChanged += new SizeChangedEventHandler(TfsControlSizeChanged);

			this.KeyDown += (sender, e) =>
			{
				if (e.Key == Key.Escape)
					this.Close();
			};
		}


		public ExpandedWindow(TfsEdge tfs, TfsEdge tfs_highlight)
			: base(tfs.Tray.tm.g)
		{
			this.so = tfs;
			uc_tfs stg = new uc_tfs(tfs, tfs_highlight);

			this.Title = String.Format("{0}", tfs.ToString());
			this.Description = "typed feature structure";
			this.Content = stg;

			//		stg.TfsControl.SizeChanged += new SizeChangedEventHandler(TfsControlSizeChanged);

			this.KeyDown += (sender, e) =>
			{
				if (e.Key == Key.Escape)
					this.Close();
			};
		}

		/// <summary>
		/// Set the initial floating window size for when it's dragged out of docking position
		/// </summary>
		void TfsControlSizeChanged(object sender, SizeChangedEventArgs e)
		{
			if (State == DockingWindowState.Document)
			{
				uc_tfs stg = this.Content as uc_tfs;

				TfsControl tfsc = stg.TfsControl;
				Size sz = tfsc.ContentSize;
				sz.Width += tfsc.Margin.Left + tfsc.Margin.Right;
				sz.Height += tfsc.Margin.Top + tfsc.Margin.Bottom;

				ScrollViewer sv = (ScrollViewer)stg.FindName("tfsc_sv");
				sz.Width += sv.ComputedVerticalScrollBarVisibility == System.Windows.Visibility.Collapsed ? 4 : 19;
				sz.Height += sv.ComputedHorizontalScrollBarVisibility == System.Windows.Visibility.Collapsed ? 21 : 20;

				Size ds = new Size(DockSite.Workspace.ActualWidth, DockSite.Workspace.ActualHeight);
				sz.Width = Math.Min(sz.Width, ds.Width - 40);
				sz.Height = Math.Min(sz.Height, ds.Height - 40);

				this.SetValue(DockSite.ControlSizeProperty, sz);
			}
		}

		public override void Print(PrintDialog pd)
		{
			(this.Content as uc_tfs).Print(pd);
		}

#if false
		protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
		{
			String n = (this.t != null) ? t.Name : "??";
			Debug.WriteLine("{0:X8} {1} {2} {3} -> {4}", this.GetHashCode(), n, e.Property, e.OldValue, e.NewValue);
			base.OnPropertyChanged(e);
		}
#endif
	};




	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	class AllTypesWindow : AgreeGrammarDocument
	{
		readonly agree.ISysObj so;

		public agree.ISysObj Inst { get { return so; } }

		public AllTypesWindow(Grammar g)
			: base(g)
		{
			this.so = g;

			this.Title = String.Format("all types");
			this.Description = "all types";

			Grid bar = new Grid();
			this.Content = bar;

			Foo foo = new Foo();
			Slider sl = new Slider();
			sl.Minimum = .3;
			sl.Maximum = 4;
			sl.Value = 1.0;
			sl.Width = 80;
			sl.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
			sl.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
			bar.Children.Add(foo);
			bar.Children.Add(sl);

			foreach (agree.Type t in g.tm.AllTypes)
			{
				if (t.Name.Length == 1 || t.IsGlb)
				{
					var tc = new TfsControl();
					tc._TfsEdge = t.Expanded;
					tc.Margin = new Thickness(10);

					ScaleTransform st = new ScaleTransform();
					tc.LayoutTransform = st;

					BindingOperations.SetBinding(st, ScaleTransform.ScaleXProperty, Anon<Binding>.New(b =>
					{
						b.Source = sl;
						b.Path = new PropertyPath("Value");
					}));
					BindingOperations.SetBinding(st, ScaleTransform.ScaleYProperty, Anon<Binding>.New(b =>
					{
						b.Source = sl;
						b.Path = new PropertyPath("Value");
					}));





					foo.Children.Add(tc);

				}
			}



			//		stg.TfsControl.SizeChanged += new SizeChangedEventHandler(TfsControlSizeChanged);

			this.KeyDown += (sender, e) =>
			{
				if (e.Key == Key.Escape)
					this.Close();
			};
		}

		public override void Print(PrintDialog pd)
		{
			(this.Content as uc_tfs).Print(pd);
		}

#if false
		protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
		{
			String n = (this.t != null) ? t.Name : "??";
			Debug.WriteLine("{0:X8} {1} {2} {3} -> {4}", this.GetHashCode(), n, e.Property, e.OldValue, e.NewValue);
			base.OnPropertyChanged(e);
		}
#endif
		class Foo : WrapPanel
		{
			public ScaleTransform st;
			public Foo()
			{
				this.Orientation = System.Windows.Controls.Orientation.Horizontal;
				st = new ScaleTransform();
				this.RenderTransform = st;
			}


		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if false
	class EdgeWindow : AgreeGrammarDocument
	{
		TfsEdge edge;

		public TfsEdge Edge { get { return edge; } }

		public EdgeWindow(TfsEdge e, String title)
			: base(e.Type.mgr.g)
		{
			this.edge = e;
			uc_tfs stg = new uc_tfs();
			stg.TfsControl._TfsEdge = edge;

			this.Title = title ?? String.Format("Feature Structure - {0}", edge.Type.Name);
			this.Description = "typed feature structure";
			this.Content = stg;

			//		stg.TfsControl.SizeChanged += new SizeChangedEventHandler(TfsControlSizeChanged);
		}

		/// <summary>
		/// Set the initial floating window size for when it's dragged out of docking position
		/// </summary>
		void TfsControlSizeChanged(object sender, SizeChangedEventArgs e)
		{
			if (State == DockingWindowState.Document)
			{
				uc_tfs stg = this.Content as uc_tfs;

				TfsControl tfsc = stg.TfsControl;
				Size sz = tfsc.ContentSize;
				sz.Width += tfsc.Margin.Left + tfsc.Margin.Right;
				sz.Height += tfsc.Margin.Top + tfsc.Margin.Bottom;

				ScrollViewer sv = (ScrollViewer)stg.FindName("tfsc_sv");
				sz.Width += sv.ComputedVerticalScrollBarVisibility == System.Windows.Visibility.Collapsed ? 4 : 19;
				sz.Height += sv.ComputedHorizontalScrollBarVisibility == System.Windows.Visibility.Collapsed ? 21 : 20;

				Size ds = new Size(DockSite.Workspace.ActualWidth, DockSite.Workspace.ActualHeight);
				sz.Width = Math.Min(sz.Width, ds.Width - 40);
				sz.Height = Math.Min(sz.Height, ds.Height - 40);

				this.SetValue(DockSite.ControlSizeProperty, sz);
			}
		}

		public override void Print(PrintDialog pd)
		{
			(this.Content as uc_tfs).Print(pd);
		}

#if false
		protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
		{
			String n = (this.t != null) ? t.Name : "??";
			Debug.WriteLine("{0:X8} {1} {2} {3} -> {4}", this.GetHashCode(), n, e.Property, e.OldValue, e.NewValue);
			base.OnPropertyChanged(e);
		}
#endif
	};
#endif

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class InteractiveWindow : AgreeDocument
	{
		Stopwatch stopw;
		public TextBlock display;
		TextBox input;
		Label prompt;
		Button execute;

		ISysObj current_obj;

		MainWindow w;

		List<String> history = new List<String>();
		int i_history = 0;

		public InteractiveWindow(MainWindow w, ISysObj def)
		{
			this.w = w;
			this.FontSize = 15;

			Grid gd = new Grid();

			gd.ColumnDefinitions.Add(new ColumnDefinition());

			// scrolling message area
			RowDefinition rd = new RowDefinition();
			gd.RowDefinitions.Add(rd);
			// splitter bar
			rd = new RowDefinition();
			rd.Height = GridLength.Auto;
			gd.RowDefinitions.Add(rd);
			// input area
			rd = new RowDefinition();
			rd.Height = GridLength.Auto;
			gd.RowDefinitions.Add(rd);

			display = new TextBlock();
			display.Margin = new Thickness(4);
			ScrollViewer sv = new ScrollViewer();
			sv.SetValue(Grid.ColumnProperty, 0);
			sv.SetValue(Grid.RowProperty, 0);
			sv.Content = display;
			gd.Children.Add(sv);

			GridSplitter spl = new GridSplitter();
			spl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
			spl.VerticalAlignment = System.Windows.VerticalAlignment.Center;
			spl.BorderThickness = new Thickness(0, 1, 0, 1);
			spl.BorderBrush = new SolidColorBrush(Color.FromRgb(0xe0, 0xe0, 0xe0));
			spl.Style = (Style)this.FindResource("gridSplitterStyle");
			spl.Height = 7;
			spl.SetValue(Grid.ColumnProperty, 0);
			spl.SetValue(Grid.RowProperty, 1);
			gd.Children.Add(spl);

			// input area
			{
				DockPanel isp = new DockPanel();
				//isp.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
				isp.Width = double.NaN;

				prompt = new Label();
				prompt.Width = 50;
				PromptText = "sys";
				prompt.Margin = new Thickness(0, 3, 0, 0);
				prompt.SetValue(DockPanel.DockProperty, System.Windows.Controls.Dock.Left);
				isp.Children.Add(prompt);

				current_obj = def;

				// this must be attached to the dock next (before the central input area)
				execute = new Button();
				execute.Margin = new Thickness(0, 5, 5, 0);
				execute.Content = "execute";
				execute.SetValue(DockPanel.DockProperty, System.Windows.Controls.Dock.Right);
				execute.VerticalAlignment = System.Windows.VerticalAlignment.Top;
				execute.Click += new RoutedEventHandler((s, e) =>
					{
						SubmitCommand(input.Text);
					});
				isp.Children.Add(execute);

				input = new TextBox();
				input.Margin = new Thickness(5);
				input.PreviewKeyDown += (s, e) =>
					{
						if (e.Key == Key.Up && i_history > 0)
						{
							input.Text = history[--i_history];
						}
						else if (e.Key == Key.Down && i_history < history.Count - 1)
						{
							input.Text = history[++i_history];
						}
						else
							return;
						e.Handled = true;
					};
				input.KeyDown += (s, e) =>
				{
					if (e.Key == Key.Escape)
						input.Text = String.Empty;
					if (e.Key == System.Windows.Input.Key.Enter)
						SubmitCommand(input.Text);
					else if (e.Key == System.Windows.Input.Key.L && Keyboard.Modifiers == ModifierKeys.Control)
						SubmitCommand("cls");
				};
				isp.Children.Add(input);

				isp.SetValue(Grid.ColumnProperty, 0);
				isp.SetValue(Grid.RowProperty, 2);
				gd.Children.Add(isp);

				this.GotFocus += new RoutedEventHandler((o, e) => { input.Focus(); });
			}

			this.Content = gd;
			this.stopw = Stopwatch.StartNew();
			this.Title = "Interactive";
		}

		public void Clear()
		{
			display.Text = String.Empty;
		}

		public CommandResultResponder CurrentHandler
		{
			get
			{
				return w.cmd_responders[current_obj];
			}
			set
			{
				current_obj = value.so;
				PromptText = value.so.SysObjName;
			}
		}

		string prompt_text;
		String PromptText
		{
			get
			{
				return prompt_text; ;
			}
			set
			{
				prompt_text = value;
				prompt.Content = prompt_text + " >";
			}
		}

		void SubmitCommand(String s)
		{
			if (s == "tsdb hike")
			{
				MyDockSite mds = MyDockSite.g_docksite;
				ItsdbDocument idoc = new ItsdbDocument(current_obj);
				mds.wksp.tmc.Items.Add(idoc);
				idoc.Activate();
				return;
			}
			else if (s == "all types")
			{
				MyDockSite mds = MyDockSite.g_docksite;
				AllTypesWindow idoc = new AllTypesWindow(current_obj as Grammar);
				mds.wksp.tmc.Items.Add(idoc);
				idoc.Activate();
				return;
			}
			else if (s == "a U d")
			{
				MyDockSite mds = MyDockSite.g_docksite;
				Edge e;
				Grammar g = current_obj as Grammar;
				Unification.Unifier uh = new Unification.Unifier(g.loadtray);
				uh.Unify(g.tm.type_dict["a"].Expanded, g.tm.type_dict["d"].Expanded, out e);
				TfsEdge te = g.loadtray.CreateTfs(e);
				ExpandedWindow idoc = new ExpandedWindow(te);
				idoc.Title = "a ⊔ d";
				mds.wksp.tmc.Items.Add(idoc);
				idoc.Activate();
				return;
			}


			history.Add(s);
			i_history = history.Count;
			input.Clear();
			WriteLine("<span style='color:#808080;'>{0}</span> > <span style='color:#800000;'>{1}</span>", current_obj.SysObjName, s);

			CurrentHandler.QueueResultContinuation(new SysCommands.CmdTokInteractive(current_obj, s));
		}

		public void Write(String s, params Object[] args)
		{
			//(this.Content as TextBox).Text += String.Format(s,args);
		}
		public void WriteLine(CommandToken x, String s, params Object[] args)
		{
			String ss;
			SysCommands.CmdTokDisplayMessage xm = x as SysCommands.CmdTokDisplayMessage;
			if (xm != null)
			{
				if (!xm.IsComplete)
					throw new Exception();
				ss = xm.Task.Result;
			}
			else
			{
				//ss = String.Format("<span style='color:#808080;'>{0,8:d\\:hh\\:mm\\:ss}</span> ", stopw.Elapsed);
				ss = String.Empty;

				if (x != null)
					ss += String.Format("<span style='color:#bb9d13;'>[{0}]</span> ", (x.Context ?? x.SystemInstance).SysObjName);

				ss += String.Format(s, args) + Environment.NewLine;
			}

			//display.Inlines.AddRange(ParseFormatting(ss));
			display.Inlines.Add(new HTMLtoWPF().ParseFormatting(ss));
			((this.Content as Grid).Children[0] as ScrollViewer).ScrollToBottom();
		}
		public void WriteLine(String s, params Object[] args)
		{
			WriteLine(null, s, args);
		}

		public IEnumerable<Run> ParseFormatting(String s)
		{
			Stack<Brush> stk_b = new Stack<Brush>();
			Brush b_cur = Brushes.Black;

			String[] parts = s.Split(new Char[] { '\ue099' });
			int i = 0;
			while (i < parts.Length)
			{
				String part = parts[i++];
				if (i > 0)
				{
					if (part.Length >= 7 && part[0] == '-')
					{
						int i_color;
						if (int.TryParse(part.Substring(1, 6), NumberStyles.HexNumber, null, out i_color))
						{
							stk_b.Push(b_cur);
							b_cur = new SolidColorBrush(Color.FromRgb((byte)(i_color >> 16), (byte)(i_color >> 8), (byte)(i_color)));
							part = part.Substring(7);
						}
					}
					else if (stk_b.Count > 0)
					{
						b_cur = stk_b.Pop();
					}
				}
				Run r = new Run(part);
				r.Foreground = b_cur;
				yield return r;
			}
		}


	}


	class HTMLtoWPF
	{
		Dictionary<String, Func<Span, Dictionary<String, String>, Dictionary<String, String>, Span>> tag_dict;

		struct StackEntry
		{
			public StackEntry(String tag, Span obj)
			{
				this.tag = tag;
				this.obj = obj;
			}
			public String tag;
			public Span obj;
		};


		public HTMLtoWPF()
		{
			tag_dict = new Dictionary<String, Func<Span, Dictionary<String, String>, Dictionary<String, String>, Span>>
				{
					{ "a",  (cur,avd,sd) =>
								{
									if (avd == null)
										return null;
									Hyperlink h = new Hyperlink();
									foreach (var kvp in avd)
									{
										if (kvp.Key=="href")
										{
											h.NavigateUri = new Uri(kvp.Value);
										}
									}
									return h;
								}
					},
					{ "i",  (cur,avd,sd) =>
								{
									Span sp = new Span();
									sp.FontStyle = FontStyles.Italic;
									return sp;
								}
					},
					{ "b",  (cur,avd,sd) =>
								{
									Span sp = new Span();
									sp.FontWeight = FontWeights.Bold;
									return sp;
								}
					},
					{ "u",  (cur,avd,sd) =>
								{
									Span sp = new Span();
									sp.TextDecorations.Add(TextDecorations.Underline);
									return sp;
								}
					},
					{ "br",  (cur,avd,sd) =>
								{
									cur.Inlines.Add(new LineBreak());
									return null;
								}
					},
					{ "span",  (cur,avd,sd) =>
								{
									if (sd == null)
										return null;
									Span sp = new Span();
									foreach (var kvp in sd)
									{
										if (kvp.Key=="color")
										{
											try {
												Color z = (Color)ColorConverter.ConvertFromString(kvp.Value);
												sp.Foreground = new SolidColorBrush(z);
											}
											catch
											{
											}
										}
										else if (kvp.Key=="font-weight" && kvp.Value=="bold")
										{
											sp.FontWeight = FontWeights.Bold;
										}
									}
									return sp;
								}
					},


				};
		}

		enum TagType { None = 0, Open, Close, AutoClose };

		Stack<StackEntry> stk = new Stack<StackEntry>();

		static Char[] tag_term = { ' ', '\t', '\r', '\n' };
		static Char[] style_split = { ':', ';' };

		public Span ParseFormatting(String s)
		{
			Span sp_base = new Span();
			Span sp_cur = sp_base;

			/// remove control characters
			s = s.Select(ch => ch < ' ' ? ' ' : ch).NewString();

			/// condense spaces
			int ix;
			while ((ix = s.IndexOf("  ")) != -1)
				s = s.Remove(ix, 1);

			/// find HTML tags
			String[] parts = s.Split(new Char[] { '<' });

			for (int i = 0; i < parts.Length; i++)
			{
				String part = parts[i];
				if (i > 0)
				{
					ix = part.IndexOf('>');
					if (ix < 1)
					{
						sp_cur.Inlines.Add(new Run("HTML parse error, missing closing tag '>' or empty HTML tag"));
						break;
					}
					/// Get the HTML tag type
					String s_tag = part.Remove(ix).Trim().ToLower();
					part = part.Substring(ix + 1);

					/// is it a closing tag?
					TagType found_tag_type = TagType.Open;
					if (s_tag[0] == '/')
					{
						found_tag_type = TagType.Close;
						s_tag = s_tag.Substring(1);
					}
					else if (s_tag.EndsWith("/"))
					{
						found_tag_type = TagType.AutoClose;
						s_tag = s_tag.Remove(s_tag.Length - 1).Trim();
					}

					String s_av = null;
					ix = s_tag.IndexOfAny(tag_term);
					if (ix != -1)
					{
						s_av = s_tag.Substring(ix + 1).Trim();
						s_tag = s_tag.Remove(ix).Trim();
					}

					if (found_tag_type == TagType.Open || found_tag_type == TagType.AutoClose)
					{
						/// get attribute-value pairs if any
						Dictionary<String, String> attribute_values = null;
						Dictionary<String, String> styles = null;
						if (s_av != null)
						{
							var rgav = s_av.Split('=');
							if ((rgav.Length & 1) > 0)
								throw new Exception();

							attribute_values = rgav.PairOff().ToDictionary(av => av.Key, av => av.Value.Trim('\'', '\"'));

							String sp;
							if (attribute_values.TryGetValue("style", out sp))
							{

								var rgsp = sp.Split(style_split, StringSplitOptions.RemoveEmptyEntries);
								if ((rgsp.Length & 1) > 0)
									throw new Exception();

								styles = rgsp.PairOff().ToDictionary(av => av.Key.Trim(), av => av.Value.Trim());
							}
						}

						Func<Span, Dictionary<String, String>, Dictionary<String, String>, Span> open_func;
						if (!tag_dict.TryGetValue(s_tag, out open_func))
						{
							sp_cur.Inlines.Add(new Run(String.Format("HTML parse error, unrecognized tag '{0}'", s_tag)));
							break;
						}

						Span ns = open_func(sp_cur, attribute_values, styles);
						if (ns != null && found_tag_type != TagType.AutoClose)
						{
							stk.Push(new StackEntry(s_tag, sp_cur));
							sp_cur.Inlines.Add(ns);

							sp_cur = ns;
						}
					}
					else if (found_tag_type == TagType.Close)
					{
						if (stk.Count == 0)
						{
							sp_cur.Inlines.Add(new Run(String.Format("HTML parse error, can't close tag '{0}' because there are no tags open", s_tag)));
							break;
						}
						if (stk.Peek().tag != s_tag)
						{
							sp_cur.Inlines.Add(new Run(String.Format("HTML parse error, can't close tag '{0}' because it is not the pending tag", s_tag)));
							break;
						}
						sp_cur = stk.Pop().obj;
					}
				}

				/// Add the unformatted text
				if (part.Length > 0)
					sp_cur.Inlines.Add(new Run(part));
			}
			sp_cur.Inlines.Add(new LineBreak());

			if (stk.Count != 0)
				throw new Exception();

			return sp_base;
		}

	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	class T3dWindow : AgreeGrammarDocument
	{
		readonly agree.Type t;

		public agree.Type Type { get { return t; } }

		public T3dWindow(agree.Type t)
			: base(t.mgr.g)
		{
			this.t = t;
			Zoom3D stg = new Zoom3D(g, t.Expanded, MainWindow.w);
			stg.ClipToBounds = true;

			this.Title = String.Format("{0}: 3d", t.Name);
			this.Description = "Expanded typed feature structure for ";
			this.Content = stg;
		}

	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	class ParseChartWindow : AgreeGrammarDocument
	{
		readonly ParseChart pc;

		public ParseChart ParseChart { get { return pc; } }

		public ParseChartWindow(ParseChart pc, IEnumerable<ParseChart.IParseChartEdge> use_edges)
			: base(pc.Grammar)
		{
			this.pc = pc;

			String title = String.Format("{0}", pc.SysObjName);
			ParseChart.CompletedParse cp = null;
			if (use_edges != null && use_edges.OfType<ParseChart.CompletedParse>().Count() == 1)
			{
				cp = use_edges.OfType<ParseChart.CompletedParse>().First();
				title += "-" + cp.Contents.ToString();
			}
			this.Title = title;

			this.Description = pc.SysObjDescription;

			ScrollViewer sv = new ScrollViewer();
			sv.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
			sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;

			VizParseChart vpc = new VizParseChart(pc, use_edges);
			vpc.Margin = new Thickness(10);
			if (cp == null)
			{
				sv.Content = vpc;
			}
			else
			{
				sv.Content = Anon<StackPanel>.New(sp =>
					{
						sp.Orientation = Orientation.Vertical;
						sp.Children.Add(vpc);
						sp.Children.Add(new VizParseTree(pc, cp));
					});
			}

			this.Content = sv;

			//		stg.TfsControl.SizeChanged += new SizeChangedEventHandler(TfsControlSizeChanged);

			this.KeyDown += (sender, e) =>
			{
				if (e.Key == Key.Escape)
					this.Close();
			};
		}

		//public override void Print(PrintDialog pd)
		//{
		//    (this.Content as uc_tfs).Print(pd);
		//}

		class VizParseChart : Grid
		{
			public VizParseChart(ParseChart pc, IEnumerable<ParseChart.IParseChartEdge> use_edges)
			{
				this.SetValue(RoundedRectangle.ContainerParentProperty, true);

				Border bthis = new Border();
				this.Children.Add(bthis);

				bthis.BorderBrush = Brushes.Black;
				bthis.BorderThickness = new Thickness(0, 0, 1, 1);
				//				bthis.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
				bthis.VerticalAlignment = System.Windows.VerticalAlignment.Top;
				bthis.SetValue(TextBlock.FontSizeProperty, 11.8);

				StackPanel rows_stack = new StackPanel();
				rows_stack.Orientation = Orientation.Vertical;
				//				rows_stack.VerticalAlignment = System.Windows.VerticalAlignment.Top;
				//			rows_stack.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
				//rows_stack.MaxWidth = 1200;

				if (use_edges == null)
					use_edges = pc.AllEdges();

				var lu0 = use_edges.OfType<ParseChart.CompletedParse>().ToLookup(pe => pe.ChartSpan);
				var lu1 = use_edges.Where(pe => pe.GetType() != typeof(LexicalAnalysis.AnalysisStack) &&
												pe.GetType() != typeof(ParseChart.CompletedParse))
									.ToLookup(pe => pe.ChartSpan);
				var lu2 = use_edges.OfType<LexicalAnalysis.AnalysisStack>().ToLookup(pe => pe.ChartSpan);
				var lu3 = pc.InputTokens.Distinct(tok => tok.ChartSpan).ToDictionary(tok => tok.ChartSpan);

				for (int i = 0; i < pc.ColumnCount; i++)
				{
					uint span = (uint)(pc.ColumnCount - i);

					bool f_spantext = i < pc.ColumnCount - 1;

					int i_subrows = 0;
					int b_subrows = 0;

					if (f_spantext)
					{
						i_subrows++;
						b_subrows |= 0x01;
					}
					if (lu0.Any(g => g.Key.Length == (int)span))
					{
						i_subrows++;
						b_subrows |= 0x02;
					}
					if (lu1.Any(g => g.Key.Length == (int)span))
					{
						i_subrows++;
						b_subrows |= 0x04;
					}
					if (lu2.Any(g => g.Key.Length == (int)span))
					{
						i_subrows++;
						b_subrows |= 0x08;
					}
					if (lu3.Any(g => g.Key.Length == (int)span))
					{
						i_subrows++;
						b_subrows |= 0x10;
					}

					if (i_subrows > 0)
					{
						Grid g_row = new Grid();
						for (int j = 0; j < i_subrows; j++)
							g_row.RowDefinitions.Add(new RowDefinition());

						for (int j = 0; j <= i; j++)
						{
							ColumnDefinition cd = new ColumnDefinition();
							g_row.ColumnDefinitions.Add(cd);

							glue.Tokenization.Span tsp = new glue.Tokenization.Span(j, span);
							String stxt = pc._TokenSet.Source.MinimalSpanText(tsp);

							int i_subrow = 0;

							if ((b_subrows & 0x01) > 0)
							{
								Border cc = new Border();
								cc.SetValue(Grid.ColumnProperty, j);
								cc.SetValue(Grid.RowProperty, i_subrow++);
								cc.BorderBrush = Brushes.Black;
								cc.BorderThickness = new Thickness(1, 1, 0, 0);
								TextBlock tb = new TextBlock(new Run(stxt));
								tb.FontSize = 14;
								tb.Margin = new Thickness(5, 5, 5, 0);
								cc.Child = tb;
								g_row.Children.Add(cc);
							}

							if ((b_subrows & 0x02) > 0)
							{
								ChartCell cc = new ChartCell();
								if (f_spantext && i_subrow == 1)
									cc.BorderThickness = new Thickness(1, 0, 0, 0);
								cc.SetValue(Grid.ColumnProperty, j);
								cc.SetValue(Grid.RowProperty, i_subrow++);

								ParseChart.CompletedParse[] rgpe = lu0[new glue.Tokenization.Span(j, span)].ToArray();
								if (rgpe.Length > 0)
								{
									cc.Padding = new Thickness(2.5);

									foreach (ParseChart.CompletedParse pe in rgpe)
									{
										TfsEdge te = pe.Contents;
										RoundedRectangle rr = new LocalRoundedRect(Brushes.Honeydew, pe, String.Format("{0:X6}\r\n{1}", te.TfsId, te.Type.Name));
										cc.AddItem(rr);
									}
								}
								g_row.Children.Add(cc);
							}

							if ((b_subrows & 0x04) > 0)
							{
								ChartCell cc = new ChartCell();
								if (f_spantext && i_subrow == 1)
									cc.BorderThickness = new Thickness(1, 0, 0, 0);
								cc.SetValue(Grid.ColumnProperty, j);
								cc.SetValue(Grid.RowProperty, i_subrow++);

								ParseChart.IParseChartEdge[] rgpe = lu1[new glue.Tokenization.Span(j, span)].ToArray();
								if (rgpe.Length > 0)
								{
									cc.Padding = new Thickness(2.5);

									foreach (ParseChart.IParseChartEdge pe in rgpe)
									{
										TfsEdge te = pe.Contents;
										RoundedRectangle rr = new LocalRoundedRect(Brushes.Beige, pe, String.Format("{0:X6}\r\n{1}", te.TfsId, te.Type.Name));
										cc.AddItem(rr);

										//Binding sss0 = new Binding();
										//sss0.Source = rr;
										//sss0.Path = new PropertyPath("Center");

										//Binding sss1 = new Binding();
										//sss1.Source = rr;
										//sss1.Path = new PropertyPath("Top");

										//Line zz = new Line();
										//zz.X1 = 0;
										//zz.Y1 = 0;
										//zz.SetBinding(Line.X2Property, sss0);
										//zz.SetBinding(Line.Y2Property, sss1);
										//zz.Stroke = Brushes.Black;
										//zz.StrokeThickness = 1;
										//this.Children.Add(zz);
									}
								}
								g_row.Children.Add(cc);
							}

							if ((b_subrows & 0x08) > 0)
							{
								ChartCell cc = new ChartCell();
								if (f_spantext && i_subrow == 1)
									cc.BorderThickness = new Thickness(1, 0, 0, 0);
								cc.SetValue(Grid.ColumnProperty, j);
								cc.SetValue(Grid.RowProperty, i_subrow++);

								LexicalAnalysis.AnalysisStack[] rgpe = lu2[new glue.Tokenization.Span(j, span)].ToArray();
								if (rgpe.Length > 0)
								{
									cc.Padding = new Thickness(2.5);

									foreach (LexicalAnalysis.AnalysisStack stk in rgpe)
									{
										RoundedRectangle rr = new LocalRoundedRect(Brushes.MistyRose, stk);

										rr.InnerChild = Anon<StackPanel>.New(sp =>
										{
											sp.Orientation = Orientation.Vertical;
											sp.Children.Add(new TextBlock(new Run(String.Format("{0:X6}", stk.Contents.TfsId))));

											foreach (var la in ((IList<LexicalAnalysis.LexicalTransform>)stk).Reverse())
											{
												sp.Children.Add(Anon<TextBlock>.New(x =>
												{
													x.Padding = new Thickness(1.5);
													x.Text = la.license.Name;

												}));
											}
										});
										cc.AddItem(rr);
									}
								}
								g_row.Children.Add(cc);
							}

							if ((b_subrows & 0x10) > 0)
							{
								ChartCell cc = new ChartCell();
								if (f_spantext && i_subrow == 1)
									cc.BorderThickness = new Thickness(1, 0, 0, 0);
								cc.SetValue(Grid.ColumnProperty, j);
								cc.SetValue(Grid.RowProperty, i_subrow++);

								ParseChart.IParseChartToken tok;
								if (lu3.TryGetValue(tsp, out tok))
								{
									cc.Padding = new Thickness(2.5);

									RoundedRectangle rr = new RoundedRectangle(tok.Text);
									((TextBlock)rr.InnerChild).FontSize = 14;
									rr.CornerRadius = new System.Windows.CornerRadius(2);
									rr.Background = Brushes.AntiqueWhite;
									rr.Margin = new Thickness(2.5);
									rr.Padding = new Thickness(8, 0, 8, 0);
									rr.BorderBrush = Brushes.Gray;
									((WrapPanel)((Border)cc).Child).HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
									cc.AddItem(rr);
								}
								g_row.Children.Add(cc);
							}
						}
						rows_stack.Children.Add(g_row);
					}
				}
				bthis.Child = rows_stack;
			}
		};

		class LocalRoundedRect : RoundedRectangle
		{
			public LocalRoundedRect(Brush br, ParseChart.IParseChartEdge pce, String txt)
				: base(txt)
			{
				Init(br, pce);
			}
			public LocalRoundedRect(Brush br, ParseChart.IParseChartEdge pce)
			{
				Init(br, pce);
			}
			void Init(Brush br, ParseChart.IParseChartEdge pce)
			{
				CornerRadius = new System.Windows.CornerRadius(2);
				Margin = new Thickness(2.5);
				BorderBrush = Brushes.Gray;
				VerticalAlignment = System.Windows.VerticalAlignment.Top;
				Background = br;

				ContextMenu = Anon<ContextMenu>.New(cm =>
					{
						cm.Items.Add(Anon<MenuItem>.New(mi =>
						{
							mi.Header = "TFS";
							mi.Click += (o, e) =>
							{
								MyDockSite mds = MyDockSite.g_docksite;
								var etw = new ExpandedWindow(pce.Contents);
								mds.wksp.tmc.Items.Add(etw);
								etw.Activate();
							};
						}));
						ParseChart.DerivedPassiveEdge dpe = pce as ParseChart.DerivedPassiveEdge;
						if (dpe != null && dpe.Daughters.Count > 0)
						{
							MenuItem mix = new MenuItem();
							mix.Header = "Derivation daughters";
							cm.Items.Add(mix);

							foreach (var d in dpe.Daughters)
							{
								mix.Items.Add(Anon<MenuItem>.New(xmi =>
								{
									xmi.Header = String.Format("{0}", d.Contents.SysObjName);
									xmi.Click += (o, e) =>
									{
										MyDockSite mds = MyDockSite.g_docksite;
										var etw = new ExpandedWindow(d.Contents);
										mds.wksp.tmc.Items.Add(etw);
										etw.Activate();
									};
								}));
							}
						}
						ParseChart.CompletedParse cp = pce as ParseChart.CompletedParse;
						if (cp != null)
						{
							cm.Items.Add(Anon<MenuItem>.New(mi =>
							{
								StartSymbol ss = cp.MatchedStartSymbol as StartSymbol;
								mi.Header = String.Format("Start symbol: {0}", ss.Name.Replace("_","__"));
								mi.Click += (o, e) =>
								{
									MyDockSite mds = MyDockSite.g_docksite;
									var etw = new ExpandedWindow(ss);
									mds.wksp.tmc.Items.Add(etw);
									etw.Activate();
								};
							}));
						}
					});
			}
		}


		class ChartCell : Border
		{
			WrapPanel wp;

			public ChartCell()
			{
				wp = new WrapPanel();

				this.Child = wp;
				this.BorderBrush = Brushes.Black;
				this.BorderThickness = new Thickness(1, 1, 0, 0);
			}

			public void AddItem(UIElement el)
			{
				wp.Children.Add(el);
			}


			//class XWrapPanel : WrapPanel
			//{
			//    protected override Size ArrangeOverride(Size finalSize)
			//    {
			//        Size sz = base.ArrangeOverride(finalSize);

			//        foreach (var ch in InternalChildren.OfType<FrameworkElement>())
			//        {
			//            Vector v = VisualTreeHelper.GetOffset(ch);
			//            Point pt = new Point(v.X,v.Y);

			//            pt = ch.TransformToAncestor(this).Transform(pt);
			//            Debug.Print("{0} {1} {2}",ch.GetType().Name, pt.X, pt.Y);
			//        }
			//        return sz;
			//    }
			//};


		};
	};

	public class ParseTreeWindow : AgreeGrammarDocument
	{
		VizParseTree tree_layout_panel;

		public ParseTreeWindow(ParseChart pc, ParseChart.IParseChartEdge pce)
			: base(pc.Grammar)
		{
			this.Title = pce.Contents.Name;

			tree_layout_panel = new VizParseTree(pc, pce);

			this.Content = tree_layout_panel;
		}

		public ParseChart.IParseChartEdge ParseTree { get { return tree_layout_panel.ParseTree; } }
	};



	public class MultiParseTreeWindow : AgreeGrammarDocument
	{
		WrapPanel wp;
		ParseChart pc;
		public MultiParseTreeWindow(ParseChart pc)
			: base(pc.Grammar)
		{
			this.pc = pc;
			this.Title = pc.SysObjName;

			wp = new WrapPanel();
			wp.Orientation = Orientation.Horizontal;
			this.Content = wp;

			foreach (ParseChart.CompletedParse cp in pc.CompletedParses)
			{
				wp.Children.Add(new VizParseTree(pc, cp));
			}

			//Loaded += new RoutedEventHandler(MultiParseTreeWindow_Loaded);
		}

		public ParseChart ParseChart { get { return pc; } }

		void MultiParseTreeWindow_Loaded(object sender, RoutedEventArgs e)
		{
			foreach (FrameworkElement fe in wp.Children)
			{
				//	SaveToPng(fe);
			}
		}



	};


}