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

namespace C1.Silverlight.FlexGridExcel
{
    /// <summary>
    /// Represents an MS Excel cell.
    /// </summary>
    public class XLCell
    {
        //-------------------------------------------------------------------------
        #region ** ctors

        /// <summary>
        /// Initializes a new instance of an <see cref="XLCell"/>.
        /// </summary>
        /// <param name="rowIndex">Index of the row that contains the cell.</param>
        /// <param name="cellIndex">Index of the cell within the row.</param>
        public XLCell(int rowIndex, int cellIndex)
        {
            // create element
            Element = new XElement(XLWorkbook.SheetNS + XLConstants.CELL);
            // set cell reference e.g. A1, D4
            Element.SetAttributeValue(XLConstants.REFERENCE, GetCellReference(rowIndex, cellIndex));
        }
        /// <summary>
        /// Initializes a new instance of an <see cref="XLCell"/> from an xml element.
        /// </summary>
        /// <param name="element">The xml element to load the XLCell from.</param>
        public XLCell(XElement element)
        {
            // create element
            Element = element ?? new XElement(XLWorkbook.SheetNS + XLConstants.CELL);
        }

        #endregion

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

        /// <summary>
        /// Gets the xml element that represents this cell.
        /// </summary>
        public XElement Element { get; private set; }
        /// <summary>
        /// Gets or sets the value of the cell.
        /// </summary>
        /// <value>The cell value.</value>
        public object Value
        {
            get
            {
                return Element.Value;
            }
            set
            {
                // Clear previous attributes and values
                Element.SetAttributeValue(XLConstants.DATA_TYPE, null);
                Element.DescendantNodes().Remove();
                if (value != null)
                {
                    // Set new attributes and values
                    if (value is string)
                    {
                        Element.SetAttributeValue(XLConstants.DATA_TYPE, XLConstants.INLINE_STRING);
                        Element.Add(new XElement(XLWorkbook.SheetNS + XLConstants.RICH_TEXT_INLINE, new XElement(XLWorkbook.SheetNS + XLConstants.TEXT, value)));
                    }
                    else if (value is bool)
                    {
                        Element.SetAttributeValue(XLConstants.DATA_TYPE, XLConstants.BOOLEAN);
                        Element.Add(new XElement(XLWorkbook.SheetNS + XLConstants.CELL_VALUE, value));
                    }
                    else
                    {
                        Element.SetAttributeValue(XLConstants.DATA_TYPE, XLConstants.NUMBER);
                        Element.Add(new XElement(XLWorkbook.SheetNS + XLConstants.CELL_VALUE, value));
                    }
                }
            }
        }
        /// <summary>
        /// Gets a value indicating whether the value of the cell represents an index in the Excel 
        /// shared strings table.
        /// </summary>
        public bool IsSharedString
        {
            get
            {
                if (Element.Attribute(XLConstants.DATA_TYPE) != null)
                {
                    return Element.Attribute(XLConstants.DATA_TYPE).Value.Equals(XLConstants.SHARED_STRING);
                }
                return false;
            }
        }
        /// <summary>
        /// Gets or sets the index of the style associated with this cell.
        /// </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);
            }
        }

        #endregion

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

        // Returns the cell reference (e.g. B3) for a given row and column index
        string GetCellReference(int rowIndex, int colIndex)
        {
            // create string builder and save column value
            StringBuilder sb = new StringBuilder();
            int div = colIndex;

            // convert column
            while (true)
            {
                char ch = (char)(div % 26 + 65);
                sb.Insert(0, ch.ToString());
                div = div / 26;
                if (div == 0)
                {
                    break;
                }
                div--;
            }

            // append row
            sb.Append(rowIndex);

            // done
            return sb.ToString();
        }

        #endregion
    }
}
