using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;
using System.Windows.Markup;

namespace OPlanner {

	public class DescriptionSymbol {

		private List<int> targetColumns;
		public List<int> TargetColumns {
			get {
				return targetColumns;
			}
		}
		private string symbolCode;
		public string SymbolCode {
			get {
				return symbolCode;
			}
		}
		private string symbolXml;
		public string Text;
		private double rotation;
		private DescriptionManager parent;
		private string baseSymbolCode;

		public DescriptionSymbol(DescriptionManager parentManager) {
			rotation = 0;
			parent = parentManager;
			targetColumns = new List<int>();
		}

		public FrameworkElement GetSymbol(double descriptionSize, Brush mainBrush) {
			string xml = symbolXml;
			if (baseSymbolCode != null && baseSymbolCode != "") {
				DescriptionSymbol target = parent.GetSymbolByCode(baseSymbolCode);
				if (target == null) {
					return null;
				}
				xml = target.symbolXml;
			}
			if (xml == null) {
				return null;
			}
			FrameworkElement symbol;
			ParserContext pc = new ParserContext();
			pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
			pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
			XmlTextReader xmlReader;
			object obj;
			try {
				xmlReader = new XmlTextReader(xml, XmlNodeType.Element, pc);
				obj = XamlReader.Load(xmlReader);
			} catch (Exception) {
				return null;
			}
			if (!(obj is FrameworkElement)) {
				return null;
			}
			symbol = (FrameworkElement)obj;
			double scaleX = descriptionSize / symbol.Width;
			double scaleY = descriptionSize / symbol.Height;
			if (scaleX == double.NaN || scaleY == double.NaN) {
				return null;
			}
			if (rotation != 0) {
				symbol.RenderTransform = new RotateTransform(rotation, (symbol.Width / 2) * scaleX, (symbol.Height / 2) * scaleY);
			}
			symbol.LayoutTransform = new ScaleTransform(scaleX, scaleY);
			symbol.Resources.Add("descriptionBrush", mainBrush);
			return symbol;
		}

		public void Clear() {
			symbolXml = null;
			targetColumns.Clear();
		}

		public bool Load(XmlNode node) {
			Clear();
			XmlAttribute attribute;
			attribute = node.Attributes["TargetColumns"];
			if (attribute == null) {
				return false;
			}
			string[] cols = attribute.Value.Split(',');
			int col;
			for (int i = 0; i < cols.Length; i++) {
				if (!int.TryParse(cols[i], out col)) {
					return false;
				}
				if (col < 3 || col > 8) {
					return false;
				}
				targetColumns.Add(col);
			}
			attribute = node.Attributes["SymbolCode"];
			if (attribute == null) {
				return false;
			}
			symbolCode = attribute.Value;
			if (node.ChildNodes.Count > 0) {
				symbolXml = node.FirstChild.OuterXml;
			}
			attribute = node.Attributes["Text"];
			if (attribute != null) {
				Text = attribute.Value;
			}
			attribute = node.Attributes["BaseSymbol"];
			if (attribute != null) {
				baseSymbolCode = attribute.Value;
			}
			attribute = node.Attributes["Rotation"];
			if (attribute != null) {
				double rot;
				if (double.TryParse(attribute.Value, out rot)) {
					rotation = rot;
				}
			}
			return true;
		}

	}

	public class DescriptionManager {

		private List<DescriptionSymbol> symbols;

		public DescriptionManager() {
			symbols = new List<DescriptionSymbol>();
		}

		public void Clear() {
			symbols.Clear();
		}

		public bool Load(string fileName) {
			Clear();
			XmlDocument doc = new XmlDocument();
			try {
				doc.Load(Application.GetRemoteStream(new Uri("pack://siteoforigin:,,,/" + fileName)).Stream);
			} catch (Exception) {
				return false;
			}
			XmlElement root = doc.DocumentElement;
			if (root.Name != "DescriptionSymbols") {
				return false;
			}
			XmlNodeList nodes = root.SelectNodes("DescriptionSymbol");
			DescriptionSymbol symbol;
			for (int i = 0; i < nodes.Count; i++) {
				symbol = new DescriptionSymbol(this);
				if (symbol.Load(nodes[i])) {
					symbols.Add(symbol);
				}
			}
			return true;
		}

		public List<DescriptionSymbol> GetSymbols(int column) {
			List<DescriptionSymbol> list = new List<DescriptionSymbol>();
			for (int i = 0; i < symbols.Count; i++) {
				if (symbols[i].TargetColumns.Contains(column)) {
					list.Add(symbols[i]);
				}
			}
			return list;
		}

