using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows;

namespace OcadMapLibrary {

	public class TextSymbol : MapSymbol {

		//Doesn't support character space or word space

		MapColorRef textColor;
		public MapColorRef TextColor {
			get {
				return textColor;
			}
			set {
				textColor = value;
			}
		}

		double fontSize;
		public double FontSize {
			get {
				return fontSize;
			}
			set {
				fontSize = value;
			}
		}

		double lineHeight;
		public double LineHeight {
			get {
				return lineHeight;
			}
			set {
				lineHeight = value;
			}
		}

		List<double> columnWidths;
		public List<double> ColumnWidths {
			get {
				return columnWidths;
			}
			set {
				columnWidths = value;
			}
		}

		FontFamily fontFamily;
		public FontFamily FontFamily {
			get {
				return fontFamily;
			}
			set {
				fontFamily = value;
			}
		}

		FontStyle style;
		public FontStyle Style {
			get {
				return style;
			}
			set {
				style = value;
			}
		}

		FontWeight weight;
		public FontWeight Weight {
			get {
				return weight;
			}
			set {
				weight = value;
			}
		}

		TextAlignment alignment;
		public TextAlignment Alignment {
			get {
				return alignment;
			}
			set {
				alignment = value;
			}
		}

		MapColorRef lineBelowColor;
		public MapColorRef LineBelowColor {
			get {
				return lineBelowColor;
			}
			set {
				lineBelowColor = value;
			}
		}

		double lineBelowWidth;
		public double LineBelowWidth {
			get {
				return lineBelowWidth;
			}
			set {
				lineBelowWidth = value;
			}
		}

		double lineBelowOffset;
		public double LineBelowOffset {
			get {
				return lineBelowOffset;
			}
			set {
				lineBelowOffset = value;
			}
		}

		double paragraphSpace;
		public double ParagraphSpace {
			get {
				return paragraphSpace;
			}
			set {
				paragraphSpace = value;
			}
		}

		FormattedText GetFormattedText(string text, Color color, double maxWidth) {
			FormattedText formattedText = new FormattedText(text, new System.Globalization.CultureInfo("en-GB"), FlowDirection.LeftToRight, new Typeface(FontFamily, Style, Weight, FontStretches.Normal), FontSize, new SolidColorBrush(color));
			if (maxWidth > 0) {
				formattedText.MaxTextWidth = maxWidth;
			}
			formattedText.TextAlignment = Alignment;
			formattedText.LineHeight = LineHeight;
			formattedText.Trimming = TextTrimming.None;
			return formattedText;
		}

		public void DrawSymbol(string text, Rect layoutRect, double rotation, DrawingContext drawingContext, MapColor mapColor) {
			if (IsHidden) {
				return;
			}
			if (string.IsNullOrWhiteSpace(text)) {
				return;
			}
			bool matchesTextColor = false;
			bool matchesLineColor = false;
			if (mapColor != null) {
				matchesTextColor = TextColor.Matches(mapColor);
				if (LineBelowColor != null && LineBelowWidth > 0) {
					matchesLineColor = LineBelowColor.Matches(mapColor);
				}
			}
			if (!(matchesLineColor || matchesTextColor)) {
				return;
			}
			double lineBelowLength = 0;
			if (matchesLineColor) {
				lineBelowLength = GetBoundingRect(text, layoutRect, 0).Width;
			}
			string newText = text;
			if (newText.StartsWith("\r")) {
				newText = newText.Substring(1);
			}
			if (newText.StartsWith("\n")) {
				newText = newText.Substring(1);
			}
			Color newColor = Colors.Black;
			if (mapColor != null) {
				newColor = mapColor.Color;
			}
			double topMargin = 0;
			double topOffset = 0;
			if (layoutRect.Width == 0) {
				topOffset = -LineHeight * 0.8;//0.8 is unknown value
			}
			if (rotation != 0) {
				RotateTransform rotate = new RotateTransform(rotation, layoutRect.Left, layoutRect.Top + LineHeight * 0.8);//0.8 is unknown value
				drawingContext.PushTransform(rotate);
			}
			double maxWidth = layoutRect.Width;
			string[] lines = newText.Split(new string[] { "\r\n" }, StringSplitOptions.None);
			for (int i = 0; i < lines.Length; i++) {
				string lineText = lines[i];
				double leftOffset = 0;
				if (ColumnWidths != null && lineText.IndexOf("\t") >= 0) {
					string[] textFragments = lineText.Split(new char[] { '\t' });
					double lastWidth = 0;
					double currentColWidth = 0;
					double lastColumnWidth = ColumnWidths[ColumnWidths.Count - 1];
					double currentMargin = 0;
					int currentCol = 0;
					for (int j = 0; j < textFragments.Length; j++) {
						if (j > 0) {
							currentMargin = -lastWidth;
							do {
								if (currentCol < ColumnWidths.Count) {
									currentColWidth = ColumnWidths[currentCol];
								} else {
									currentColWidth = lastColumnWidth;
								}
								currentCol++;
								currentMargin += currentColWidth;
							} while (currentMargin < 0);
						} else {
							currentMargin = 0;
						}
						FormattedText currentText = GetFormattedText(textFragments[j], newColor, layoutRect.Width);
						lastWidth = currentText.WidthIncludingTrailingWhitespace;
						Point topLeft = layoutRect.TopLeft;
						topLeft.X = topLeft.X + leftOffset + currentMargin;
						topLeft.Y = topLeft.Y + topMargin + topOffset;
						leftOffset += lastWidth + currentMargin;
						if (matchesTextColor) {
							drawingContext.DrawText(currentText, topLeft);
						}
						if (leftOffset > maxWidth) {
							maxWidth = leftOffset;
						}
					}
				} else {
					FormattedText currentText = GetFormattedText(lineText.Replace("\t", ""), newColor, layoutRect.Width);
					Point topLeft = layoutRect.TopLeft;
					topLeft.X = topLeft.X + leftOffset;
					topLeft.Y = topLeft.Y + topMargin + topOffset;
					if (matchesTextColor) {
						drawingContext.DrawText(currentText, topLeft);
					}
					double width = currentText.WidthIncludingTrailingWhitespace;
					if (width > maxWidth) {
						maxWidth = width;
					}
				}
				topOffset += topMargin + LineHeight;
				if (LineBelowColor != null && LineBelowWidth > 0) {
					if (matchesLineColor) {
						double lineY = layoutRect.Top + topOffset + 0.2 * LineBelowOffset;//0.2 is unknown value
						drawingContext.DrawLine(new Pen(new SolidColorBrush(newColor), LineBelowWidth), new Point(layoutRect.Left, lineY), new Point(layoutRect.Left + lineBelowLength, lineY));
					}
					topOffset += LineBelowWidth + 0.2 * LineBelowOffset;//0.2 is unknown value
				}
				topMargin = ParagraphSpace;
			}
			if (rotation != 0) {
				drawingContext.Pop();
			}
		}

