using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using BeWo.Validation;
using BeWo.ViewModel.ListViewModel;

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

namespace BeWo.ViewModel
{
    public class OrganisationVM : AbstractDCMapperVM<OrganisationDC>
    {
        public static string PropertyName_AccountNumber = "AccountNumber";

        public static string PropertyName_BankCode = "BankCode";

        public static string PropertyName_BankName = "BankName";

        public static string PropertyName_Bic = "Bic";

        public static string PropertyName_ContactPerson = "ContactPerson";

        public static string PropertyName_CostRatePeriods = "CostRatePeriods";

        public static string PropertyName_EMail = "EMail";

        public static string PropertyName_Fax = "Fax";

        public static string PropertyName_IBAN = "IBAN";

        public static string PropertyName_InvoiceAddressPOBox = "InvoiceAddressPOBox";

        public static string PropertyName_InvoiceAddressPostalCode = "InvoiceAddressPostalCode";

        // public static string PropertyName_IsCostBearer = "IsCostBearer";
        public static string PropertyName_InvoiceAddressStreet = "InvoiceAddressStreet";

        public static string PropertyName_InvoiceAddressTown = "InvoiceAddressTown";

        public static string PropertyName_IsCalculatingWithFactor = "IsCalculatingWithFactor";

        public static string PropertyName_IsSingleInvoicePerCustomer = "IsSingleInvoicePerCustomer";

        public static string PropertyName_Name = "Name";

        public static string PropertyName_Notice = "Notice";

        public static string PropertyName_POBox = "POBox";

        public static string PropertyName_Phone = "Phone";

        public static string PropertyName_PossibleQualifications = "PossibleQualifications";

        public static string PropertyName_PersonRelations = "PersonRelations";

        public static string PropertyName_PostalCode = "PostalCode";

        public static string PropertyName_Street = "Street";

        public static string PropertyName_Town = "Town";

        public static string PropertyName_Website = "Website";

        public static string PropertyName_DebitorNumber = "DebitorNumber";

		public static string PropertyName_IsArchived = "IsArchived";

		public static string PropertyName_VarFields = "VarFields";

        private readonly List<ValueListEntryDC> _AllQualifications;

        private string _AccountNumber;

        private string _BankCode;

        private string _BankName;

        private string _Bic;

        private string _ContactPerson;

        private CostRatePeriodListVM _CostRatePeriods;

        private string _EMail;

        private string _Fax;

        private string _IBAN;

        private string _InvoiceAddressPOBox;

        private string _InvoiceAddressPostalCode;

        private string _InvoiceAddressStreet;

        private string _InvoiceAddressTown;

        private bool _IsCalculatingWithFactor;

        private bool _IsSingleInvoicePerCustomer;

        private string _Name;

        private string _Notice;

        private string _POBox;

        private string _Phone;

        private OrganisationPersonRelationListVM _PersonRelations;

        private string _PostalCode;

        private string _Street;

        private string _Town;

        private string _Website;

        private string _DebitorNumber;

		private bool _IsArchived;

		private VarFieldListVM _VarFields;

        public OrganisationVM(OrganisationDC pDataContract, List<ValueListEntryDC> pAllQualifications) : base(pDataContract, pDataContract.OrganisationOid == null)
        {
            this._AllQualifications = pAllQualifications;
        }

        public string AccountNumber
        {
            get { return this._AccountNumber; }

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

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.AccountNumber, value), PropertyName_AccountNumber);