		public DescriptionSymbol GetSymbolByCode(string code) {
			if (code == null || code == "") {
				return null;
			}
			for (int i = 0; i < symbols.Count; i++) {
				if (symbols[i].SymbolCode == code) {
					return symbols[i];
				}
			}
			return null;
		}

		public FrameworkElement GetDescriptions(OPlannerData data, Brush mainBrush, double descriptionSize, int maxRows, string title) {
			StackPanel outerPanel = new StackPanel();
			outerPanel.Orientation = Orientation.Horizontal;
			int outerColumnNum = 0;
			int overallOrderedObjectNum = 0;
			RowDefinition rowDefinition;
			List<OBaseObject> tempList = new List<OBaseObject>(data.OObjects);
			tempList.Sort(OPlannerHelper.CompareOBaseObjects);
			while (true) {
				int currentRowNum = 0;
				Border border = new Border();
				border.Background = Brushes.White;
				border.BorderBrush = mainBrush;
				border.BorderThickness = new Thickness(1);
				border.SnapsToDevicePixels = true;
				border.HorizontalAlignment = HorizontalAlignment.Left;
				border.VerticalAlignment = VerticalAlignment.Top;
				if (outerColumnNum > 0) {
					border.Margin = new Thickness(3, 0, 0, 0);
				}
				outerPanel.Children.Add(border);
				Grid grid = new Grid();
				border.Child = grid;
				int numDescriptionRows = 0;
				int numRows = 0;
				if (outerColumnNum == 0) {
					FrameworkElement titleRow = GetDescriptionTitle(mainBrush, descriptionSize, title);
					if (titleRow != null) {
						Grid.SetRow(titleRow, 0);
						grid.Children.Add(titleRow);
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numRows++;
						currentRowNum++;
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(1);
						grid.RowDefinitions.Add(rowDefinition);
						Rectangle rectangle = new Rectangle();
						rectangle.Fill = mainBrush;
						Grid.SetRow(rectangle, numRows);
						grid.Children.Add(rectangle);
						numRows++;
					}
					FrameworkElement header = GetDescriptionHeader(null, mainBrush, descriptionSize);
					Grid.SetRow(header, numRows);
					grid.Children.Add(header);
					rowDefinition = new RowDefinition();
					rowDefinition.Height = new GridLength(descriptionSize);
					grid.RowDefinitions.Add(rowDefinition);
					numRows++;
					currentRowNum++;
				}
				for (int i = overallOrderedObjectNum; i < tempList.Count; i++) {
					if (maxRows > 0) {
						if (currentRowNum >= maxRows) {
							break;
						}
					}
					bool addLine = false;
					int rowPos = numRows;
					if (currentRowNum > 0) {
						rowPos++;
					}
					ISymbolDescription symbolDesc = (ISymbolDescription)tempList[i].GetObject(typeof(ISymbolDescription));
					ITextDescription textDesc = (ITextDescription)tempList[i].GetObject(typeof(ITextDescription));
					if (symbolDesc != null) {
						FrameworkElement row = GetDescriptionRow(tempList[i], mainBrush, descriptionSize, true);
						if (row != null) {
							addLine = true;
							Grid.SetRow(row, rowPos);
							grid.Children.Add(row);
						}
					}
					if (addLine) {
						if (numRows > 0) {
							rowDefinition = new RowDefinition();
							rowDefinition.Height = new GridLength(1);
							grid.RowDefinitions.Add(rowDefinition);
							Rectangle rectangle = new Rectangle();
							rectangle.Fill = mainBrush;
							Grid.SetRow(rectangle, numRows);
							grid.Children.Add(rectangle);
							numRows++;
						}
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numDescriptionRows++;
						numRows++;
					}
					overallOrderedObjectNum++;
					currentRowNum++;
				}
				if (overallOrderedObjectNum >= tempList.Count) {
					break;
				}
				outerColumnNum++;
			}
			return outerPanel;
		}