		public Rect GetBoundingRect(string text, Rect layoutRect, double rotation) {
			if (IsHidden) {
				return Rect.Empty;
			}
			if (string.IsNullOrWhiteSpace(text)) {
				return Rect.Empty;
			}
			string newText = text;
			if (newText.StartsWith("\r")) {
				newText = newText.Substring(1);
			}
			if (newText.StartsWith("\n")) {
				newText = newText.Substring(1);
			}
			double topMargin = 0;
			double topOffset = 0;
			if (layoutRect.Width == 0) {
				topOffset = -LineHeight * 0.8;//0.8 is unknown value
			}
			double maxWidth = layoutRect.Width;
			string[] lines = newText.Split(new string[] { "\r\n" }, StringSplitOptions.None);
			for (int i = 0; i < lines.Length; i++) {
				string lineText = lines[i];
				double leftOffset = 0;
				if (ColumnWidths != null && lineText.IndexOf("\t") >= 0) {
					string[] textFragments = lineText.Split(new char[] { '\t' });
					double lastWidth = 0;
					double currentColWidth = 0;
					double lastColumnWidth = ColumnWidths[ColumnWidths.Count - 1];
					double currentMargin = 0;
					int currentCol = 0;
					for (int j = 0; j < textFragments.Length; j++) {
						if (j > 0) {
							currentMargin = -lastWidth;
							do {
								if (currentCol < ColumnWidths.Count) {
									currentColWidth = ColumnWidths[currentCol];
								} else {
									currentColWidth = lastColumnWidth;
								}
								currentCol++;
								currentMargin += currentColWidth;
							} while (currentMargin < 0);
						} else {
							currentMargin = 0;
						}
						FormattedText currentText = GetFormattedText(textFragments[j], Colors.Black, layoutRect.Width);
						lastWidth = currentText.WidthIncludingTrailingWhitespace;
						Point topLeft = layoutRect.TopLeft;
						topLeft.X = topLeft.X + leftOffset + currentMargin;
						topLeft.Y = topLeft.Y + topMargin + topOffset;
						leftOffset += lastWidth + currentMargin;
						if (leftOffset > maxWidth) {
							maxWidth = leftOffset;
						}
					}
				} else {
					FormattedText currentText = GetFormattedText(lineText.Replace("\t", ""), Colors.Black, layoutRect.Width);
					Point topLeft = layoutRect.TopLeft;
					topLeft.X = topLeft.X + leftOffset;
					topLeft.Y = topLeft.Y + topMargin + topOffset;
					double width = currentText.WidthIncludingTrailingWhitespace;
					if (width > maxWidth) {
						maxWidth = width;
					}
				}
				topOffset += topMargin + LineHeight;
				if (LineBelowColor != null && LineBelowWidth > 0) {
					topOffset += LineBelowWidth + 0.2 * LineBelowOffset;//0.2 is unknown value
				}
				topMargin = ParagraphSpace;
			}
			Rect rect = layoutRect;
			rect.Width = maxWidth;
			rect.Height = topOffset;
			if (layoutRect.Width == 0) {
				rect.Height = rect.Height + LineHeight * 0.8;//0.8 is unknown value
				rect.Y = rect.Y - LineHeight * 0.8;//0.8 is unknown value
				if (Alignment == TextAlignment.Center) {
					rect.X = rect.X - rect.Width / 2;
				} else if (Alignment == TextAlignment.Right) {
					rect.X = rect.X - rect.Width;
				}
			}
			if (rotation != 0) {
				RotateTransform rotate = new RotateTransform(rotation, layoutRect.Left, layoutRect.Top + LineHeight * 0.8);//0.8 is unknown value;
				rect = rotate.TransformBounds(rect);
			}
			return rect;
		}

	}

}
