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

using BeWo.Core;
using BeWo.Validation;
using BeWo.ViewModel.ListViewModel;

using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;

namespace BeWo.ViewModel
{
    public class PersonVM : AbstractDCMapperVM<PersonDC>
    {
        public static string PropertyName_DateOfBirth = "DateOfBirth";

        public static string PropertyName_FirstName = "FirstName";

        public static string PropertyName_Function = "Function";

        public static string PropertyName_InvoiceAddressPostalCode = "InvoiceAddressPostalCode";

        public static string PropertyName_InvoiceAddressStreet = "InvoiceAddressStreet";

        public static string PropertyName_InvoiceAddressTown = "InvoiceAddressTown";

        public static string PropertyName_IsArchived = "IsArchived";

        public static string PropertyName_IsFemale = "IsFemale";

        public static string PropertyName_IsMale = "IsMale";

        public static string PropertyName_LastName = "LastName";

        public static string PropertyName_NewOrganisationRelation = "NewOrganisationRelation";

        public static string PropertyName_Notice = "Notice";

        public static string PropertyName_OrganisationRelations = "OrganisationRelations";

        public static string PropertyName_PostalCode = "PostalCode";

        public static string PropertyName_PrivateEMail = "EMail";

        public static string PropertyName_PrivateFax = "Fax";

        public static string PropertyName_PrivateHomepage = "Homepage";

        public static string PropertyName_PrivateMobilePhone = "PrivateMobilePhone";

        public static string PropertyName_PrivatePhone = "Phone";

        public static string PropertyName_Sex = "Sex";

		public static string PropertyName_AddressLine1 = "AddressLine1";

        public static string PropertyName_Street = "Street";

        public static string PropertyName_Title = "Title";

        public static string PropertyName_Town = "Town";

        public static string PropertyName_VarFields = "VarFields";

        private DateTime? _DateOfBirth;

        private string _FirstName;

        private ValueListEntryDC _Function;

        private ObservableSortCollection<ValueListEntryDC> _Functions;

        private string _InvoiceAddressPostalCode;

        private string _InvoiceAddressStreet;

        private string _InvoiceAddressTown;

        private bool _IsArchived;

        private bool _IsFemale;

        private bool _IsMale;

        private string _LastName;

        private PersonOrganisationRelationVM _NewOrganisationRelation;

        private string _Notice;

        private PersonOrganisationRelationListVM _OrganisationRelations;
		
        private string _PostalCode;

        private string _PrivateEMail;

        private string _PrivateFax;

        private string _PrivateHomepage;

        private string _PrivateMobilePhone;

        private string _PrivatePhone;

        private string _AddressLine1;

		private string _Street;

        private ValueListEntryDC _Title;

        private ObservableSortCollection<ValueListEntryDC> _Titles;

        private string _Town;

        private VarFieldListVM _VarFields;

        public PersonVM(PersonDC pDataContract, List<ValueListEntryDC> pPossibleTitles, List<ValueListEntryDC> pPossibleFunctions) : base(pDataContract, pDataContract.PersonOid == null)
        {
            this._Titles = new ObservableSortCollection<ValueListEntryDC>(pPossibleTitles, Comparer.ValueListEntryDCComparer);

            this._Functions = new ObservableSortCollection<ValueListEntryDC>(pPossibleFunctions, Comparer.ValueListEntryDCComparer);
        }

