using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ease.Core.DataAccess;
using Ease.Core.Model;
using Ease.Core.Utility;
using HRM.BO;

namespace HRM.DA
{
    #region AttnWiseAllowance Service

    [Serializable]
    public class AttnWiseAllowanceService : ServiceTemplate
    {
        private void MapObject(AttnWiseAllowance oAttnWiseAllowance, DataReader oReader)
        {
            base.SetObjectID(oAttnWiseAllowance, (oReader.GetInt32("AttnWiseAllowanceID").Value));
            oAttnWiseAllowance.ShiftID = oReader.GetInt32("ShiftID").Value;
            oAttnWiseAllowance.ShiftName = oReader.GetString("ShiftName");
            oAttnWiseAllowance.ProvisionID = oReader.GetInt32("ProvisionID").Value;
            oAttnWiseAllowance.ProvisionName = oReader.GetString("ProvisionName");
            oAttnWiseAllowance.ProvisionType = (enumPayrollComponentType)oReader.GetInt32("ProvisionType").Value;
            oAttnWiseAllowance.ConsiderShiftHour = oReader.GetBoolean("HasHour").Value;
            oAttnWiseAllowance.HoursOverShift = oReader.GetBoolean("HasHourOverShift").Value;
            oAttnWiseAllowance.OnLeave = oReader.GetBoolean("IncludeLeave").Value;
            oAttnWiseAllowance.OnHoliday = oReader.GetBoolean("IncludeHoliday").Value; //Newly Added
            oAttnWiseAllowance.ConsiderPresentHour = oReader.GetBoolean("ConsiderPresentHour").Value; //Newly Added
            oAttnWiseAllowance.Multiple = oReader.GetDouble("Multiple").Value;
            oAttnWiseAllowance.FixedAmount = oReader.GetDouble("FixedAmount").Value;
            oAttnWiseAllowance.PercentOfBasic = oReader.GetDouble("PercentOfBasic").Value;
            oAttnWiseAllowance.CreatedBy = oReader.GetInt32("CreatedBy", 0);
            oAttnWiseAllowance.CreatedDate = oReader.GetDateTime("CreatedDate").Value;
            oAttnWiseAllowance.ModifiedBy = oReader.GetInt32("ModifiedBy", 0);
            oAttnWiseAllowance.ModifiedDate = oReader.GetDateTime("ModifiedDate");
            oAttnWiseAllowance.PayrollTypeID = oReader.GetInt32("PayrollTypeID", 0);
            oAttnWiseAllowance.TimeDependent = oReader.GetBoolean("TimeDependent", false);
            oAttnWiseAllowance.FromTime = oReader.GetDateTime("FromTime", DateTime.MinValue);
            oAttnWiseAllowance.ToTime = oReader.GetDateTime("ToTime", DateTime.MinValue);
            oAttnWiseAllowance.WorkTime = oReader.GetDouble("WorkTime", 0.0);
            oAttnWiseAllowance.GraceTime = oReader.GetDouble("GraceTime", 0.0);
            oAttnWiseAllowance.ConsiderOutTime = oReader.GetBoolean("ConsiderOutTime", false); //Newly Added
            this.SetObjectState(oAttnWiseAllowance, Ease.Core.ObjectState.Saved);
        }

        protected override T CreateObject<T>(DataReader oReader)
        {
            AttnWiseAllowance oAttnWiseAllowance = new AttnWiseAllowance();
            MapObject(oAttnWiseAllowance, oReader);
            return oAttnWiseAllowance as T;
        }

        #region Service implementation

        public AttnWiseAllowance Get(int id, int payrollTypeID)
        {
            AttnWiseAllowance oAttnWiseAllowance = new AttnWiseAllowance();
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                DataReader oreader = new DataReader(AttnWiseAllowanceDA.Get(tc, id, payrollTypeID));
                if (oreader.Read())
                {
                    oAttnWiseAllowance = this.CreateObject<AttnWiseAllowance>(oreader);
                }

                oreader.Close();
                tc.End();
            }
            catch (Exception e)
            {
                #region Handle Exception

                if (tc != null)
                    tc.HandleError();
                ExceptionLog.Write(e);
                throw new ServiceException(e.Message, e);

                #endregion
            }

            return oAttnWiseAllowance;
        }

