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

namespace InABox.Core
{
    public class HTMLStyle : Dictionary<string, string>
    {
    }

    public enum HTMLFontStyle
    {
        Regular,
        Bold,
        Italic,
        Underline
    }

    public class HTMLBuilder
    {
        private readonly Dictionary<string, object> _attributes = new Dictionary<string, object>();
        private Dictionary<string, string> _styles = new Dictionary<string, string>();

        private readonly StringBuilder body = new StringBuilder();
        private readonly HTMLBuilder parent;

        public HTMLBuilder()
        {
        }

        public HTMLBuilder(string TagName, HTMLBuilder Parent)
        {
            this.TagName = TagName;
            parent = Parent;
            if (Parent != null)
            {
                DefaultStyle = Parent.DefaultStyle;
                TableStyle = Parent.TableStyle;
                CellStyle = Parent.CellStyle;
            }
        }

        public HTMLStyle DefaultStyle { get; set; }
        public HTMLStyle TableStyle { get; set; }
        public HTMLStyle CellStyle { get; set; }

        public string TagName { get; }

        public HTMLBuilder AddContent(string Content, HTMLFontStyle style = HTMLFontStyle.Regular)
        {
            if (style == HTMLFontStyle.Regular)
            {
                body.Append(Content);
                return this;
            }

            var tmp = new HTMLBuilder();

            if (style == HTMLFontStyle.Bold)
                tmp = tmp.StartTag("b", null);

            if (style == HTMLFontStyle.Italic)
                tmp = tmp.StartTag("i", null);

            if (style == HTMLFontStyle.Underline)
                tmp = tmp.StartTag("u", null);

            tmp.AddContent(Content);

            if (style != HTMLFontStyle.Regular)
                tmp = tmp.EndTag();

            body.Append(tmp);
            return this;
        }

        public HTMLBuilder AddContentFormat(string Format, params object[] args)
        {
            body.AppendFormat(Format, args);
            return this;
        }

        private HTMLBuilder StartTag(string TagName, HTMLStyle tagStyle)
        {
            var tag = new HTMLBuilder(TagName, this)
            {
                DefaultStyle = tagStyle, //(tagStyle != null ? tagStyle : this.DefaultStyle),
                TableStyle = TableStyle,
                CellStyle = CellStyle
            };
            return tag;
        }

        private HTMLBuilder EndTag()
        {
            parent.AddContent(ToString());
            return parent;
        }

        public HTMLBuilder AddAttribute(string Name, object Value)
        {
            _attributes.Add(Name, Value);
            return this;
        }

        public HTMLBuilder StartBody(HTMLStyle style = null)
        {
            return StartTag("body", style);
        }

        public HTMLBuilder EndBody()
        {
            if (TagName.Equals("body"))
                return EndTag();
            throw new Exception("EndBody() Exception");
        }

        public HTMLBuilder StartFont(string Face, string Size)
        {
            return StartTag("font", null).AddAttribute("face", Face).AddAttribute("size", Size);
        }

        public HTMLBuilder EndFont()
        {
            if (TagName.Equals("font"))
                return EndTag();
            throw new Exception("EndFont() Exception");
        }

        public HTMLBuilder StartParagraph(HTMLStyle style = null)
        {
            return StartTag("p", style);
        }

        public HTMLBuilder AddBreak()
        {
            body.Append("<br>");
            return this;
        }

        public HTMLBuilder EndParagraph()
        {
            if (TagName.Equals("p"))
                return EndTag();
            throw new Exception("EndParagraph() Exception");
        }

        public HTMLBuilder StartTable(HTMLStyle style = null)
        {
            return StartTag("table", style != null ? style : TableStyle);
        }

        public HTMLBuilder EndTable()
        {
            if (TagName.Equals("table"))
                return EndTag();
            throw new Exception("EndTable() Exception");
        }

        public HTMLBuilder StartRow(HTMLStyle style = null)
        {
            if (TagName.Equals("table"))
                return StartTag("tr", style);
            throw new Exception("StartRow() Exception");
        }

        public HTMLBuilder EndRow()
        {
            if (TagName.Equals("tr"))
                return EndTag();
            throw new Exception("EndRow() Exception");
        }

        public HTMLBuilder StartCell(HTMLStyle style = null, int colspan = 1, int rowspan = 1, string width = "",
            Alignment align = Alignment.MiddleLeft, string color = "#FFFFFF00")
        {
            if (TagName.Equals("tr"))
            {
                var tag = StartTag("td", style != null ? style : CellStyle);
                if (colspan != 1)
                    tag.AddAttribute("colspan", colspan.ToString());
                if (rowspan != 1)
                    tag.AddAttribute("rowspan", rowspan.ToString());
                if (!string.IsNullOrEmpty(width))
                    tag.AddAttribute("width", width);

                if (align.Equals(Alignment.TopCenter) || align.Equals(Alignment.MiddleCenter) || align.Equals(Alignment.BottomCenter))
                    tag.AddAttribute("align", "center");
                else if (align.Equals(Alignment.TopRight) || align.Equals(Alignment.MiddleRight) || align.Equals(Alignment.BottomRight))
                    tag.AddAttribute("align", "right");

                if (align.Equals(Alignment.BottomLeft) || align.Equals(Alignment.BottomCenter) || align.Equals(Alignment.BottomRight))
                    tag.AddAttribute("valign", "bottom");
                else if (align.Equals(Alignment.MiddleLeft) || align.Equals(Alignment.MiddleCenter) || align.Equals(Alignment.MiddleRight))
                    tag.AddAttribute("valign", "middle");

                if (!color.ToUpper().Equals("#FFFFFF00"))
                    tag.AddAttribute("bgcolor", color);

                return tag;
            }

            throw new Exception("StartCell() Exception");
        }

        public HTMLBuilder EndCell()
        {
            if (TagName.Equals("td"))
                return EndTag();
            throw new Exception("EndCell() Exception");
        }

        public HTMLBuilder AddImage(string FileName, string Width, string Height)
        {
            body.AppendFormat("<img src=\"{0}\" alt=\"{0}\"", FileName);
            if (!Height.Equals(""))
                body.AppendFormat(" height=\"{0}\"", Height);
            if (!Width.Equals(""))
                body.AppendFormat(" width=\"{0}\"", Width);
            body.Append(">");
            return this;
        }

        public override string ToString()
        {
            var tag = new StringBuilder();

            // preamble
            if (!string.IsNullOrEmpty(TagName))
            {
                tag.AppendFormat("<{0}", TagName);
                if (DefaultStyle != null)
                {
                    tag.Append(" style=\"");
                    foreach (var key in DefaultStyle.Keys)
                        tag.AppendFormat("{0}:{1};", key, DefaultStyle[key]);
                    tag.Append("\"");
                }
            }

            if (_attributes.Count > 0)
            {
                tag.Append(" ");
                tag.Append(
                    string.Join(" ",
                        _attributes
                            .Select(
                                kvp => string.Format("{0}={1}", kvp.Key,
                                    kvp.Value.GetType().Equals(typeof(string)) ? "\"" + kvp.Value + "\"" : kvp.Value.ToString()))
                            .ToArray()));
            }

            // body/ending
            if (body.Length > 0)
            {
                if (!string.IsNullOrEmpty(TagName) || _attributes.Count > 0)
                    tag.Append(">");
                tag.Append(body.ToString());
                if (!string.IsNullOrEmpty(TagName))
                    tag.AppendFormat("</{0}>", TagName);
            }
            else if (!string.IsNullOrEmpty(TagName))
            {
                tag.Append("/>");
            }

            return tag.ToString();
        }
    }
}