        public DateTime? DateOfBirth
        {
            get { return this._DateOfBirth; }

            set
            {
                if (this.AreDifferent(this._DateOfBirth, value))
                {
                    this._DateOfBirth = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.DateOfBirth, value), PropertyName_DateOfBirth);

                    this.FirePropertyChanged(PropertyName_DateOfBirth);
                }
            }
        }

        public string FirstName
        {
            get { return this._FirstName; }

            set
            {
                if (this.AreDifferent(this._FirstName, value))
                {
                    this._FirstName = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.FirstName, value), PropertyName_FirstName);

                    this.FirePropertyChanged(PropertyName_FirstName);
                }
            }
        }

        public ValueListEntryDC Function
        {
            get { return this._Function; }

            set
            {
                if (this.AreDifferent(this._Function, value))
                {
                    this._Function = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.Function, value), PropertyName_Function);

                    this.FirePropertyChanged(PropertyName_Function);
                }
            }
        }

        public ObservableSortCollection<ValueListEntryDC> Functions
        {
            get
            {
                if (this._Functions == null)
                {
                    this._Functions = new ObservableSortCollection<ValueListEntryDC>();
                }

                return this._Functions;
            }
        }

        public string InvoiceAddressPostalCode
        {
            get { return this._InvoiceAddressPostalCode; }

            set
            {
                if (this.AreDifferent(this._InvoiceAddressPostalCode, value))
                {
                    this._InvoiceAddressPostalCode = value;
                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.InvoiceAddressPostalCode, value), PropertyName_InvoiceAddressPostalCode);
                    this.FirePropertyChanged(PropertyName_InvoiceAddressPostalCode);
                }
            }
        }

        public string InvoiceAddressStreet
        {
            get { return this._InvoiceAddressStreet; }

            set
            {
                if (this.AreDifferent(this._InvoiceAddressStreet, value))
                {
                    this._InvoiceAddressStreet = value;
                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.InvoiceAddressStreet, value), PropertyName_InvoiceAddressStreet);
                    this.FirePropertyChanged(PropertyName_InvoiceAddressStreet);
                }
            }
        }

        public string InvoiceAddressTown
        {
            get { return this._InvoiceAddressTown; }

            set
            {
                if (this.AreDifferent(this._InvoiceAddressTown, value))
                {
                    this._InvoiceAddressTown = value;
                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.InvoiceAddressTown, value), PropertyName_InvoiceAddressTown);
                    this.FirePropertyChanged(PropertyName_InvoiceAddressTown);
                }
            }
        }

        public bool IsArchived
        {
            get { return this._IsArchived; }

            set
            {
                if (this.AreDifferent(this._IsArchived, value))
                {
                    this._IsArchived = value;
                    this.StoreDirtyInformation(
                        (value && this.DataContract.ActivationType == ActivationTypeId.Active) || (!value && this.DataContract.ActivationType == ActivationTypeId.Archived), PropertyName_IsArchived);
                    this.FirePropertyChanged(PropertyName_IsArchived);
                }
            }
        }

        public override bool IsDirty
        {

            get
            {
	            //return base.IsDirty || (this._VarFields != null && this._VarFields.IsDirty);

				if (Utils.IsAnyNull(_OrganisationRelations, _VarFields))
				{
					return false;
				}
				return base.IsDirty || this._OrganisationRelations.IsDirty || this._VarFields.IsDirty;
            }
        }


        public bool IsFemale
        {
            get { return this._IsFemale; }

            set
            {
                if (this._IsFemale != value)
                {
                    this._IsFemale = value;
                    this._IsMale = !value;

                    this.StoreDirtyInformation((this.DataContract.Sex == Sex.Female) != value, "sex");

                    this.FirePropertyChanged(PropertyName_IsFemale);
                    this.FirePropertyChanged(PropertyName_IsMale);
                }
            }
        }

        public bool IsMale
        {
            get { return this._IsMale; }

            set
            {
                if (this._IsMale != value)
                {
                    this._IsMale = value;
                    this._IsFemale = !value;

                    this.StoreDirtyInformation((this.DataContract.Sex == Sex.Male) != value, "sex");

                    this.FirePropertyChanged(PropertyName_IsFemale);
                    this.FirePropertyChanged(PropertyName_IsMale);
                }
            }
        }

        [Validation(ValidationRule = ValidationRules.NotNullOrStringEmpty)]
        public string LastName
        {
            get { return this._LastName; }

            set
            {
                if (this.AreDifferent(this._LastName, value))
                {
                    this._LastName = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.LastName, value), PropertyName_LastName);

                    this.FirePropertyChanged(PropertyName_LastName);
                }
            }
        }

		//public PersonOrganisationRelationVM NewOrganisationRelation
		//{
		//    get { return this._NewOrganisationRelation; }

		//    set
		//    {
		//        if (this.AreDifferent(this._NewOrganisationRelation, value))
		//        {
		//            this._NewOrganisationRelation = value;
		//            this.FirePropertyChanged(PropertyName_NewOrganisationRelation);
		//        }
		//    }
		//}

        public string Notice
        {
            get { return this._Notice; }

            set
            {
                if (this.AreDifferent(this._Notice, value))
                {
                    this._Notice = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.PersonNotice, value), PropertyName_Notice);

                    this.FirePropertyChanged(PropertyName_Notice);
                }
            }
        }

		public PersonOrganisationRelationListVM OrganisationRelations
		{
			get { return this._OrganisationRelations; }

			set
			{
				this._OrganisationRelations = value;
				this.FirePropertyChanged(PropertyName_OrganisationRelations);
			}
		}


        public string PostalCode
        {
            get { return this._PostalCode; }

            set
            {
                if (this.AreDifferent(this._PostalCode, value))
                {
                    this._PostalCode = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.PostalCode, value), PropertyName_PostalCode);

                    this.FirePropertyChanged(PropertyName_PostalCode);
                }
            }
        }

        public string PrivateEMail
        {
            get { return this._PrivateEMail; }

            set
            {
                if (this.AreDifferent(this._PrivateEMail, value))
                {
                    this._PrivateEMail = value;

                    this.StoreDirtyInformation(
                        this.DataContract.ContactInformations.Where(con => con.ContactType == ContactType.private_Mail && con.ContactValue == value).SingleOrDefault() == null, 
                        PropertyName_PrivateEMail);

                    this.FirePropertyChanged(PropertyName_PrivateEMail);
                }
            }
        }

        public string PrivateFax
        {
            get { return this._PrivateFax; }

            set
            {
                if (this.AreDifferent(this._PrivateFax, value))
                {
                    this._PrivateFax = value;

                    this.StoreDirtyInformation(
                        this.DataContract.ContactInformations.Where(con => con.ContactType == ContactType.private_Fax && con.ContactValue == value).SingleOrDefault() == null, PropertyName_PrivateFax);

                    this.FirePropertyChanged(PropertyName_PrivateFax);
                }
            }
        }

        public string PrivateHomepage
        {
            get { return this._PrivateHomepage; }

            set
            {
                if (this.AreDifferent(this._PrivateHomepage, value))
                {
                    this._PrivateHomepage = value;

                    this.StoreDirtyInformation(
                        this.DataContract.ContactInformations.Where(con => con.ContactType == ContactType.private_Homepage && con.ContactValue == value).SingleOrDefault() == null, PropertyName_PrivateHomepage);

                    this.FirePropertyChanged(PropertyName_PrivateHomepage);
                }
            }
        }

        public string PrivateMobilePhone
        {
            get { return this._PrivateMobilePhone; }

            set
            {
                if (this.AreDifferent(this._PrivateMobilePhone, value))
                {
                    this._PrivateMobilePhone = value;

                    this.StoreDirtyInformation(
                        this.DataContract.ContactInformations.Where(con => con.ContactType == ContactType.private_MobilePhone && con.ContactValue == value).SingleOrDefault() == null, 
                        PropertyName_PrivateMobilePhone);

                    this.FirePropertyChanged(PropertyName_PrivateMobilePhone);
                }
            }
        }

        public string PrivatePhone
        {
            get { return this._PrivatePhone; }

            set
            {
                if (this.AreDifferent(this._PrivatePhone, value))
                {
                    this._PrivatePhone = value;

                    this.StoreDirtyInformation(
                        this.DataContract.ContactInformations.Where(con => con.ContactType == ContactType.private_Phone && con.ContactValue == value).SingleOrDefault() == null, 
                        PropertyName_PrivatePhone);

                    this.FirePropertyChanged(PropertyName_PrivatePhone);
                }
            }
        }

		public string AddressLine1
		{
			get { return this._AddressLine1; }

			set
			{
				if (this.AreDifferent(this._AddressLine1, value))
				{
					this._AddressLine1 = value;

					this.StoreDirtyInformation(this.AreDifferent(this.DataContract.AddressLine1, value), PropertyName_AddressLine1);

					this.FirePropertyChanged(PropertyName_AddressLine1);
				}
			}
		}

        public string Street
        {
            get { return this._Street; }

            set
            {
                if (this.AreDifferent(this._Street, value))
                {
                    this._Street = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.Street, value), PropertyName_Street);

                    this.FirePropertyChanged(PropertyName_Street);
                }
            }
        }

        public ValueListEntryDC Title
        {
            get { return this._Title; }

            set
            {
                if (this.AreDifferent(this._Title, value))
                {
                    this._Title = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.Title, value), PropertyName_Title);

                    this.FirePropertyChanged(PropertyName_Title);
                }
            }
        }

        public ObservableSortCollection<ValueListEntryDC> Titles
        {
            get
            {
                if (this._Titles == null)
                {
                    this._Titles = new ObservableSortCollection<ValueListEntryDC>();
                }

                return this._Titles;
            }
        }

        public string Town
        {
            get { return this._Town; }

            set
            {
                if (this.AreDifferent(this._Town, value))
                {
                    this._Town = value;

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.Town, value), PropertyName_Town);

                    this.FirePropertyChanged(PropertyName_Town);
                }
            }
        }

        public VarFieldListVM VarFields
        {
            get { return this._VarFields; }

            set
            {
                if (this.AreDifferent(this._VarFields, value))
                {
                    this._VarFields = value;
                    this.FirePropertyChanged(PropertyName_VarFields);
                }
            }
        }

        protected override void InitByDataContract(PersonDC pDataContract)
        {
            this._VarFields = new VarFieldListVM(pDataContract.VarFields);

            if (!this.IsNew)
            {
                this._DateOfBirth = pDataContract.DateOfBirth;
                this._FirstName = pDataContract.FirstName;
                this._LastName = pDataContract.LastName;
                this._PostalCode = pDataContract.PostalCode;
                this._Street = pDataContract.Street;
				this._AddressLine1 = pDataContract.AddressLine1;
                this._Town = pDataContract.Town;
                this._InvoiceAddressPostalCode = pDataContract.InvoiceAddressPostalCode;
                this._InvoiceAddressStreet = pDataContract.InvoiceAddressStreet;
                this._InvoiceAddressTown = pDataContract.InvoiceAddressTown;
                this._Notice = pDataContract.PersonNotice;
                this._IsArchived = pDataContract.ActivationType == ActivationTypeId.Archived;

                this._IsMale = pDataContract.Sex == Sex.Male;
				this._IsFemale = pDataContract.Sex == Sex.Female;
                this._Title = pDataContract.Title;
                this._Function = pDataContract.Function;

                foreach (ContactDC iContactDC in pDataContract.ContactInformations)
                {
                    if (iContactDC.ContactType == ContactType.private_Mail)
                    {
                        this._PrivateEMail = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.private_Fax)
                    {
                        this._PrivateFax = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.private_Homepage)
                    {
                        this._PrivateHomepage = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.private_Phone)
                    {
                        this._PrivatePhone = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.private_MobilePhone)
                    {
                        this._PrivateMobilePhone = iContactDC.ContactValue;
                    }
                }

				

				//foreach (Organisation2PersonDC iOrganisationRel in pDataContract.OrganisationRelations)
				//{
				//    this.OrganisationRelations.Add(new PersonOrganisationRelationVM(iOrganisationRel));
				//}
            }
			OrganisationRelations = new PersonOrganisationRelationListVM(pDataContract.OrganisationRelations ??
				(pDataContract.OrganisationRelations = new List<Organisation2PersonDC>()));
			//this.OrganisationRelations.ListChanged +=
			//    (s, e) =>
			//    this.StoreDirtyInformation(!this._OrganisationRelations.Select(vm => vm.DataContract).ContainsSameItemsAs(pDataContract.OrganisationRelations), PropertyName_OrganisationRelations);
        }

        protected override PersonDC MapToDataContract(PersonDC pDataContract, bool doCommit)
        {
            pDataContract.DateOfBirth = this._DateOfBirth;
            pDataContract.FirstName = this._FirstName;
            pDataContract.LastName = this._LastName;
            pDataContract.PostalCode = this._PostalCode;
            pDataContract.Street = this._Street;
			pDataContract.AddressLine1 = this._AddressLine1;
            pDataContract.Town = this._Town;
            pDataContract.InvoiceAddressStreet = this._InvoiceAddressStreet;
            pDataContract.InvoiceAddressTown = this._InvoiceAddressTown;
            pDataContract.InvoiceAddressPostalCode = this._InvoiceAddressPostalCode;
            pDataContract.ActivationType = this._IsArchived ? ActivationTypeId.Archived : ActivationTypeId.Active;

            pDataContract.PersonNotice = this._Notice;
            if (this._VarFields != null)
            {
                pDataContract.VarFields = this._VarFields.CopyToDCList(doCommit);
            }

            this.CommitContact(this._PrivateMobilePhone, ContactType.private_MobilePhone);
            this.CommitContact(this._PrivatePhone, ContactType.private_Phone);
            this.CommitContact(this._PrivateFax, ContactType.private_Fax);
            this.CommitContact(this._PrivateHomepage, ContactType.private_Homepage);
            this.CommitContact(this._PrivateEMail, ContactType.private_Mail);

			if (this._IsMale)
				pDataContract.Sex = Sex.Male;
			if (this._IsFemale)
				pDataContract.Sex = Sex.Female;

			//List<Organisation2PersonDC> lOrganisationRel = new List<Organisation2PersonDC>();
			//foreach (PersonOrganisationRelationVM iRelVM in this._OrganisationRelations)
			//{
			//    lOrganisationRel.Add(iRelVM.CommitToDataContract());
			//}
			//pDataContract.OrganisationRelations = lOrganisationRel;

			pDataContract.OrganisationRelations = this._OrganisationRelations.CopyToDCList(doCommit);

            

            pDataContract.Title = this._Title;
            pDataContract.Function = this._Function;

            return pDataContract;
        }

        private void CommitContact(string pValue, ContactType pContactType)
        {
            List<ContactDC> lOldContactDCs;
            if (this.DataContract.ContactInformations != null)
            {
                lOldContactDCs = this.DataContract.ContactInformations.ToList();
            }
            else
            {
                lOldContactDCs = new List<ContactDC>();
            }

            ContactDC lContactDC = lOldContactDCs.SingleOrDefault(con => con.ContactType == pContactType);

            if (string.IsNullOrEmpty(pValue) && lContactDC != null)
            {
                lOldContactDCs.Remove(lContactDC);
            }
            else if (!string.IsNullOrEmpty(pValue))
            {
                if (lContactDC == null)
                {
                    lContactDC = new ContactDC
                        {
                            ContactType = pContactType
                        };
                    lOldContactDCs.Add(lContactDC);
                }

                lContactDC.ContactValue = pValue;
            }

            this.DataContract.ContactInformations = lOldContactDCs;
        }
    }
}