using System;
using System.Collections.Generic;
using System.Linq;

using BeWo.ServiceProxy;
using BeWo.Validation;

using BS.Shared.Extensions;
using BS.Shared.DataContracts.Compact;
using BS.Shared.DataContracts;

namespace BeWo.ViewModel
{
    public class AdditionalServiceGroupOfPeopleRelationVM : AbstractDCMapperVM<AdditionalServiceGroupOfPeopleRelationDC>
    {
        #region Constants and Fields
        public static string PropertyName_AdditionalServiceOid = "AdditionalServiceOid";
        
        public static string PropertyName_AdditionalServiceNotice = "AdditionalServiceNotice";
        
        public static string PropertyName_AdditionalServiceVersion = "AdditionalServiceVersion";
        
        public static string PropertyName_RoundedDuration = "RoundedDuration";
        
        public static string PropertyName_Date = "Date";

        public static string PropertyName_AdditionalServiceGroupOfPeople = "AdditionalServiceGroupOfPeople";

        public static string PropertyName_AdditionalServiceGroupOfPeopleString = "AdditionalServiceGroupOfPeopleString";

        public static string PropertyName_AdditionalService = "AdditionalService";

        public static string PropertyName_AdditionalServiceString = "AdditionalServiceString";

        public static string PropertyName_AdditionalServiceRegion = "AdditionalServiceRegion";

        public static string PropertyName_AdditionalServiceRegionString = "AdditionalServiceRegionString";

        public static string PropertyName_StartTime = "StartTimeEditString";

        public static string PropertyName_EndTime = "EndTimeEditString";


        private static readonly DateTime NULL_TIME = new DateTime(2000, 1, 1, 0, 0, 1);

        private AdditionalServiceGroupOfPeopleDC _AdditionalServiceGroupOfPeople;

        private AdditionalServiceDC _AdditionalService;

        private AdditionalServiceRegionDC _AdditionalServiceRegion;

        private decimal? _RoundedDuration;

        private DateTime _Date;
        private DateTime? _StartTime;
        private DateTime? _EndTime;
        #endregion

        #region Constructors and Destructors

        public AdditionalServiceGroupOfPeopleRelationVM(AdditionalServiceGroupOfPeopleRelationDC pDC)
            : base(pDC, pDC.AdditionalService2GroupOfPeopleOid == null)
        {
        }

        #endregion

        #region Properties
        [Validation(ValidationRule = ValidationRules.NotNullOrStringEmpty)]
        public AdditionalServiceGroupOfPeopleDC AdditionalServiceGroupOfPeople
        {
            get { return _AdditionalServiceGroupOfPeople; }

            set
            {
                if(AreDifferent(_AdditionalServiceGroupOfPeople, value))
                {
                    _AdditionalServiceGroupOfPeople = value;

                    StoreDirtyInformation(AreDifferent(DataContract.AdditionalServiceGroupOfPeople, value), PropertyName_AdditionalServiceGroupOfPeople);
                    FirePropertyChanged(PropertyName_AdditionalServiceGroupOfPeople);
                    FirePropertyChanged(PropertyName_AdditionalServiceGroupOfPeopleString);
                }
            }
        }

        [Validation(ValidationRule = ValidationRules.NotNullOrStringEmpty)]
        public AdditionalServiceDC AdditionalService
        {
            get { return _AdditionalService; }

            set
            {
                if (!AreDifferent(_AdditionalService, value)) 
                    return;

                _AdditionalService = value;
                StoreDirtyInformation(AreDifferent(DataContract.AdditionalService, value), PropertyName_AdditionalService);
                FirePropertyChanged(PropertyName_AdditionalService);
                FirePropertyChanged(PropertyName_AdditionalServiceString);
            }
        }

        public AdditionalServiceRegionDC AdditionalServiceRegion
        {
            get { return _AdditionalServiceRegion; }

            set
            {
                if (AreDifferent(_AdditionalService, value))
                {
                    _AdditionalServiceRegion = value;
                    StoreDirtyInformation(AreDifferent(DataContract.AdditionalServiceRegion, value), PropertyName_AdditionalServiceRegion);
                    FirePropertyChanged(PropertyName_AdditionalServiceRegion);
                    FirePropertyChanged(PropertyName_AdditionalServiceRegionString);
                }
            }
        }