		public FrameworkElement GetDescriptions(Course course, Brush mainBrush, double descriptionSize, int maxRows, string title) {
			StackPanel outerPanel = new StackPanel();
			outerPanel.Orientation = Orientation.Horizontal;
			int numDescriptionColumns = 8;
			RowDefinition rowDefinition;
			int outerColumnNum = 0;
			int overallOrderedObjectNum = 0;
			while (true) {
				int currentRowNum = 0;
				Border border = new Border();
				border.Background = Brushes.White;
				border.BorderBrush = mainBrush;
				border.BorderThickness = new Thickness(1);
				border.SnapsToDevicePixels = true;
				border.HorizontalAlignment = HorizontalAlignment.Left;
				border.VerticalAlignment = VerticalAlignment.Top;
				if (outerColumnNum > 0) {
					border.Margin = new Thickness(3, 0, 0, 0);
				}
				outerPanel.Children.Add(border);
				Grid grid = new Grid();
				border.Child = grid;
				int numDescriptionRows = 0;
				int numRows = 0;
				if (outerColumnNum == 0) {
					FrameworkElement titleRow = GetDescriptionTitle(mainBrush, descriptionSize, title);
					if (titleRow != null) {
						Grid.SetRow(titleRow, 0);
						grid.Children.Add(titleRow);
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numRows++;
						currentRowNum++;
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(1);
						grid.RowDefinitions.Add(rowDefinition);
						Rectangle rectangle = new Rectangle();
						rectangle.Fill = mainBrush;
						Grid.SetRow(rectangle, numRows);
						grid.Children.Add(rectangle);
						numRows++;
					}
					FrameworkElement header = GetDescriptionHeader(course, mainBrush, descriptionSize);
					Grid.SetRow(header, numRows);
					grid.Children.Add(header);
					rowDefinition = new RowDefinition();
					rowDefinition.Height = new GridLength(descriptionSize);
					grid.RowDefinitions.Add(rowDefinition);
					numRows++;
					currentRowNum++;
				}
				for (int i = overallOrderedObjectNum; i < course.OrderedObjects.Count; i++) {
					if (maxRows > 0) {
						if (currentRowNum >= maxRows) {
							break;
						}
					}
					bool addLine = false;
					int rowPos = numRows;
					if (currentRowNum>0) {
						rowPos++;
					}
					ISymbolDescription symbolDesc = (ISymbolDescription)course.OrderedObjects[i].GetObject(typeof(ISymbolDescription));
					ITextDescription textDesc = (ITextDescription)course.OrderedObjects[i].GetObject(typeof(ITextDescription));
					if (symbolDesc != null) {
						FrameworkElement row = GetDescriptionRow(course.OrderedObjects[i], mainBrush, descriptionSize, false);
						if (row != null) {
							addLine = true;
							Grid.SetRow(row, rowPos);
							grid.Children.Add(row);
						}
					} else if (textDesc != null) {
						if (textDesc.TextDescription != null && textDesc.TextDescription != "") {
							addLine = true;
							TextBlock textBlock = new TextBlock();
							textBlock.Text = textDesc.TextDescription;
							textBlock.HorizontalAlignment = HorizontalAlignment.Center;
							textBlock.VerticalAlignment = VerticalAlignment.Center;
							textBlock.Foreground = mainBrush;
							Grid.SetRow(textBlock, rowPos);
							grid.Children.Add(textBlock);
						}
					} else if (course.OrderedObjects[i].GetObject(typeof(OFinish)) != null) {
						addLine = true;
						Grid finishGrid = new Grid();
						Grid.SetRow(finishGrid, rowPos);
						grid.Children.Add(finishGrid);
						Ellipse ellipse;
						ellipse = new Ellipse();
						ellipse.Stroke = mainBrush;
						ellipse.StrokeThickness = 1;
						ellipse.Margin = new Thickness(2, 0, 0, 0);
						ellipse.Width = descriptionSize - 2;
						ellipse.Height = descriptionSize - 2;
						ellipse.HorizontalAlignment = HorizontalAlignment.Left;
						ellipse.VerticalAlignment = VerticalAlignment.Center;
						finishGrid.Children.Add(ellipse);
						ellipse = new Ellipse();
						ellipse.Stroke = mainBrush;
						ellipse.StrokeThickness = 1;
						ellipse.Margin = new Thickness(0, 0, 2, 0);
						ellipse.Width = descriptionSize - 2;
						ellipse.Height = descriptionSize - 2;
						ellipse.HorizontalAlignment = HorizontalAlignment.Right;
						ellipse.VerticalAlignment = VerticalAlignment.Center;
						finishGrid.Children.Add(ellipse);
						ellipse = new Ellipse();
						ellipse.Stroke = mainBrush;
						ellipse.StrokeThickness = 1;
						ellipse.Margin = new Thickness(0, 0, 5, 0);
						ellipse.Width = descriptionSize - 8;
						ellipse.Height = descriptionSize - 8;
						ellipse.HorizontalAlignment = HorizontalAlignment.Right;
						ellipse.VerticalAlignment = VerticalAlignment.Center;
						finishGrid.Children.Add(ellipse);
						Polyline line;
						Point[] points;
						if (course.TapesToFinish == false) {
							line = new Polyline();
							line.Stroke = mainBrush;
							line.StrokeThickness = 1;
							points = new Point[3];
							points[0] = new Point(10, 2);
							points[1] = new Point(0, descriptionSize / 2);
							points[2] = new Point(10, descriptionSize - 2);
							line.Points = new PointCollection(points);
							line.Margin = new Thickness(descriptionSize, 0, 0, 0);
							line.HorizontalAlignment = HorizontalAlignment.Left;
							finishGrid.Children.Add(line);
						} else {
							line = new Polyline();
							line.Stroke = mainBrush;
							line.StrokeThickness = 1;
							points = new Point[2];
							points[0] = new Point(descriptionSize, descriptionSize / 2);
							points[1] = new Point(descriptionSize * (numDescriptionColumns - 1), descriptionSize / 2);
							line.Points = new PointCollection(points);
							line.HorizontalAlignment = HorizontalAlignment.Left;
							line.StrokeDashArray = new DoubleCollection(new double[] { 16, 6 });
							finishGrid.Children.Add(line);
						}
						line = new Polyline();
						line.Stroke = mainBrush;
						line.StrokeThickness = 1;
						points = new Point[3];
						points[0] = new Point(0, 2);
						points[1] = new Point(10, descriptionSize / 2);
						points[2] = new Point(0, descriptionSize - 2);
						line.Points = new PointCollection(points);
						line.Margin = new Thickness(0, 0, descriptionSize, 0);
						line.HorizontalAlignment = HorizontalAlignment.Right;
						finishGrid.Children.Add(line);
						TextBlock textBlock = new TextBlock();
						textBlock.Text = course.GetDistanceToFinish().ToString() + " m";
						textBlock.HorizontalAlignment = HorizontalAlignment.Center;
						textBlock.VerticalAlignment = VerticalAlignment.Center;
						textBlock.Foreground = mainBrush;
						textBlock.Background = Brushes.White;
						textBlock.Padding = new Thickness(2);
						finishGrid.Children.Add(textBlock);
					}
					if (addLine) {
						if (numRows > 0) {
							rowDefinition = new RowDefinition();
							rowDefinition.Height = new GridLength(1);
							grid.RowDefinitions.Add(rowDefinition);
							Rectangle rectangle = new Rectangle();
							rectangle.Fill = mainBrush;
							Grid.SetRow(rectangle, numRows);
							grid.Children.Add(rectangle);
							numRows++;
						}
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numDescriptionRows++;
						numRows++;
					}
					overallOrderedObjectNum++;
					currentRowNum++;
				}
				if (overallOrderedObjectNum >= course.OrderedObjects.Count) {
					break;
				}
				outerColumnNum++;
			}
			return outerPanel;
		}