                    this.FirePropertyChanged(PropertyName_AccountNumber);
                }
            }
        }

        public string BankCode
        {
            get { return this._BankCode; }

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

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.BankCode, value), PropertyName_BankCode);

                    this.FirePropertyChanged(PropertyName_BankCode);
                }
            }
        }

        public string BankName
        {
            get { return this._BankName; }

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

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.BankName, value), PropertyName_BankName);

                    this.FirePropertyChanged(PropertyName_BankName);
                }
            }
        }

        public string Bic
        {
            get { return this._Bic; }

            set
            {
                if (this.AreDifferent(this._Bic, value))
                {
                    this._Bic = value;
                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.Bic, value), PropertyName_Bic);
                    this.FirePropertyChanged(PropertyName_Bic);
                }
            }
        }

        public string ContactPerson
        {
            get { return this._ContactPerson; }

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

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

                    this.FirePropertyChanged(PropertyName_ContactPerson);
                }
            }
        }

        public CostRatePeriodListVM CostRatePeriods
        {
            get { return this._CostRatePeriods; }

            set
            {
                if (this.AreDifferent(this._CostRatePeriods, value))
                {
                    this._CostRatePeriods = value;
                    this.FirePropertyChanged(PropertyName_CostRatePeriods);
                }
            }
        }

        public string EMail
        {
            get { return this._EMail; }

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

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

                    this.FirePropertyChanged(PropertyName_EMail);
                }
            }
        }

        public string Fax
        {
            get { return this._Fax; }

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

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

                    this.FirePropertyChanged(PropertyName_Fax);
                }
            }
        }

        public string IBAN
        {
            get { return this._IBAN; }

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

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.IBAN, value), PropertyName_IBAN);

                    this.FirePropertyChanged(PropertyName_IBAN);
                }
            }
        }

        public string InvoiceAddressPOBox
        {
            get { return this._InvoiceAddressPOBox; }

            set
            {
                if (this.AreDifferent(this._InvoiceAddressPOBox, value))
                {
                    this._InvoiceAddressPOBox = value;
                    this.StoreDirtyInformation(
                        this.DataContract.ContactInformations.Where(con => con.ContactType == ContactType.private_POBox && con.ContactValue == value).SingleOrDefault() == null, 
                        PropertyName_InvoiceAddressPOBox);
                    this.FirePropertyChanged(PropertyName_InvoiceAddressPOBox);
                }
            }
        }

        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 IsCalculatingWithFactor
        {
            get { return this._IsCalculatingWithFactor; }

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

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.IsCalculatingWithFactor, value), PropertyName_IsCalculatingWithFactor);

                    this.FirePropertyChanged(PropertyName_IsCalculatingWithFactor);
                }
            }
        }

		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
            {
				if (Utils.IsAnyNull(this._CostRatePeriods, _VarFields))
				{
					return false;
				}

				return base.IsDirty || this._CostRatePeriods.IsDirty || this._VarFields.IsDirty;
            }
        }

        public bool IsSingleInvoicePerCustomer
        {
            get { return this._IsSingleInvoicePerCustomer; }

            set
            {
                if (this.AreDifferent(this._IsSingleInvoicePerCustomer, value))
                {
                    this._IsSingleInvoicePerCustomer = value;
                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.IsSingleInvoicePerCustomer, value), PropertyName_IsSingleInvoicePerCustomer);
                    this.FirePropertyChanged(PropertyName_IsSingleInvoicePerCustomer);
                }
            }
        }

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

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

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.Name, value), PropertyName_Name);

                    this.FirePropertyChanged(PropertyName_Name);
                }
            }
        }

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

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

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

                    this.FirePropertyChanged(PropertyName_Notice);
                }
            }
        }

        public string POBox
        {
            get { return this._POBox; }

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

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

                    this.FirePropertyChanged(PropertyName_POBox);
                }
            }
        }

        public string Phone
        {
            get { return this._Phone; }

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

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

                    this.FirePropertyChanged(PropertyName_Phone);
                }
            }
        }

        public List<ValueListEntryDC> PossibleQualifications
        {
            get
            {
                var existing = this._CostRatePeriods.VMList.Where(i => i.ValueListEntry != null).Select(i => i.ValueListEntry.ValueListEntryOid).Distinct().ToList();

                return this._AllQualifications.Where(i => !existing.Contains(i.ValueListEntryOid)).ToList();
            }
        }

        public OrganisationPersonRelationListVM PersonRelations
        {
            get { return _PersonRelations; }

            set
            {
                _PersonRelations = value;
                FirePropertyChanged(PropertyName_PersonRelations);
            }
        }

        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 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 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 string Website
        {
            get { return this._Website; }

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

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

                    this.FirePropertyChanged(PropertyName_Website);
                }
            }
        }

        public string DebitorNumber
        {
            get { return this._DebitorNumber; }

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

                    this.StoreDirtyInformation(this.AreDifferent(this.DataContract.DebitorNumber, value), PropertyName_DebitorNumber);

                    this.FirePropertyChanged(PropertyName_DebitorNumber);
                }
            }
        }

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

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

        protected 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;
        }

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

            if (!this.IsNew)
            {
                this._AccountNumber = pDataContract.AccountNumber;
                this._BankCode = pDataContract.BankCode;
                this._BankName = pDataContract.BankName;
                this._Bic = pDataContract.Bic;
                this._IBAN = pDataContract.IBAN;
                this._Name = pDataContract.Name;
                this._Notice = pDataContract.OrganisationNotice;
                this._PostalCode = pDataContract.PostalCode;
                this._Street = pDataContract.Street;
                this._Town = pDataContract.Town;
                this._InvoiceAddressPostalCode = pDataContract.InvoiceAddressPostalCode;
                this._InvoiceAddressStreet = pDataContract.InvoiceAddressStreet;
                this._InvoiceAddressTown = pDataContract.InvoiceAddressTown;
                this._IsCalculatingWithFactor = pDataContract.IsCalculatingWithFactor;
                this._IsSingleInvoicePerCustomer = pDataContract.IsSingleInvoicePerCustomer;
                this._DebitorNumber = pDataContract.DebitorNumber;
				this._IsArchived = pDataContract.ActivationType == ActivationTypeId.Archived;

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

                    if (iContactDC.ContactType == ContactType.business_Homepage)
                    {
                        this._Website = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.business_Fax)
                    {
                        this._Fax = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.business_Phone)
                    {
                        this._Phone = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.ContactPerson)
                    {
                        this._ContactPerson = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.ContactPerson)
                    {
                        this._ContactPerson = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.business_POBox)
                    {
                        this._POBox = iContactDC.ContactValue;
                    }

                    if (iContactDC.ContactType == ContactType.private_POBox)
                    {
                        this._InvoiceAddressPOBox = iContactDC.ContactValue;
                    }
                }
            }

            VMFactory.CreateOrganisationPersonRelationListVMAsync(
                pDataContract.RelatedPersons ?? (pDataContract.RelatedPersons = new List<OrganisationPersonRelationDC>()), cb => PersonRelations = cb);

            if (pDataContract.CostRatePeriods == null)
            {
                pDataContract.CostRatePeriods = new List<CostRatePeriodDC>();
            }

            Utils.GetAllEnumValues<CostRatePeriodType>().ToList().ForEach(
                t =>
                    {
                        if (t != CostRatePeriodType.Unknown && !pDataContract.CostRatePeriods.Exists(i => i.CostRateType == t))
                        {
                            pDataContract.CostRatePeriods.Add(
                                new CostRatePeriodDC
                                    {
                                        CostRateType = t
                                    });
                        }
                    });

            this._CostRatePeriods = new CostRatePeriodListVM(pDataContract.CostRatePeriods);

            this._CostRatePeriods.VMList.ListChanged += (s, e) =>
                {
                    if (e.ListChangedType != ListChangedType.ItemChanged)
                    {
                        this.FirePropertyChanged(PropertyName_PossibleQualifications);
                    }
                };
        }

        protected override OrganisationDC MapToDataContract(OrganisationDC pDataContract, bool doCommit)
        {
            pDataContract.AccountNumber = this._AccountNumber;
            pDataContract.BankCode = this._BankCode;
            pDataContract.BankName = this._BankName;
            pDataContract.Bic = this._Bic;
            pDataContract.IBAN = this._IBAN;
            pDataContract.Name = this._Name;
            pDataContract.OrganisationNotice = this._Notice;
            pDataContract.PostalCode = this._PostalCode;
            pDataContract.RelatedPersons = this._PersonRelations.CopyToDCList(doCommit);
            pDataContract.Street = this._Street;
            pDataContract.Town = this._Town;
            pDataContract.InvoiceAddressStreet = this._InvoiceAddressStreet;
            pDataContract.InvoiceAddressTown = this._InvoiceAddressTown;
            pDataContract.InvoiceAddressPostalCode = this._InvoiceAddressPostalCode;
            pDataContract.IsCalculatingWithFactor = this._IsCalculatingWithFactor;
            pDataContract.IsSingleInvoicePerCustomer = this._IsSingleInvoicePerCustomer;
            pDataContract.DebitorNumber = this._DebitorNumber;
			pDataContract.ActivationType = this._IsArchived ? ActivationTypeId.Archived : ActivationTypeId.Active;

            this.CommitContact(this._Phone, ContactType.business_Phone);
            this.CommitContact(this._Website, ContactType.business_Homepage);
            this.CommitContact(this._Fax, ContactType.business_Fax);
            this.CommitContact(this._EMail, ContactType.business_Mail);
            this.CommitContact(this._ContactPerson, ContactType.ContactPerson);
            this.CommitContact(this._POBox, ContactType.business_POBox);
            this.CommitContact(this._InvoiceAddressPOBox, ContactType.private_POBox);

            pDataContract.CostRatePeriods = this._CostRatePeriods.CopyToDCList(doCommit);

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

            return pDataContract;
        }
    }
}