        [ValidationAttribute(ValidationRule = ValidationRules.GreaterThanOrEqualZero)]
        public decimal? RoundedDuration
        {
            get { return _RoundedDuration; }

            set
            {
                if (value >= 0 && AreDifferent(_RoundedDuration, value))
                {
                    _RoundedDuration = value;

                    if (StartTime != null)
                        EndTime = StartTime.Value.AddMinutes(Convert.ToDouble(value.Value));

                    TimeCheck();
                    FirePropertyChanged(PropertyName_RoundedDuration);
                }
            }
        }

        [ValidationAttribute(ValidationRule = ValidationRules.NotNullOrStringEmpty)]
        public DateTime Date
        {
            get
            {
                return _Date;
            }

            set
            {
                if (!AreDifferent(_Date, value)) 
                    return;

                _Date = value;
                TimeCheck();
                FirePropertyChanged(PropertyName_Date);
            }
        }

        public DateTime? DateAndTime
        {
            get
            {
                DateTime? date = _Date;
                DateTime? time = _StartTime;

                if (date != null && time != null)
                {
                    date = date.Value.AddHours(time.Value.Hour);
                    date = date.Value.AddMinutes(time.Value.Minute);
                    date = date.Value.AddSeconds(time.Value.Second);
                }

                return date;
            }
        }

        [ValidationAttribute(ValidationRule = ValidationRules.NotNullOrStringEmpty)]
        public DateTime? StartTime
        {
            get { return _StartTime; }

            set
            {
                DateTime? newStartTime = value;

                if (newStartTime == null)
                    newStartTime = NULL_TIME;

                if ((_StartTime == null && newStartTime != NULL_TIME) ||
                    (_StartTime != null && _StartTime.Value.TimeOfDay != newStartTime.Value.TimeOfDay))
                {
                    _StartTime = newStartTime;
                    if (_StartTime.Value.Second == 0)
                    {
                        if (_EndTime != null)
                        {
                            var end = new DateTime(_StartTime.Value.Year, _StartTime.Value.Month, _StartTime.Value.Day,
                                                   _EndTime.Value.Hour, _EndTime.Value.Minute, 0);

                            TimeSpan diff = end.Subtract(_StartTime.Value);
                            if (diff.TotalSeconds < 0)
                            {
                                EndTime = _StartTime;
                                end = EndTime.Value;
                            }

                            diff = end.Subtract(_StartTime.Value);
                            RoundedDuration = (int) diff.TotalMinutes;
                        }
                        else if (RoundedDuration != null)
                        {
                            EndTime = _StartTime.Value.AddMinutes(Convert.ToDouble(RoundedDuration.Value));
                        }
                    }
                    
                    TimeCheck();
                    FirePropertyChanged(PropertyName_StartTime);
                }
            }
        }

        public DateTime? EndTime
        {
            get { return _EndTime; }

            set
            {
                if ((_EndTime == null && value != null) || (_EndTime != null && value == null) || (_EndTime != null && _EndTime.Value.TimeOfDay != value.Value.TimeOfDay))
                {
                    _EndTime = value;

                    if (_EndTime != null)
                    {
                        if (_StartTime.Value.Second != 0)
                            StartTime = new DateTime(_EndTime.Value.Year, _EndTime.Value.Month, _EndTime.Value.Day, _EndTime.Value.Hour, 0, 0);

                        DateTime start = new DateTime(_EndTime.Value.Year, _EndTime.Value.Month, _EndTime.Value.Day, StartTime.Value.Hour, StartTime.Value.Minute, 0);

                        TimeSpan diff = _EndTime.Value.Subtract(start);
                        RoundedDuration = (int)diff.TotalMinutes;
                    }

                    FirePropertyChanged(PropertyName_EndTime);
                }
            }
        }

        public String EndTimeEditString
        {
            get
            {
                if (_EndTime == null || _EndTime.Value.Second != 0)
                    return null;

                return String.Format("{0:HH:mm}", _EndTime);
            }

            set
            {
                if (String.IsNullOrEmpty(value))
                    EndTime = null;
                else
                {
                    DateTime? endTime = EndTime;
                    if (!endTime.HasValue)
                        endTime = EndDate;
                    if (!endTime.HasValue)
                        endTime = DateTime.Now;

                    String dtStr = String.Format("{0:dd.MM.yyyy} {1}", endTime, value);
                    DateTime dt;
                    if (DateTime.TryParse(dtStr, out dt))
                        EndTime = dt;
                    else
                        EndTime = null;
                }

                FirePropertyChanged(PropertyName_EndTime);
            }
        }