		private FrameworkElement GetDescriptionRow(IBaseObject obj, Brush mainBrush, double descriptionSize, bool alwaysShowCode) {
			if (obj == null) {
				return null;
			}
			ISymbolDescription symbolDesc = (ISymbolDescription)obj.GetObject(typeof(ISymbolDescription));
			if (symbolDesc == null) {
				return null;
			}
			int numDescriptionColumns = 8;
			Grid grid = new Grid();
			for (int i = 0; i < numDescriptionColumns; i++) {
				ColumnDefinition columnDefinition;
				if (i > 0) {
					columnDefinition = new ColumnDefinition();
					columnDefinition.Width = new GridLength(1);
					grid.ColumnDefinitions.Add(columnDefinition);
				}
				columnDefinition = new ColumnDefinition();
				columnDefinition.Width = new GridLength(descriptionSize);
				grid.ColumnDefinitions.Add(columnDefinition);
			}
			for (int i = 1; i < numDescriptionColumns; i++) {
				Rectangle rectangle = new Rectangle();
				rectangle.Fill = mainBrush;
				Grid.SetColumn(rectangle, i * 2 - 1);
				grid.Children.Add(rectangle);
			}
			for (int i = 3; i <= numDescriptionColumns; i++) {
				DescriptionSymbol symbol = GetSymbolByCode(symbolDesc.GetDescription(i));
				if (symbol != null) {
					FrameworkElement element = symbol.GetSymbol(descriptionSize, mainBrush);
					Grid.SetColumn(element, i * 2 - 2);
					grid.Children.Add(element);
				}
				if (i == 6) {
					Size size = symbolDesc.GetFeatureSize();
					if (size.Width != 0 || size.Height != 0) {
						StackPanel sizePanel = new StackPanel();
						sizePanel.VerticalAlignment = VerticalAlignment.Center;
						if (size.Width != 0) {
							TextBlock textBlock = new TextBlock();
							textBlock.Text = size.Width.ToString();
							textBlock.HorizontalAlignment = HorizontalAlignment.Center;
							textBlock.Foreground = mainBrush;
							sizePanel.Children.Add(textBlock);
						}
						if (size.Height != 0) {
							TextBlock textBlock = new TextBlock();
							textBlock.Text = size.Height.ToString();
							textBlock.HorizontalAlignment = HorizontalAlignment.Center;
							textBlock.Foreground = mainBrush;
							sizePanel.Children.Add(textBlock);
						}
						Grid.SetColumn(sizePanel, i * 2 - 2);
						grid.Children.Add(sizePanel);
					}
				}
			}
			OCourseControl control = (OCourseControl)obj.GetObject(typeof(OCourseControl));
			if (control != null) {
				if (control.GetCourse() != null) {
					int num = control.GetCourse().GetControlNum(control);
					if (num > 0) {
						TextBlock textBlock = new TextBlock();
						textBlock.Text = num.ToString();
						textBlock.HorizontalAlignment = HorizontalAlignment.Center;
						textBlock.VerticalAlignment = VerticalAlignment.Center;
						textBlock.Foreground = mainBrush;
						Grid.SetColumn(textBlock, 0);
						grid.Children.Add(textBlock);
					}
				}
			}
			OControl targetControl = (OControl)obj.GetObject(typeof(OControl));
			ICodeObject targetObject = (ICodeObject)obj.GetObject(typeof(ICodeObject));
			if ((targetControl != null || alwaysShowCode == true) && targetObject!=null) {
				TextBlock textBlock = new TextBlock();
				textBlock.Text = targetObject.ObjectCode;
				textBlock.HorizontalAlignment = HorizontalAlignment.Center;
				textBlock.VerticalAlignment = VerticalAlignment.Center;
				textBlock.Foreground = mainBrush;
				Grid.SetColumn(textBlock, 2);
				grid.Children.Add(textBlock);
			}
			if (obj.GetObject(typeof(OStart)) != null) {
				Polygon poly = new Polygon();
				poly.Stroke = mainBrush;
				poly.StrokeThickness = 1;
				Point[] points = new Point[3];
				points[0] = new Point(Math.Sqrt(3), 1);
				points[1] = new Point(0, 2);
				points[2] = new Point(0, 0);
				ScaleTransform scale = new ScaleTransform(Math.Floor(descriptionSize/2.5), Math.Floor(descriptionSize/2.5), 0, 0);
				scale.Value.Transform(points);
				TranslateTransform move = new TranslateTransform(5, 0);
				move.Value.Transform(points);
				poly.Points = new PointCollection(points);
				poly.VerticalAlignment = VerticalAlignment.Center;
				Grid.SetColumn(poly, 0);
				grid.Children.Add(poly);
			}
			return grid;
		}