        public List<AttnWiseAllowance> Get(int payrollTypeID)
        {
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                DataReader dr = new DataReader(AttnWiseAllowanceDA.Get(tc, payrollTypeID));
                var AttnWiseAllowances = this.CreateObjects<AttnWiseAllowance>(dr);
                dr.Close();
                tc.End();
                return AttnWiseAllowances;
            }
            catch (Exception e)
            {
                #region Handle Exception

                if (tc != null)
                    tc.HandleError();
                ExceptionLog.Write(e);
                throw new ServiceException(e.Message, e);

                #endregion
            }
        }

        public List<AttnWiseAllowance> Get(int shiftId, EnumAttendanceType attnType, bool value)
        {
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                DataReader dr = new DataReader(AttnWiseAllowanceDA.Get(tc, shiftId, attnType, value));
                //if (dr.Read())
                //{
                var AttnWiseAllowances = this.CreateObjects<AttnWiseAllowance>(dr);
                //}
                dr.Close();
                tc.End();
                return AttnWiseAllowances;
            }
            catch (Exception e)
            {
                #region Handle Exception

                if (tc != null)
                    tc.HandleError();
                ExceptionLog.Write(e);
                throw new ServiceException(e.Message, e);

                #endregion
            }
        }

        public int Save(AttnWiseAllowance oAttnWiseAllowance)
        {
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin(true);
                if (oAttnWiseAllowance.IsNew)
                {
                    //int id = tc.GenerateID("AttnWiseAllowance", "AttnWiseAllowanceID");
                    //base.SetObjectID(oAttnWiseAllowance, ID.FromInteger(id));
                    AttnWiseAllowanceDA.Insert(tc, oAttnWiseAllowance);
                }
                else
                {
                    AttnWiseAllowanceDA.Update(tc, oAttnWiseAllowance);
                }

                tc.End();
                return oAttnWiseAllowance.ID;
            }
            catch (Exception e)
            {
                #region Handle Exception

                if (tc != null)
                    tc.HandleError();
                ExceptionLog.Write(e);
                throw new ServiceException(e.Message, e);

                #endregion
            }
        }

        public void Delete(int id)
        {
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin(true);
                AttnWiseAllowanceDA.Delete(tc, id);
                tc.End();
            }
            catch (Exception e)
            {
                #region Handle Exception

                if (tc != null)
                    tc.HandleError();
                ExceptionLog.Write(e);
                throw new ServiceException(e.Message, e);

                #endregion
            }
        }
        public DateTime GetShiftOutTime(AttnWiseAllowance oAttnWiseAllowance, Shift oshift, DailyAttnProcess attn)
        {
            DateTime loutTime = DateTime.MinValue;
            if (oshift.IsOverlapingDay == true)
            {
                DateTime newDate = attn.AttnDate.AddDays(1);
                loutTime = new DateTime(newDate.Year, newDate.Month, newDate.Day, oshift.OutTime.Hour, oshift.OutTime.Minute, 0);
            }
            else
            {
                DateTime newDate = attn.AttnDate;
                loutTime = new DateTime(newDate.Year, newDate.Month, newDate.Day, oshift.OutTime.Hour, oshift.OutTime.Minute, 0);

            }

            DateTime dtOutTime = new DateTime(loutTime.Year, loutTime.Month, loutTime.Day, oAttnWiseAllowance.OutTime.Hour, oAttnWiseAllowance.OutTime.Minute, 0);

            return dtOutTime;
        }
        public List<AttnWiseAllowance> GetAllApplicableItem(List<AttnWiseAllowance> attnSetups, DailyAttnProcess atProcess)
        {

            List<AttnWiseAllowance> oattBens = new List<AttnWiseAllowance>();

            if (atProcess.InTime != DateTime.MinValue && atProcess.OutTime != DateTime.MinValue)
            {
                foreach (var attnSetup in attnSetups)
                {
                    if (attnSetup.FromTime != DateTime.MinValue)
                    {
                        attnSetup.FromTime = atProcess.AttnDate.Date.Add(attnSetup.FromTime.TimeOfDay);
                    }
                }

                List<AttnWiseAllowance> attnWiseAllowances = GetAttnWiseAllowances(attnSetups, atProcess, (int)atProcess.ShiftID);

                if (attnWiseAllowances.Count > 0)
                    oattBens.AddRange(attnWiseAllowances);
            }
            return oattBens;
        }

        public static List<AttnWiseAllowance> GetAllApplicableItem(List<AttnWiseAllowance> attnSetups,
            DailyAttnProcess atProcess, AttnNationalHoliday anHoliday, List<Leave> oLeaves, bool isWorkingDay)
        {
            List<AttnWiseAllowance> oattBens = new List<AttnWiseAllowance>();

            foreach (var attnSetup in attnSetups)
            {
                if (attnSetup.FromTime != DateTime.MinValue)
                {
                    attnSetup.FromTime = atProcess.AttnDate.Date.Add(attnSetup.FromTime.TimeOfDay);
                }
            }

            List<AttnWiseAllowance> attnWiseAllowances =
                GetAttnWiseAllowances(attnSetups, atProcess, (int) atProcess.ShiftID);

            //if (atProcess.HasDualShift && atProcess.SecondaryShift != null)
            //{
            //    attnWiseAllowances = GetAttnWiseAllowances(attnSetups, atProcess, atProcess.SecondaryShift.ID);
            //}


            if (atProcess.InTime != DateTime.MinValue && atProcess.OutTime != DateTime.MinValue)
            {
                oattBens.AddRange(attnWiseAllowances);
            }

            return oattBens;
        }

        private static List<AttnWiseAllowance> GetAttnWiseAllowances(List<AttnWiseAllowance> attnSetups,
            DailyAttnProcess atProcess, int shiftID)
        {
            DateTime InTime = (DateTime)atProcess.InTime;
            DateTime OutTime = atProcess.OutTime != DateTime.MinValue ? (DateTime)atProcess.OutTime : DateTime.MinValue;

            //List<AttnWiseAllowance> attnWiseAllowances = attnSetups.
            //                                                         Where(osetup => osetup.ShiftID == shiftID &&
            //                                                         (osetup.ProvisionType == enumPayrollComponentType.Allowance || osetup.ProvisionType == enumPayrollComponentType.Over_Time) &&
            //                                                         (osetup.TimeDependent ? (osetup.FromTime >= InTime && osetup.FromTime <= OutTime) : true)).
            //                                                         ToList();

            List<AttnWiseAllowance> attnWiseAllowances = attnSetups.Where(osetup => osetup.ShiftID == shiftID &&
                    (osetup.ProvisionType == enumPayrollComponentType.Allowance ||
                     osetup.ProvisionType == enumPayrollComponentType.Over_Time) &&
                    (osetup.TimeDependent ? (atProcess.OTHour + (osetup.GraceTime / 60.0) >= osetup.WorkTime) : true))
                .ToList();


            if (atProcess.WorkDayType == EnumWorkPlanDayType.WorkingDay)
            {
                // Take general allowances
                // Take holiday allowance if next day is holiday and out time is in next day
                //attnWiseAllowances = attnWiseAllowances.Where(x => !x.OnHoliday ||
                //                                                   ((atProcess.NextWorkDayType ==
                //                                                     EnumWorkPlanDayType.WeeklyHoliday ||
                //                                                     atProcess.NextWorkDayType ==
                //                                                     EnumWorkPlanDayType.NationalHoliday) &&
                //                                                    x.OnHoliday && x.ConsiderOutTime &&
                //                                                    OutTime.Date > atProcess.AttnDate)).ToList();
            }
            else if (atProcess.WorkDayType == EnumWorkPlanDayType.WeeklyHoliday ||
                     atProcess.WorkDayType == EnumWorkPlanDayType.NationalHoliday)
            {
                // Take general allowances
                // Tske holiday allowances which does not consider out time
                // Take holiday allowance if next day is holiday and out time is in next day
                //attnWiseAllowances = attnWiseAllowances.Where(x => !x.OnHoliday ||
                //                                                   (x.OnHoliday && !x.ConsiderOutTime) ||
                //                                                   ((atProcess.NextWorkDayType ==
                //                                                     EnumWorkPlanDayType.WeeklyHoliday ||
                //                                                     atProcess.NextWorkDayType ==
                //                                                     EnumWorkPlanDayType.NationalHoliday) &&
                //                                                    x.OnHoliday && x.ConsiderOutTime &&
                //                                                    OutTime.Date > atProcess.AttnDate)).ToList();
            }

            // If there is one or more time dependent allowance 
            if (attnWiseAllowances.Where(x => x.TimeDependent).Count() > 1)
            {
                //DateTime maxFromTime = attnWiseAllowances.Where(x => x.TimeDependent).Max(x => x.FromTime);
                double workTime = attnWiseAllowances.Where(x => x.TimeDependent).Max(x => x.WorkTime);

                // Take all not time dependent allowances
                // Take only the maximum time dependent allowance
                //attnWiseAllowances = attnWiseAllowances.Where(x => !x.TimeDependent ||
                //                                                  x.FromTime == maxFromTime)
                //                                       .ToList();
                attnWiseAllowances = attnWiseAllowances.Where(x => !x.TimeDependent ||
                                                                   x.WorkTime == workTime)
                    .ToList();
            }

            return attnWiseAllowances;
        }

        #endregion
    }

    #endregion
}