        public DateTime? EndDate
        {
            get
            {
                DateTime? dt = DateAndTime;
                if (dt.HasValue)
                {
                    if (_StartTime != null)
                    {
                        DateTime timeDt = _StartTime.Value;
                        dt = timeDt.AddMinutes((double)RoundedDuration);
                    }
                }

                return dt;
            }
        }

        public DateTime? EndMinutes
        {
            get { return EndDate.HasValue && EndDate.Value.Second == 0 ? EndDate : null; }
        }


        public DateTime? StartDate
        {
            get { return DateAndTime; }
        }

        public DateTime? StartMinutes
        {
            get { return StartDate.HasValue && StartDate.Value.Second == 0 ? StartDate : null; }
        }

        public String StartTimeEditString
        {
            get
            {
                if (_StartTime == null || _StartTime.Value.Second != 0)
                    return null;

                return String.Format("{0:HH:mm}", _StartTime);
            }

            set
            {
                if (String.IsNullOrEmpty(value))
                    StartTime = null;
                else
                {
                    DateTime? startTime = StartTime;
                    if (!startTime.HasValue)
                        startTime = StartDate;
                    if (!startTime.HasValue)
                        startTime = DateTime.Now;

                    String dtStr = String.Format("{0:dd.MM.yyyy} {1}", startTime, value);
                    DateTime dt;
                    if (DateTime.TryParse(dtStr, out dt))
                        StartTime = dt;
                    else
                        StartTime = null;
                }

                FirePropertyChanged(PropertyName_StartTime);
            }
        }
        #endregion

        #region Methods
        protected override void InitByDataContract(AdditionalServiceGroupOfPeopleRelationDC pDataContract)
        {
            if (IsNew)
            {
                _Date = DateTime.Now.Date;
                _StartTime = NULL_TIME;
                _RoundedDuration = 0;
                return;
            }

            _AdditionalService = pDataContract.AdditionalService;
            _AdditionalServiceGroupOfPeople = pDataContract.AdditionalServiceGroupOfPeople;
            _AdditionalServiceRegion = pDataContract.AdditionalServiceRegion;

            if (pDataContract.EndDate == null)
            {
                var End = (pDataContract.StartDate.Value.AddMinutes(Convert.ToDouble(pDataContract.RoundedDuration)));
                _RoundedDuration = Convert.ToDecimal((End - pDataContract.StartDate.Value).GetTotalMinutes());
            }
            else
                _RoundedDuration = Convert.ToDecimal((pDataContract.EndDate.Value - pDataContract.StartDate.Value).GetTotalMinutes());

            _Date = pDataContract.Date.Value;
            _StartTime = pDataContract.StartDate;
            
            if (pDataContract.StartDate != null && pDataContract.StartDate.Value.Second == 0 && _RoundedDuration != null)
                _EndTime = pDataContract.StartDate.Value.AddMinutes(Convert.ToDouble(_RoundedDuration.Value));
            else
                _EndTime = pDataContract.EndDate;
        }

        protected override AdditionalServiceGroupOfPeopleRelationDC MapToDataContract(AdditionalServiceGroupOfPeopleRelationDC pDataContract, bool doCommit)
        {
            pDataContract.AdditionalService = _AdditionalService;
            pDataContract.AdditionalServiceGroupOfPeople = _AdditionalServiceGroupOfPeople;
            pDataContract.AdditionalServiceRegion = _AdditionalServiceRegion;

            pDataContract.RoundedDuration = _RoundedDuration.Value;
            pDataContract.Date = _Date;

            if (_StartTime != null)
                pDataContract.StartDate = new DateTime(_Date.Year, _Date.Month, _Date.Day, _StartTime.Value.Hour, _StartTime.Value.Minute, _StartTime.Value.Second);
            else
                pDataContract.StartDate = null;

            pDataContract.EndDate = _EndTime != null
                                        ? new DateTime(_Date.Year, _Date.Month, _Date.Day, _EndTime.Value.Hour, _EndTime.Value.Minute, _EndTime.Value.Second)
                                        : _StartTime.Value.AddMinutes(Convert.ToDouble(_RoundedDuration));

            return pDataContract;
        }

        private void TimeCheck()
        {   
            int duration = 0;
            if (_RoundedDuration.HasValue)
                duration = (int)_RoundedDuration.Value;

            StoreDirtyInformation(AreDifferent(DataContract.EndDate, (_Date + _StartTime.Value.TimeOfDay).AddMinutes(duration)) ||
                                    AreDifferent(DataContract.StartDate, _Date + _StartTime.Value.TimeOfDay), "TIME");
        }
        #endregion
    }
}