		private FrameworkElement GetDescriptionTitle(Brush mainBrush, double descriptionSize, string title) {
			if (title == null || title == "") {
				return null;
			}
			Grid grid = new Grid();
			TextBlock textBlock;
			textBlock = new TextBlock();
			textBlock.Text = title;
			textBlock.HorizontalAlignment = HorizontalAlignment.Center;
			textBlock.VerticalAlignment = VerticalAlignment.Center;
			textBlock.Foreground = mainBrush;
			grid.Children.Add(textBlock);
			return grid;
		}

		private FrameworkElement GetDescriptionHeader(Course course, Brush mainBrush, double descriptionSize) {
			Grid grid = new Grid();
			TextBlock textBlock;
			int numDescriptionColumns = 8;
			for (int i = 0; i < numDescriptionColumns; i++) {
				ColumnDefinition columnDefinition;
				if (i > 0) {
					columnDefinition = new ColumnDefinition();
					columnDefinition.Width = new GridLength(1);
					grid.ColumnDefinitions.Add(columnDefinition);
				}
				columnDefinition = new ColumnDefinition();
				columnDefinition.Width = new GridLength(descriptionSize);
				grid.ColumnDefinitions.Add(columnDefinition);
			}
			if (course == null) {
				textBlock = new TextBlock();
				textBlock.Text = "All Controls";
				textBlock.HorizontalAlignment = HorizontalAlignment.Center;
				textBlock.VerticalAlignment = VerticalAlignment.Center;
				textBlock.Foreground = mainBrush;
				Grid.SetColumnSpan(textBlock, numDescriptionColumns*2-1);
				grid.Children.Add(textBlock);
				return grid;
			}
			Rectangle rectangle = new Rectangle();
			rectangle.Fill = mainBrush;
			Grid.SetColumn(rectangle, 5);
			grid.Children.Add(rectangle);
			rectangle = new Rectangle();
			rectangle.Fill = mainBrush;
			Grid.SetColumn(rectangle, 11);
			grid.Children.Add(rectangle);
			textBlock = new TextBlock();
			textBlock.Text = course.Name;
			textBlock.HorizontalAlignment = HorizontalAlignment.Center;
			textBlock.VerticalAlignment = VerticalAlignment.Center;
			textBlock.Foreground = mainBrush;
			Grid.SetColumn(textBlock, 0);
			Grid.SetColumnSpan(textBlock, 5);
			grid.Children.Add(textBlock);
			textBlock = new TextBlock();
			textBlock.Text = course.GetLength().ToString() + " km";
			textBlock.HorizontalAlignment = HorizontalAlignment.Center;
			textBlock.VerticalAlignment = VerticalAlignment.Center;
			textBlock.Foreground = mainBrush;
			Grid.SetColumn(textBlock, 6);
			Grid.SetColumnSpan(textBlock, 5);
			grid.Children.Add(textBlock);
			textBlock = new TextBlock();
			textBlock.Text = course.Climb.ToString() + " m";
			textBlock.HorizontalAlignment = HorizontalAlignment.Center;
			textBlock.VerticalAlignment = VerticalAlignment.Center;
			textBlock.Foreground = mainBrush;
			Grid.SetColumn(textBlock, 12);
			Grid.SetColumnSpan(textBlock, 3);
			grid.Children.Add(textBlock);
			return grid;
		}

