using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using BeWo.Scheduler.Resources;
using BeWo.Scheduler.View;
using BeWo.ViewModel;
using BeWo.ViewModel.ListViewModel;
using BS.Shared.DataContracts;
using DevExpress.Xpf.Scheduler;
using DevExpress.XtraScheduler;
using SchedulerControl = DevExpress.Xpf.Scheduler.SchedulerControl;
using SchedulerStorage = DevExpress.Xpf.Scheduler.SchedulerStorage;

namespace BeWo.Scheduler.ViewModel
{
    public abstract class AbstractAppointmentListVM<DCType, VMType> : AbstractDCListMapperVM<DCType, VMType>,
        ISchedulerViewModel where VMType : AbstractDCMapperVM<DCType>, IBeWoAppointment where DCType : new()
    {
        private List<BeWoAppointmentCategory> mAppointmentCategoryList;
        private BindingList<IBeWoAppointment> mAppointmentList;
        private List<IBeWoAppointmentResource> mAppointmentResourceList;

        public AbstractAppointmentListVM(IEnumerable<DCType> appList) : base(appList)
        {
        }

        public IEnumerable<BeWoAppointmentCategory> Categories
        {
            get { return mAppointmentCategoryList; }
        }

        public IList<IBeWoAppointmentResource> Resources
        {
            get { return mAppointmentResourceList; }
        }

		public Dictionary<Guid, Dictionary<string, Dictionary<string, object>>> ChangedOccurencyCustomFields { get; private set; }

	    public object SelectedFilterObject { get; set; }

	    public virtual bool FilterAppointment(string filterCategory, object selectedObject, Appointment appointment, bool showPrivateAppointments)
        {
            return false;
        }

	    public void InitChangedOccurrencyCustomFields(IEnumerable<SchedulerAppointmentDC> appList) { }

	    public BindingList<IBeWoAppointment> Appointments
        {
            get
            {
	            if (mAppointmentList != null) return mAppointmentList;

	            mAppointmentList = new BindingList<IBeWoAppointment>();

	            foreach (var vm in VMList)
		            mAppointmentList.Add(vm);

	            mAppointmentList.AddingNew += mAppointmentList_AddingNew;

	            return mAppointmentList;
            }
        }

        public abstract SchedulerSettings GetDefaultSchedulerSettings();

		public void SaveAppointments(SchedulerControl control, IList<Appointment> list)
        {
            var dcList = new List<DCType>();
            foreach (var appointment in list)
            {
                var vm = appointment.GetSourceObject(control.GetCoreStorage()) as VMType;
	            if (vm == null) continue;
	            UpdateAppointment(appointment, vm);
	            dcList.Add(vm.CommitToDataContract());
            }

            if (dcList.Count > 0)
                SaveAppointments(dcList);
        }

		public void DeleteAppointments(SchedulerControl control, IList<Appointment> list)
        {
            var dcList = (from appointment in list select appointment.GetSourceObject(control.GetCoreStorage()) as VMType into vm where vm != null && !vm.IsNew select vm.CommitToDataContract()).ToList();
	        if (dcList.Count > 0)
                DeleteAppointments(dcList);
        }

		public void InsertAppointments(SchedulerControl control, IList<Appointment> list)
        {
            var dcList = new List<DCType>();
            foreach (var appointment in list)
            {
                var vm = appointment.GetSourceObject(control.GetCoreStorage()) as VMType;
	            if (vm == null) continue;

	            UpdateAppointment(appointment, vm);
	            dcList.Add(vm.CommitToDataContract());
            }
            if (dcList.Count > 0)
                InsertNewAppointments(dcList);
        }

        public virtual AbstractAppointmentEditForm GetEditAppointmentForm(SchedulerControl control, Appointment appointment)
        {
            return null;
        }

        public virtual void AddCustomFieldsMapping(SchedulerStorage schedulerStorage)
        {
        }

        public virtual void InitNewAppointment(Appointment appointment)
        {
            appointment.StatusId = 0;
        }

        protected void InitViewModel()
        {
            mAppointmentCategoryList = new List<BeWoAppointmentCategory>();
            mAppointmentResourceList = new List<IBeWoAppointmentResource>();

            InitCategoryList(mAppointmentCategoryList);
            InitResourceList(mAppointmentResourceList);
            InitAppointmentList();

            mAppointmentResourceList.Sort((a, b) => a.Caption.CompareTo(b.Caption));
        }

        protected virtual void InitCategoryList(List<BeWoAppointmentCategory> categoryList)
        {
            //
        }

        protected virtual void InitResourceList(List<IBeWoAppointmentResource> resourceList)
        {
            //
        }

        protected virtual void InitAppointmentList()
        {
            //
        }

        private void mAppointmentList_AddingNew(object sender, AddingNewEventArgs e)
        {
            var newApp = CreateNewAppointmentVM();
            e.NewObject = newApp;
        }

        protected abstract IBeWoAppointment CreateNewAppointmentVM();

        protected abstract void SaveAppointments(List<DCType> dcList);

        protected abstract void DeleteAppointments(IEnumerable<DCType> dcList);

        protected abstract void InsertNewAppointments(List<DCType> dcList);

        protected virtual void UpdateAppointment(Appointment app, VMType vm)
        {
        }

        protected virtual void UpdateViewModel(IEnumerable<DCType> updatedDcList)
        {
            foreach (DCType dc in updatedDcList)
            {
                var found = default(VMType);
                foreach (var vm in mAppointmentList.Cast<VMType>().Where(vm => vm.DataContract.Equals(dc)))
	                found = vm;

                if (found != null)
                    found.DataContract = dc;
            }
        }

		protected virtual void UpdateResourceList(List<IBeWoAppointmentResource> resourceList, long pOid)
	    {
			mAppointmentResourceList.Clear();
			mAppointmentResourceList.Add(resourceList.Find(f => f.Id.Equals(pOid)));
	    }
    }
}