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

using BeWo.Data.Access;
using BeWo.Data.Entities;

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

namespace BeWo.Service.DCEntityMapper
{
    public class ValueListEntryDC_ValueListEntry : AbstractIDCEntityMapper<ValueListEntry, ValueListEntryDC>
    {
        public override ValueListEntryDC MergeWithDC(ValueListEntry pEntity, ValueListEntryDC pDataContract)
        {
            pDataContract.ValueListEntryVersion = pEntity.Version;
            pDataContract.TypeDescription = pEntity.Value;
            pDataContract.ValueListEntryOid = pEntity.Oid;
            pDataContract.Type = pEntity.Type;
            pDataContract.Abbreviation = pEntity.Abbreviation;
            pDataContract.IsSystemEntry = pEntity.SystemEntryID != null;
            pDataContract.ParentOid = pEntity.ParentOid;

            return pDataContract;
        }

        public override ValueListEntry MergeWithEntity(ValueListEntryDC pDataContract, ValueListEntry pEntity)
        {
            ConcurrencyCheck(pDataContract.ValueListEntryVersion, pEntity);

            pEntity.Oid = pDataContract.ValueListEntryOid;
            pEntity.Value = pDataContract.TypeDescription;
            pEntity.Abbreviation = pDataContract.Abbreviation;
            pEntity.Type = pDataContract.Type;
            pEntity.ParentOid = pDataContract.ParentOid;

            return pEntity;
        }

        internal void MapUniqueTypeValueListEntryBack2Entity(ValueListEntryDC pValueListEntryDC, IList<ValueListEntry2Object> pValueList, ValueListEntryType pEntryType, TableID pTid)
        {
            // Look whether the entity already has an Entry of that type
            ValueListEntry2Object lEntityListEntry2Object = pValueList.FindSingleByType(pEntryType);

            // if it has and the EntryDC is null we remove the entry from list. It was deleted by the client
            if (pValueListEntryDC == null && lEntityListEntry2Object != null)
            {
                pValueList.Remove(lEntityListEntry2Object);
            }
            else
            {
                // if DC is not null...
                if (pValueListEntryDC != null)
                {
                    // ..and there is no Entry in the List already
                    if (lEntityListEntry2Object == null)
                    {
                        // ...create a new one and add it to the list
                        lEntityListEntry2Object = new ValueListEntry2Object { ObjectTid = pTid };
                        lEntityListEntry2Object.Entry = DAOFactory.GenericDAO.LoadByID<ValueListEntry>(pValueListEntryDC.ValueListEntryOid.Value);
                        pValueList.Add(lEntityListEntry2Object);
                    }
                    else
                    {
                        // .. if there is one already but with a different oid
                        if (lEntityListEntry2Object.Entry.Oid != pValueListEntryDC.ValueListEntryOid)
                        {
                            // ...replace the existing entry with that that was set by the client
                            lEntityListEntry2Object.Entry = DAOFactory.GenericDAO.LoadByID<ValueListEntry>(pValueListEntryDC.ValueListEntryOid.Value);
                        }
                    }

                    // now map
                    this.MergeWithEntity(pValueListEntryDC, lEntityListEntry2Object.Entry);
                }
            }
        }

        internal void MapValueEntryListBack2Entity(IList<ValueListEntryDC> pEntryDCs, IList<ValueListEntry2Object> pEntry2Objects, ValueListEntryType pType, TableID pTid, bool updateEntry)
        {
            IEnumerable<ValueListEntry> lExistingEntrys = pEntry2Objects.Where(e2o => e2o.Entry.Type == pType).Select(e2o => e2o.Entry);

            // remove deleted
			List<ValueListEntry> lToDelete = new List<ValueListEntry>();

	        foreach (var existingEntry in lExistingEntrys)
	        {
		        bool exists = false;
				foreach (var edc in pEntryDCs)
				{
					if (edc.ValueListEntryOid != null && existingEntry.Oid != null && edc.ValueListEntryOid == existingEntry.Oid)
						exists = true;
				}

				if (!exists)
					lToDelete.Add(existingEntry);
	        }
			
					//pEntryDCs.SingleOrDefault(
					//edc =>
					//    {
					//        if (edc.ValueListEntryOid != null && ent.Oid != null)
					//        {
					//            return edc.ValueListEntryOid == ent.Oid;
					//        }

					//        return edc.TypeDescription == ent.Value;
					//    }) == null);

            pEntry2Objects.RemoveRange(e2o => lToDelete.Contains(e2o.Entry));

            // add new
			List<ValueListEntryDC> lToAdd = new List<ValueListEntryDC>();

	        foreach (var edc in pEntryDCs)
	        {
		        bool exists = false;
				foreach (var existingEntry in lExistingEntrys)
				{
					if (edc.ValueListEntryOid != null && existingEntry.Oid != null)
					{
						bool equals = edc.ValueListEntryOid == existingEntry.Oid;
						if (equals)
							exists = true;
						if (updateEntry && equals)
							existingEntry.Value = edc.TypeDescription;// MapperFactory.ValueListEntryDC_ValueListEntry.MergeWithEntity(edc, ent);
					}
				}
				if (!exists)
					lToAdd.Add(edc);
	        }

			//IEnumerable<ValueListEntryDC> lToAdd = pEntryDCs.Where(
			//    edc => lExistingEntrys.SingleOrDefault(
			//        ent =>
			//            {
			//                if (edc.ValueListEntryOid != null && ent.Oid != null)
			//                {
			//                    bool equals = edc.ValueListEntryOid == ent.Oid;
			//                    if (updateEntry && equals)
			//                        ent.Value = edc.TypeDescription;// MapperFactory.ValueListEntryDC_ValueListEntry.MergeWithEntity(edc, ent);
			//                    return equals;
			//                }

			//                return ent.Value == edc.TypeDescription;
			//            }) == null);

            pEntry2Objects.AddRange(lToAdd.Select(edc =>
                {
                    var v2o = new ValueListEntry2Object
                        {
                            ObjectTid = pTid
                        };

                    if (edc.ValueListEntryOid.HasValue)
                        v2o.Entry = DAOFactory.GenericDAO.LoadByID<ValueListEntry>(edc.ValueListEntryOid.Value);
                    else
                    {
                        v2o.Entry = MapperFactory.ValueListEntryDC_ValueListEntry.MapToNewEntity(edc);
                    }
                    return v2o;
                }));

           
        }

        protected override bool AreDCAndEntityEqual(ValueListEntryDC pDC, ValueListEntry pEntity)
        {
            if (pDC.ValueListEntryOid == null)
            {
                return false;
            }

            return pDC.ValueListEntryOid == pEntity.Oid;
        }
    }
}