		private FrameworkElement GetTextDescriptionRow(IBaseObject obj, Brush mainBrush, double descriptionSize, bool alwaysShowCode) {
			if (obj == null) {
				return null;
			}
			int numDescriptionColumns = 8;
			Grid grid = new Grid();
			ColumnDefinition columnDefinition;
			columnDefinition = new ColumnDefinition();
			columnDefinition.Width = new GridLength(descriptionSize);
			grid.ColumnDefinitions.Add(columnDefinition);
			columnDefinition = new ColumnDefinition();
			columnDefinition.Width = new GridLength(descriptionSize*1.5);
			grid.ColumnDefinitions.Add(columnDefinition);
			columnDefinition = new ColumnDefinition();
			grid.ColumnDefinitions.Add(columnDefinition);
			columnDefinition = new ColumnDefinition();
			columnDefinition.Width = new GridLength(5);
			grid.ColumnDefinitions.Add(columnDefinition);
			bool leftGap = false;
			OCourseControl control = (OCourseControl)obj.GetObject(typeof(OCourseControl));
			if (control != null) {
				leftGap = true;
				if (control.GetCourse() != null) {
					int num = control.GetCourse().GetControlNum(control);
					if (num > 0) {
						TextBlock textBlock = new TextBlock();
						textBlock.Text = num.ToString();
						textBlock.HorizontalAlignment = HorizontalAlignment.Center;
						textBlock.VerticalAlignment = VerticalAlignment.Center;
						textBlock.Foreground = mainBrush;
						Grid.SetColumn(textBlock, 0);
						grid.Children.Add(textBlock);
					}
				}
			}
			OControl targetControl = (OControl)obj.GetObject(typeof(OControl));
			ICodeObject targetObject = (ICodeObject)obj.GetObject(typeof(ICodeObject));
			if ((targetControl != null || alwaysShowCode == true) && targetObject != null) {
				leftGap = true;
				TextBlock textBlock = new TextBlock();
				textBlock.Text = targetObject.ObjectCode;
				textBlock.HorizontalAlignment = HorizontalAlignment.Center;
				textBlock.VerticalAlignment = VerticalAlignment.Center;
				textBlock.Foreground = mainBrush;
				Grid.SetColumn(textBlock, 1);
				grid.Children.Add(textBlock);
			}else if (obj.GetObject(typeof(OStart)) != null) {
				leftGap = true;
				TextBlock textBlock = new TextBlock();
				textBlock.Text = "Start";
				textBlock.HorizontalAlignment = HorizontalAlignment.Center;
				textBlock.VerticalAlignment = VerticalAlignment.Center;
				textBlock.Foreground = mainBrush;
				Grid.SetColumn(textBlock, 1);
				grid.Children.Add(textBlock);
			}
			bool gotDesc = false;
			ITextDescription textDesc = (ITextDescription)obj.GetObject(typeof(ITextDescription));
			if (textDesc != null) {
				if (textDesc.TextDescription != "" && textDesc.TextDescription != null) {
					gotDesc = true;
					TextBlock textBlock = new TextBlock();
					textBlock.Text = textDesc.TextDescription;
					textBlock.VerticalAlignment = VerticalAlignment.Center;
					textBlock.Foreground = mainBrush;
					if (leftGap) {
						textBlock.HorizontalAlignment = HorizontalAlignment.Left;
						textBlock.Padding = new Thickness(5, 0, 0, 0);
						Grid.SetColumn(textBlock, 2);
						Grid.SetColumnSpan(textBlock, 1);//
					} else {
						textBlock.HorizontalAlignment = HorizontalAlignment.Center;
						Grid.SetColumn(textBlock, 0);
						Grid.SetColumnSpan(textBlock, 3);//
					}
					grid.Children.Add(textBlock);
				}
			}
			if (gotDesc == false) {
				ISymbolDescription symbolDesc = (ISymbolDescription)obj.GetObject(typeof(ISymbolDescription));
				if (symbolDesc != null) {
					gotDesc = true;
					string str = "";
					for (int i = 3; i <= numDescriptionColumns; i++) {
						DescriptionSymbol symbol = GetSymbolByCode(symbolDesc.GetDescription(i));
						if (symbol != null) {
							if (str != "") {
								str += " ";
							}
							if (i == 6 && symbolDesc.GetDescription(6)==null) {
								Size size = symbolDesc.GetFeatureSize();
								if (size.Width != 0) {
									str += size.Width.ToString() + "m";
								}
								if (size.Height != 0 && size.Width != 0) {
									str += "by" + size.Height.ToString() + "m";
								}
							} else {
								str += symbol.Text;
							}
						}
					}
					if (str != "") {
						TextBlock textBlock = new TextBlock();
						textBlock.Text = str;
						textBlock.VerticalAlignment = VerticalAlignment.Center;
						textBlock.Foreground = mainBrush;
						if (leftGap) {
							textBlock.HorizontalAlignment = HorizontalAlignment.Left;
							textBlock.Padding = new Thickness(5, 0, 0, 0);
							Grid.SetColumn(textBlock, 2);
							Grid.SetColumnSpan(textBlock, 1);//
						} else {
							textBlock.HorizontalAlignment = HorizontalAlignment.Center;
							Grid.SetColumn(textBlock, 0);
							Grid.SetColumnSpan(textBlock, 3);//
						}
						grid.Children.Add(textBlock);
					}
				}
			}
			if (gotDesc) {
				return grid;
			} else {
				return null;
			}
		}

