using System;
using System.Diagnostics;
using nft.framework;
using nft.util;
using nft.framework.plugin;
using System.Reflection;
using System.Globalization;
using nft.core.view;

namespace nft.core.schedule
{
	/// <summary>
	/// Time instant.
	/// </summary>
	[Serializable]
	public class Calendar : IGlobalModule
	{
        private static Calendar the_calendar;
        public static Calendar ActiveCalendar {
            get {
                return the_calendar;
            }
            set {
                the_calendar = value;
            }
        }

        private ITimeTickConverter tickConverter;

        public Calendar(ParamsReader node)
        {
            ParamsReader f = PluginUtil.LoadAnotherXml(node["settings"]["include"]);
            LoadSettingFile(f);
            tickConverter = new SimpleTimeTickConverter(60,7);
            ActiveCalendar = this;
        }

        public Clock CreateNewClock(Date start) {
            return new Clock(tickConverter.ToTicks(start));
        }

        public ITimeTickConverter TimeTickConverter {
            get { return tickConverter; }
        }

        public void LoadSettingFile(ParamsReader reader){
            Debug.WriteLine("Load calender settings from:"+reader.SourceURI);
            ParamsReader cr = reader["calendar"];
            ReadNamedConditions(cr["named_conditons"]);
        }

        private void ReadNamedConditions(ParamsReader r){
            foreach (ParamsReader r1 in r.EnumChildren("predefined_group")) {
                ReadPredefinedGroup(r1);
            }
            foreach (ParamsReader r2 in r.EnumChildren("group")) {
                ReadGroup(r2);
            }
        }

        private void ReadGroup(ParamsReader r) {
            string grp_name = r["name"].InnerText;
            string tpnam = r["type"].InnerText;
            ConditionTypes ctype =(ConditionTypes)Enum.Parse(typeof(ConditionTypes), tpnam, true);
            string format = r["format"].InnerText;
            foreach (ParamsReader r2 in r.EnumChildren("assign")) {
                string cname = r2["name"].InnerText;
                ParamsReader match = r2["match"];
                if(match.IsNull){
                    string v_from = r2["from"].InnerText;
                    string v_until = r2["until"].InnerText;
                    PrimitiveConditions.CreateSceneConditionFromDateFormat(grp_name, cname, ctype, format, v_from, v_until );
                } else {
                    string v_match = match.InnerText;
                    PrimitiveConditions.CreateSceneConditionFromDateFormat(grp_name, cname, ctype, format, v_match);
                }
            }
        }

        private void ReadPredefinedGroup(ParamsReader r) {
            string name = r["name"].InnerText;
            string tpnam = r["type"].InnerText.ToLower();
            string culnam = r["culture"].InnerText;
            CultureInfo culture = culnam!=null ? CultureInfo.GetCultureInfo(culnam):CultureInfo.CurrentCulture;
            Type t = typeof(DateTimeFormatInfo);
            string[] arr = t.InvokeMember(name, BindingFlags.InvokeMethod|BindingFlags.GetProperty, null, culture.DateTimeFormat, null) as string[];
            if ("weekly".Equals(tpnam) && arr.Length >= 7) {
                PrepareDayOfWeekGroup(arr);
            } else if ("monthly".Equals(tpnam) && arr.Length >= 12) { // なぜか13個の要素がある
                PrepareMonthGroup(arr);
            } else {
                Debug.WriteLine("Unknown array: "+name);
            }
        }

        private void PrepareDayOfWeekGroup(string[] arr) {
            for(int i=0; i<arr.Length; i++){
                PrimitiveConditions.CreateSceneCondition("DayOfWeekName", arr[i], ConditionTypes.Weekly, i, TimeUnit.Day);
            }
        }

        private void PrepareMonthGroup(string[] arr) {
            for (int i = 0; i < 12; i++) {
                PrimitiveConditions.CreateSceneCondition("MonthName", arr[i], ConditionTypes.Yearly, i, TimeUnit.Month);
            }
        }

        public static ISceneCondition CreateCondition(string name, ConditionTypes ctype, IComparable from, IComparable to) {

            return null;
        }

        #region IGlobalModule implementation
        public Type RegistType {
            get {
                return typeof(Calendar);
            }
        }
        #endregion
    }
}
