using System;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using System.Globalization;

namespace C1.Silverlight.FlexGridExcel
{
    /// <summary>
    /// Represents a MS Excel column.
    /// </summary>
    public class XLColumn
    {
        //-------------------------------------------------------------------------
        #region ** ctor

        /// <summary>
        /// Initializes a new instance of the <see cref="XLColumn"/> class.
        /// </summary>
        /// <param name="element">The xml element to load the XLColumn from.</param>
        public XLColumn(XElement element)
        {
            Element = element ?? new XElement(XLWorkbook.SheetNS + XLConstants.COLUMN);
        }
        /// <summary>
        /// Initializes a new instance of an <see cref="XLColumn"/>.
        /// </summary>
        /// <param name="index">Index of the new column.</param>
        public XLColumn(int index)
        {
            Element = new XElement(XLWorkbook.SheetNS + XLConstants.COLUMN);
            Element.SetAttributeValue(XLConstants.MIN, index);
            Element.SetAttributeValue(XLConstants.MAX, index);
        }

        #endregion

        //-------------------------------------------------------------------------
        #region ** object model

        /// <summary>
        /// Gets the <see cref="XElement"/> that represents this column.
        /// </summary>
        public XElement Element { get; private set; }
        /// <summary>
        /// Gets or sets the index of the style used by this column.
        /// </summary>
        public int? Style
        {
            get
            {
                if (Element.Attribute(XLConstants.STYLE) != null)
                {
                    return int.Parse(Element.Attribute(XLConstants.STYLE).Value, CultureInfo.InvariantCulture);
                }
                return null;
            }
            set
            {
                Element.SetAttributeValue(XLConstants.STYLE, value);
            }
        }
        /// <summary>
        /// Gets or sets the width of this column in pixels.
        /// </summary>
        public double? Width
        {
            get
            {
                if (Element.Attribute(XLConstants.WIDTH) != null)
                {
                    double colWidth = double.Parse(Element.Attribute(XLConstants.WIDTH).Value, CultureInfo.InvariantCulture);
                    return CharacterWidthToPixels(colWidth);
                }
                return null;
            }
            set
            {
                if (value.HasValue)
                {
                    var convertedWidth = PixelsToCharacterWidth(value.Value);
                    Element.SetAttributeValue(XLConstants.WIDTH, convertedWidth);
                    Element.SetAttributeValue(XLConstants.BEST_FIT, 1);
                    Element.SetAttributeValue(XLConstants.CUSTOM_WIDTH, 1);
                }
                else
                {
                    Element.SetAttributeValue(XLConstants.WIDTH, null);
                    Element.SetAttributeValue(XLConstants.BEST_FIT, null);
                    Element.SetAttributeValue(XLConstants.CUSTOM_WIDTH, null);
                }
            }
        }

        #endregion

        //-------------------------------------------------------------------------
        #region ** implementation

        // Converts pixels to character width (used to specify column widths in excel).
        // Column width measured as the number of characters of the maximum digit width of the
        // numbers 0, 1, 2, …, 9 as rendered in the normal style's font. There are 4 pixels of
        // margin padding (two on each side), plus 1 pixel padding for the gridlines.
        // Using the Calibri font as an example, the maximum digit width of 11 point font
        // size is 7 pixels (at 96 dpi)
        double PixelsToCharacterWidth(double pixels)
        {
            int maxDigitWith = 7;
            return Math.Ceiling(Math.Floor((pixels - 5) / maxDigitWith * 100 + 0.5) / 100);
        }

        double CharacterWidthToPixels(double width)
        {
            int maxDigitWith = 7;
            return Math.Floor(((256 * width + Math.Floor(128 / maxDigitWith)) / 256) * maxDigitWith);
        }

        #endregion
    }
}