		public FrameworkElement GetTextDescriptions(Course course, Brush mainBrush, double descriptionSize, int maxRows, string title) {
			StackPanel outerPanel = new StackPanel();
			outerPanel.Orientation = Orientation.Horizontal;
			int numDescriptionColumns = 8;
			RowDefinition rowDefinition;
			int outerColumnNum = 0;
			int overallOrderedObjectNum = 0;
			while (true) {
				int currentRowNum = 0;
				Border border = new Border();
				border.Background = Brushes.White;
				border.BorderBrush = mainBrush;
				border.BorderThickness = new Thickness(1);
				border.SnapsToDevicePixels = true;
				border.HorizontalAlignment = HorizontalAlignment.Left;
				border.VerticalAlignment = VerticalAlignment.Top;
				if (outerColumnNum > 0) {
					border.Margin = new Thickness(3, 0, 0, 0);
				}
				outerPanel.Children.Add(border);
				Grid grid = new Grid();
				border.Child = grid;
				grid.MinWidth = 8 * descriptionSize;
				int numDescriptionRows = 0;
				int numRows = 0;
				if (outerColumnNum == 0) {
					FrameworkElement titleRow = GetDescriptionTitle(mainBrush, descriptionSize, title);
					if (titleRow != null) {
						Grid.SetRow(titleRow, 0);
						grid.Children.Add(titleRow);
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numRows++;
						currentRowNum++;
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(1);
						grid.RowDefinitions.Add(rowDefinition);
						Rectangle rectangle = new Rectangle();
						rectangle.Fill = mainBrush;
						Grid.SetRow(rectangle, numRows);
						grid.Children.Add(rectangle);
						numRows++;
					}
					FrameworkElement header = GetDescriptionHeader(course, mainBrush, descriptionSize);
					Grid.SetRow(header, numRows);
					grid.Children.Add(header);
					rowDefinition = new RowDefinition();
					rowDefinition.Height = new GridLength(descriptionSize);
					grid.RowDefinitions.Add(rowDefinition);
					numRows++;
					currentRowNum++;
				}
				for (int i = overallOrderedObjectNum; i < course.OrderedObjects.Count; i++) {
					if (maxRows > 0) {
						if (currentRowNum >= maxRows) {
							break;
						}
					}
					bool addLine = false;
					int rowPos = numRows;
					if (i == 0) {
						rowPos++;
					}
					FrameworkElement row = GetTextDescriptionRow(course.OrderedObjects[i], mainBrush, descriptionSize, false);
					if (row != null) {
						addLine = true;
						Grid.SetRow(row, rowPos);
						grid.Children.Add(row);
					} else if (course.OrderedObjects[i].GetObject(typeof(OFinish)) != null) {
						addLine = true;
						Grid finishGrid = new Grid();
						Grid.SetRow(finishGrid, rowPos);
						grid.Children.Add(finishGrid);
						string str = "";
						if (course.TapesToFinish == false) {
							str = "Navigate";
						} else {
							str = "Follow tapes";
						}
						str += " " + course.GetDistanceToFinish().ToString() + " m to finish";
						TextBlock textBlock = new TextBlock();
						textBlock.Text = str;
						textBlock.HorizontalAlignment = HorizontalAlignment.Center;
						textBlock.VerticalAlignment = VerticalAlignment.Center;
						textBlock.Foreground = mainBrush;
						Grid.SetColumn(textBlock, 0);
						Grid.SetColumnSpan(textBlock, numDescriptionColumns);
						finishGrid.Children.Add(textBlock);
					}
					if (addLine) {
						if (i == 0) {
							rowDefinition = new RowDefinition();
							rowDefinition.Height = new GridLength(1);
							grid.RowDefinitions.Add(rowDefinition);
							Rectangle rectangle = new Rectangle();
							rectangle.Fill = mainBrush;
							Grid.SetRow(rectangle, numRows);
							grid.Children.Add(rectangle);
							numRows++;
						}
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numDescriptionRows++;
						numRows++;
					}
					overallOrderedObjectNum++;
					currentRowNum++;
				}
				if (overallOrderedObjectNum >= course.OrderedObjects.Count) {
					break;
				}
				outerColumnNum++;
			}
			return outerPanel;
		}

