#region COPYRIGHT
//
//     THIS IS GENERATED BY TEMPLATE
//     
//     AUTHOR  :     ROYE
//     DATE       :     2010
//
//     COPYRIGHT (C) 2010, TIANXIAHOTEL TECHNOLOGIES CO., LTD. ALL RIGHTS RESERVED.
//
#endregion

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

namespace System.Office.Excel
{
    public class ExcelMapper
    {
        #region Read

        public void Read(object destination, string excelFileName)
        {
            if (destination == null)
                throw new ArgumentNullException("destination");

            using (ExcelManager em = new ExcelManager())
            {
                em.Open(excelFileName);

                HandleCommonClassAttributes(em, destination);

                // Check attributes of Properties in class
                Type objType = destination.GetType();
                foreach (PropertyInfo propInfo in objType.GetProperties())
                {
                    object[] attributes = propInfo.GetCustomAttributes(true);
                    if (attributes == null)
                        continue;

                    foreach (Attribute att in attributes)
                    {
                        HandleCommonPropertiesAttributes(em, destination, att, propInfo);

                        // Read Specific Attributes:

                        // [FromCell]
                        FromCellAttribute fromCell = att as FromCellAttribute;
                        if (fromCell != null)
                        {
                            object value = em.GetValue(fromCell.CellAddress, fromCell.Category);
                            propInfo.SetValue(destination, value, null);
                        }

                        // [FromRange]
                        FromRangeAttribute fromRange = att as FromRangeAttribute;
                        if (fromRange != null)
                        {
                            ArrayList values = em.GetRangeValues(fromRange.StartCellAddress, fromRange.EndCellAddress, fromRange.Category);
                            propInfo.SetValue(destination, values, null);
                        }
                    }
                }
            }
        }

        #endregion

        #region Write

        public void Write(object target, string excelFileName)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            using (ExcelManager em = new ExcelManager())
            {
                em.Create(excelFileName);
                Write(em, target);
                em.Save();
            }
        }

        public void Write(object target, string excelFileName, string templateFileName)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            using (ExcelManager em = new ExcelManager())
            {
                em.Open(templateFileName);
                Write(em, target);
                em.SaveAs(excelFileName);
            }
        }

        private void Write(ExcelManager manager, object target)
        {
            HandleCommonClassAttributes(manager, target);

            //static cells
            target.GetProperties().ForEach(p =>
            {
                object value = target.GetPropertyValue(p.Name);
                if (p.HasAttribute<ToCellAttribute>())
                {
                    ToCellAttribute toCell = p.Attribute<ToCellAttribute>();
                    if (toCell != null)
                    {
                        manager.SetValue(toCell.CellAddress, value);
                    }
                }
                else if (p.HasAttribute<ToRangeAttribute>())
                {
                    ToRangeAttribute toRange = p.Attribute<ToRangeAttribute>();
                    if (value is IList)
                    {
                        manager.SetRangeValues(toRange.StartCellAddress, toRange.EndCellAddress, (IList)value);
                    }
                    else
                    {
                        manager.SetRangeValue(toRange.StartCellAddress, toRange.EndCellAddress, value);
                    }
                }
            });

            target.GetProperties().FindAll(p => p.HasAttribute<ToDynamicRangeAttribute>()).ForEach(p =>
            {
                object value = target.GetPropertyValue(p.Name);
                if (value is IList)
                {
                    IList list = value as IList;
                    ToDynamicRangeAttribute dr = p.Attribute<ToDynamicRangeAttribute>();
                    int startRow = dr.StartRow;
                    for (int i = 1; i < list.Count; i++)
                    {
                        manager.CopyRows(startRow, startRow, startRow + 1);
                        startRow++;
                    }
                    for (int i = 0; i < list.Count; i++)
                    {
                        var item = list[i];
                        if (item is IList)
                        {
                            manager.SetRangeValues(
                                string.Format("{0}{1}", dr.StartColumnName, dr.StartRow + i),
                                string.Format("{0}{1}", dr.EndColumnName, dr.StartRow + i + list.Count - 1),
                                (item as IList));
                        }
                    }
                }
            });

        }

        private void HandleCommonClassAttributes(ExcelManager em, object obj)
        {
            Type objType = obj.GetType();
            // Check class attributes
            foreach (Attribute att in objType.GetCustomAttributes(true))
            {
                // [DefaultSheet]
                DefaultSheetAttribute defaultSheet = att as DefaultSheetAttribute;
                if (defaultSheet != null)
                {
                    em.ActivateSheet(defaultSheet.SheetName);
                }
            }
        }

        private void HandleCommonPropertiesAttributes(ExcelManager em, object obj, Attribute att, PropertyInfo propInfo)
        {
            UseSheetAttribute useSheet = att as UseSheetAttribute;
            if (useSheet != null)
            {
                if (!String.IsNullOrEmpty(useSheet.SheetName))
                {
                    em.ActivateSheet(useSheet.SheetName);
                }
                else
                {
                    string sheetName = Convert.ToString(propInfo.GetValue(obj, null));
                    em.ActivateSheet(sheetName);
                }
            }
        }

        #endregion
    }
}
