namespace App.Dal
{
    using Contracts;
    using Contracts.DataModels;
    using System;
    using System.Linq;
    using Contracts.Dals;
    using DataModels;
    using EntityDataModels;
    
    class LocationDal : IDal<ILocationDataModel>, ILocationDal
    {        
        /// <summary> 
        /// Create a new Location
        /// </summary>
        public void Create(ILocationDataModel item, IModelContext context)
        {            
            var ctx = new AppContext();
            var dataEntity = new LocationEntityDataModel(item);
            ctx.Location.Add(dataEntity);
            ctx.SaveChanges();
            item.Id = dataEntity.Id;    
        }
        
        /// <summary> 
        /// Update a Location
        /// </summary>
        public void Update(ILocationDataModel item, IModelContext context)
        {
            var ctx = new AppContext();
            var entity = ctx.Location.FirstOrDefault(x=> x.Id == item.Id);
            if (entity == null)
            {
                return;
            }
            
			ctx.Entry(entity).CurrentValues.SetValues(item);
            ctx.SaveChanges();
        }  

        /// <summary> 
        /// Delete an existing Location
        /// </summary>
        public void Delete(int id, IModelContext context)
        {
            var ctx = new AppContext();
            var itemToRemove = ctx.Location.SingleOrDefault(x => x.Id == id); 

            if (itemToRemove != null)
            {
                ctx.Location.Remove(itemToRemove);
				ctx.EventLocation.RemoveRange(ctx.EventLocation.Where(x => x.LocationId == id)); // Remove any EventLocation relationships 

				ctx.Region.Where(x=>x.RegionLocationId == id).ToList().ForEach(x=>x.RegionLocationId = -1) ;// unset any RegionLocation relationships 

				ctx.SaveChanges();
            }   
        }
        
        /// <summary> 
        /// Find a single Location
        /// </summary>
        public ILocationDataModel Get(Func<ILocationDataModel, bool> filter, IModelContext context)
        {
             var ctx = new AppContext();
             var rtn = ctx.Location.FirstOrDefault(filter);
             return rtn;
        }
        
        /// <summary> 
        /// Find a single Location
        /// </summary>
        public ILocationDataModel Get(int id, IModelContext context)
        {
             var ctx = new AppContext();
             var rtn = ctx.Location.FirstOrDefault(x=>x.Id == id);
             return rtn;
        }
        
        /// <summary> 
        /// Find zero or more Location
        /// </summary>
        public IQueryable<ILocationDataModel> GetAll(Func<ILocationDataModel, bool> filter, IModelContext context)
        {
            var ctx = new AppContext();
            var rtn = ctx.Location.Where(filter).AsQueryable();
            return rtn;
        }

		
		#region 'RegionLocation'        
		/// <summary>
        /// Gets the single Location by Region id for RegionLocation relationship.
        /// </summary>
        public ILocationDataModel GetSingleLocationByRegionForRegionLocation(int regionId, IModelContext context)
		{
			var ctx = new AppContext();
            var item = ctx.Region.Find(regionId);
			if(item == null) return null;
			var rtn = ctx.Location.Find(item.RegionLocationId);
			return rtn;
		} 

		/// <summary>
        /// Connects a Location to a Region for RegionLocation relationship.
        /// </summary>
        public void AddLocationToRegionForRegionLocation(int locationId, int regionId, IModelContext context)
		{
			var ctx = new AppContext();
            var item = ctx.Region.Find(regionId);
            if (item == null) return;
            item.RegionLocationId = locationId;
            ctx.SaveChanges();
		}   

		/// <summary>
        /// Unconnect a Location to a Region for RegionLocation relationship.
        /// </summary>
		public void RemoveLocationFromRegionForRegionLocation(int regionId, IModelContext context)
		{
			var ctx = new AppContext();
            var item = ctx.Region.Find(regionId);
            if (item == null) return;
            item.RegionLocationId = -1;
            ctx.SaveChanges();
		}  

		#endregion 
		
		
		#region 'EventLocation'	
		/// <summary>
        /// Adds the location to event for 'EventLocation' relationship.
        /// </summary>
		public void AddEventToLocationForEventLocation(int locationId, int eventId, IModelContext context)
		{
			var ctx = new AppContext();
            var existing = ctx.EventLocation.Any(x=> x.LocationId == locationId && x.EventId == eventId);
            if (existing) return;
            ctx.EventLocation.Add(new EventLocationRelationshipModel{LocationId = locationId, EventId = eventId});
            ctx.SaveChanges();
		}

		/// <summary>
        /// Removes the location from event for 'EventLocation' relationship.
        /// </summary>
		public void RemoveEventFromLocationForEventLocation(int locationId, int eventId, IModelContext context)
		{
			var ctx = new AppContext();
            var existing = ctx.EventLocation.FirstOrDefault(x=> x.LocationId == locationId && x.EventId == eventId);
            if (existing == null) return;
            ctx.EventLocation.Remove(existing);
            ctx.SaveChanges();
		}

		/// <summary>
        /// Get all Location for 'EventLocation' relationship.
        /// </summary>
		public IQueryable<ILocationDataModel> GetAllForEventLocation(int eventId, IModelContext context)
		{
			var ctx = new AppContext();
			var result = (from main in ctx.Location
						join link in ctx.EventLocation on main.Id equals link.LocationId
						where (link.EventId == eventId)
						select main);
			return result;
		}
		#endregion 		
		    }
}