		public FrameworkElement GetTextDescriptions(OPlannerData data, Brush mainBrush, double descriptionSize, int maxRows, string title) {
			StackPanel outerPanel = new StackPanel();
			outerPanel.Orientation = Orientation.Horizontal;
			RowDefinition rowDefinition;
			int outerColumnNum = 0;
			int overallOrderedObjectNum = 0;
			List<OBaseObject> tempList = new List<OBaseObject>(data.OObjects);
			tempList.Sort(OPlannerHelper.CompareOBaseObjects);
			while (true) {
				int currentRowNum = 0;
				Border border = new Border();
				border.Background = Brushes.White;
				border.BorderBrush = mainBrush;
				border.BorderThickness = new Thickness(1);
				border.SnapsToDevicePixels = true;
				border.HorizontalAlignment = HorizontalAlignment.Left;
				border.VerticalAlignment = VerticalAlignment.Top;
				if (outerColumnNum > 0) {
					border.Margin = new Thickness(3, 0, 0, 0);
				}
				outerPanel.Children.Add(border);
				Grid grid = new Grid();
				border.Child = grid;
				int numDescriptionRows = 0;
				int numRows = 0;
				if (outerColumnNum == 0) {
					FrameworkElement titleRow = GetDescriptionTitle(mainBrush, descriptionSize, title);
					if (titleRow != null) {
						Grid.SetRow(titleRow, 0);
						grid.Children.Add(titleRow);
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numRows++;
						currentRowNum++;
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(1);
						grid.RowDefinitions.Add(rowDefinition);
						Rectangle rectangle = new Rectangle();
						rectangle.Fill = mainBrush;
						Grid.SetRow(rectangle, numRows);
						grid.Children.Add(rectangle);
						numRows++;
					}
					FrameworkElement header = GetDescriptionHeader(null, mainBrush, descriptionSize);
					Grid.SetRow(header, numRows);
					grid.Children.Add(header);
					rowDefinition = new RowDefinition();
					rowDefinition.Height = new GridLength(descriptionSize);
					grid.RowDefinitions.Add(rowDefinition);
					numRows++;
					currentRowNum++;
				}
				for (int i = overallOrderedObjectNum; i < tempList.Count; i++) {
					if (maxRows > 0) {
						if (currentRowNum >= maxRows) {
							break;
						}
					}
					bool addLine = false;
					int rowPos = numRows;
					if (i == 0) {
						rowPos++;
					}
					FrameworkElement row = GetTextDescriptionRow(tempList[i], mainBrush, descriptionSize, true);
					if (row != null) {
						addLine = true;
						Grid.SetRow(row, rowPos);
						grid.Children.Add(row);
					}
					if (addLine) {
						if (i == 0) {
							rowDefinition = new RowDefinition();
							rowDefinition.Height = new GridLength(1);
							grid.RowDefinitions.Add(rowDefinition);
							Rectangle rectangle = new Rectangle();
							rectangle.Fill = mainBrush;
							Grid.SetRow(rectangle, numRows);
							grid.Children.Add(rectangle);
							numRows++;
						}
						rowDefinition = new RowDefinition();
						rowDefinition.Height = new GridLength(descriptionSize);
						grid.RowDefinitions.Add(rowDefinition);
						numDescriptionRows++;
						numRows++;
					}
					overallOrderedObjectNum++;
					currentRowNum++;
				}
				if (overallOrderedObjectNum >=tempList.Count) {
					break;
				}
				outerColumnNum++;
			}
			return outerPanel;
		}

	}

}
