using Ease.Core.Model;
using Ease.Core.DataAccess;
using HRM.BO;
using Ease.Core.Utility;
using System.Collections.Generic;
using System.Data;
using Ease.Core;
using Payroll.Service;
using System;


namespace HRM.DA
{
    public class TaxParameterService : ServiceTemplate, ITaxParameterService
    {
        public TaxParameterService()
        {
        }

        private void MapObject(TaxParameter oTaxParameter, DataReader oReader)
        {
            base.SetObjectID(oTaxParameter, oReader.GetInt32("TaxParamID").Value);
            oTaxParameter.FiscalYear = oReader.GetString("fiscalYear");
            oTaxParameter.AssessmentYear = oReader.GetString("assessmentYear");
            oTaxParameter.MaxInvestPercent = oReader.GetDouble("maxInvestPercent").Value;
            oTaxParameter.MaxHRPercent = oReader.GetDouble("maxHRPercent").Value;
            oTaxParameter.MaxHRAmount = oReader.GetDouble("maxHRAmount").Value;
            oTaxParameter.MaxMedicalPercent = oReader.GetDouble("MaxMedicalPercent").Value;
            oTaxParameter.MaxMedicalAmount = oReader.GetDouble("MaxMedicalAmount").Value;
            oTaxParameter.MaxConvAmount = oReader.GetDouble("maxConvAmount").Value;
            oTaxParameter.MaxCPFPercent = oReader.GetDouble("maxCPFPercent").Value;
            oTaxParameter.MaxInvExempPercent = oReader.GetDouble("maxInvExempPercent").Value;
            oTaxParameter.MaxInvAmount = oReader.GetDouble("maxInvAmount").Value;
            oTaxParameter.MinTaxAmount = oReader.GetDouble("minTaxAmount").Value;
            oTaxParameter.PfIntProjection = oReader.GetDouble("pfIntProjection").Value;
            oTaxParameter.MaxAge = oReader.GetDouble("maxAge").Value;
            oTaxParameter.InvestmentActiveMonth = oReader.GetDateTime("InvestmentActiveMonth");
            oTaxParameter.CreatedBy = oReader.GetInt32("CreatedBy", 0);
            oTaxParameter.CreatedDate = oReader.GetDateTime("CreationDate").Value;
            oTaxParameter.ModifiedBy = oReader.GetInt32("ModifiedBy", 0);
            oTaxParameter.ModifiedDate = oReader.GetDateTime("ModifiedDate");
            oTaxParameter.PayrollTypeID = oReader.GetInt32("PayrollTypeID").Value;
            this.SetObjectState(oTaxParameter, Ease.Core.ObjectState.Saved);
        }

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

        private void MapTaxSlabObject(TaxParameterSlab oTaxParamSlab, DataReader oReader)
        {
            base.SetObjectID(oTaxParamSlab, oReader.GetInt32("TAXPARAMID").Value);
            oTaxParamSlab.TaxparamID = oReader.GetInt32("TAXPARAMID").Value;
            oTaxParamSlab.SequenceNo = oReader.GetInt32("SEQUENCENO").Value;
            oTaxParamSlab.IncomeAmount = oReader.GetDouble("INCOMEAMOUNT").Value;
            oTaxParamSlab.TaxPercent = oReader.GetDouble("TAXPERCENT").Value;
            oTaxParamSlab.ParamType = (EnumTaxSlabType)oReader.GetInt32("TYPE").Value;
            this.SetObjectState(oTaxParamSlab, Ease.Core.ObjectState.Saved);
        }

        protected List<TaxParameterSlab> CreateTaxSlabObject(DataReader oReader)
        {
            List<TaxParameterSlab> oTaxParamSlabs = new List<TaxParameterSlab>();
            while (oReader.Read())
            {
                TaxParameterSlab oTaxParamSlab = new TaxParameterSlab();
                MapTaxSlabObject(oTaxParamSlab, oReader);
                oTaxParamSlabs.Add(oTaxParamSlab);
            }

            return oTaxParamSlabs;
        }

        #region Service implementation

        public TaxParameter Get(int id)
        {
            TaxParameter oTaxParameter = null;

            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                DataReader oreader = new DataReader(TaxParameterDA.Get(tc, id));
                if (oreader.Read())
                {
                    oTaxParameter = this.CreateObject<TaxParameter>(oreader);
                    oreader.Close();
                    if (oTaxParameter != null)
                    {
                        DataReader dr = new DataReader(TaxParameterDA.GetSlabsByParamID(tc, oTaxParameter.ID));
                        //dr.Close();
                        oTaxParameter.TaxParameterSlabs = this.CreateTaxSlabObject(dr);
                        dr.Close();
                    }
                }

                //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 oTaxParameter;
        }


        public TaxParameter Get(string assessmentYear)
        {
            TaxParameter oTaxParameter = null;
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                DataReader oreader = new DataReader(TaxParameterDA.Get(tc, assessmentYear));
                if (oreader.Read())
                {
                    oTaxParameter = this.CreateObject<TaxParameter>(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 oTaxParameter;
        }

        public TaxParameter GetByFiscalYear(string fiscalYear)
        {
            TaxParameter oTaxParameter = null;
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                DataReader oreader = new DataReader(TaxParameterDA.GetByFiscalYear(tc, fiscalYear));
                if (oreader.Read())
                {
                    oTaxParameter = this.CreateObject<TaxParameter>(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 oTaxParameter;
        }
        //public static List<TaxParameter> Get(bool IsCurrentFY)
        //{
        //    #region Cache Header

        //    List<TaxParameter> taxParameters = new List<TaxParameter>();

        //    #endregion

        //    try
        //    {
        //        taxParameters = TaxParameterDA.Get(IsCurrentFY);
        //    }
        //    catch (ServiceException e)
        //    {
        //        throw new Exception(e.Message, e);
        //    }
        //    return taxParameters;
        //}
        public List<TaxParameter> Get(bool IsCurrentFY, int payrollTypeID)
        {
            List<TaxParameter> taxParameters = new List<TaxParameter>();

            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();

                DataReader dr = new DataReader(TaxParameterDA.Get(tc, IsCurrentFY, payrollTypeID));
                taxParameters = this.CreateObjects<TaxParameter>(dr);
                dr.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 taxParameters;
        }

        public List<TaxParameter> GetbyPayrolltype(int payrolltypeid)
        {
            List<TaxParameter> taxParameters = new List<TaxParameter>();

            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();

                DataReader dr = new DataReader(TaxParameterDA.GetbyPayrolltype(tc, payrolltypeid));
                taxParameters = this.CreateObjects<TaxParameter>(dr);
                dr.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 taxParameters;
        }

        public List<TaxParameterSlab> GetTaxSlabs(int nID, EnumTaxSlabType TaxType)
        {
            List<TaxParameterSlab> taxParameterSlabs = new List<TaxParameterSlab>();

            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();

                DataReader dr = new DataReader(TaxParameterDA.GetTaxSlabs(tc, nID, TaxType));
                dr.Close();
                taxParameterSlabs = this.CreateTaxSlabObject(dr);
                tc.End();
            }
            catch (Exception e)
            {
                #region Handle Exception

                if (tc != null)
                    tc.HandleError();
                ExceptionLog.Write(e);

                throw new ServiceException(e.Message, e);

                #endregion
            }


            return taxParameterSlabs;
        }

        public DataSet GetTSByParamAndType(int nID, EnumTaxSlabType TaxType)
        {
            DataSet taxParameterSlabs = null;
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                taxParameterSlabs = TaxParameterDA.GetTSByParamAndType(tc, nID, TaxType);
                tc.End();
            }
            catch (Exception e)
            {
                #region Handle Exception

                if (tc != null)
                    tc.HandleError();
                ExceptionLog.Write(e);

                throw new ServiceException(e.Message, e);

                #endregion
            }

            return taxParameterSlabs;
        }
        public TaxParameter GetByDate(DateTime salaryMonth)
        {
            TaxParameter oTaxParameter = null;
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();
                DataReader oreader = new DataReader(TaxParameterDA.GetByDate(tc, salaryMonth));
                if (oreader.Read())
                {
                    oTaxParameter = this.CreateObject<TaxParameter>(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 oTaxParameter;
        }
        public List<TaxParameterSlab> GetSlabsByParamID(int nID)
        {
            List<TaxParameterSlab> taxParameterSlabs = new List<TaxParameterSlab>();

            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin();

                DataReader dr = new DataReader(TaxParameterDA.GetSlabsByParamID(tc, nID));
                taxParameterSlabs = this.CreateTaxSlabObject(dr);
                dr.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 taxParameterSlabs;
        }

        public int Save(TaxParameter oTaxParameter, int payrollTypeID)
        {
            PayrollType ptype = new PayrollTypeService().Get(payrollTypeID);
            TransactionContext tc = null;

            try
            {
                tc = TransactionContext.Begin(true);
                if (oTaxParameter.IsNew)
                {
                    if (ptype.TaxParamID != null) throw new Exception("Not allowed to create new tax-year until current year-end.");

                    int MaxID = TaxParameterDA.GetMaxID(tc, payrollTypeID);

                    int id = tc.GenerateID("TaxParameter", "TaxParamID");
                    base.SetObjectID(oTaxParameter, (id));
                    TaxParameterDA.Insert(tc, oTaxParameter);

                    if (MaxID != 0)
                    {
                        List<TaxMergeMaster> TaxMergeMasters =
                            new TaxMergeMasterService().GetByTaxParamID(tc, MaxID, payrollTypeID);

                        if (TaxMergeMasters != null)
                        {
                            foreach (TaxMergeMaster oTaxMergeMaster in TaxMergeMasters)
                            {
                                int newId = tc.GenerateID("TaxMergeMaster", "TaxMergeID");
                                int position = tc.GenerateID("TaxMergeMaster", "Position");
                                oTaxMergeMaster.Position = position;
                                oTaxMergeMaster.TaxParameterID = (id);
                                base.SetObjectID(oTaxMergeMaster, (newId));
                                TaxMergeMasterDA.Insert(tc, oTaxMergeMaster);

                                foreach (TaxMergeMaster.TaxMergeDetail oTaxMergeDetail in oTaxMergeMaster
                                    .TaxMergeDetails)
                                {
                                    int detailid = tc.GenerateID("TaxMergeDetail", "DetailId");
                                    base.SetObjectID(oTaxMergeDetail, (detailid));
                                    oTaxMergeDetail.TaxMergeID = (newId);
                                    oTaxMergeDetail.TaxParameterID = oTaxMergeMaster.TaxParameterID;
                                    TaxMergeMasterDA.Insert(tc, oTaxMergeDetail);
                                }
                            }
                        }

                        //
                        List<ITEmpHead> itHeads = new ITEmpHeadService().GetWithTaxParam(tc, MaxID);
                        int carid = tc.GenerateID("ITEmpHead", "ITEMPHEADID");
                        foreach (ITEmpHead item in itHeads)
                        {
                            if (oTaxParameter.FiscalyearDatefrom == item.EndDate.AddDays(1))
                            {
                                carid = carid + 1;
                                base.SetObjectID(item, (carid));
                                ITEmpHeadDA.Insert(tc, item);
                            }
                        }
                    }
                    PayrollTypeDA.UpdateTaxParam(tc, oTaxParameter.ID, payrollTypeID);
                }
                else
                {
                    TaxParameterDA.Update(tc, oTaxParameter);
                    TaxParameterDA.DeleteByParamID(tc, oTaxParameter.ID);
                }

                int seqNo = 1;
                foreach (TaxParameterSlab taxParamSlab in oTaxParameter.TaxParameterSlabs)
                {
                    if (taxParamSlab.ParamType == EnumTaxSlabType.Male)
                    {
                        taxParamSlab.TaxparamID = oTaxParameter.ID;
                        taxParamSlab.SequenceNo = seqNo++;
                        TaxParameterDA.Insert(tc, taxParamSlab);
                    }
                }

                seqNo = 1;
                foreach (TaxParameterSlab taxParamSlab in oTaxParameter.TaxParameterSlabs)
                {
                    if (taxParamSlab.ParamType == EnumTaxSlabType.Female)
                    {
                        taxParamSlab.TaxparamID = oTaxParameter.ID;
                        taxParamSlab.SequenceNo = seqNo++;
                        TaxParameterDA.Insert(tc, taxParamSlab);
                    }
                }

                seqNo = 1;
                foreach (TaxParameterSlab taxParamSlab in oTaxParameter.TaxParameterSlabs)
                {
                    if (taxParamSlab.ParamType == EnumTaxSlabType.Age)
                    {
                        taxParamSlab.TaxparamID = oTaxParameter.ID;
                        taxParamSlab.SequenceNo = seqNo++;
                        TaxParameterDA.Insert(tc, taxParamSlab);
                    }
                }

                seqNo = 1;
                foreach (TaxParameterSlab taxParamSlab in oTaxParameter.TaxParameterSlabs)
                {
                    if (taxParamSlab.ParamType == EnumTaxSlabType.Disable)
                    {
                        taxParamSlab.TaxparamID = oTaxParameter.ID;
                        taxParamSlab.SequenceNo = seqNo++;
                        TaxParameterDA.Insert(tc, taxParamSlab);
                    }
                }

                seqNo = 1;
                foreach (TaxParameterSlab taxParamSlab in oTaxParameter.TaxParameterSlabs)
                {
                    if (taxParamSlab.ParamType == EnumTaxSlabType.Freedom_Fighter)
                    {
                        taxParamSlab.TaxparamID = oTaxParameter.ID;
                        taxParamSlab.SequenceNo = seqNo++;
                        TaxParameterDA.Insert(tc, taxParamSlab);
                    }
                }

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

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

                #endregion
            }
        }
        public void SetCurrentYearTax(int taxParamid, int payrollTypeID)
        {
            TransactionContext tc = null;
            bool isExist = false;
            try
            {
                tc = TransactionContext.Begin(true);
                isExist =TaxParameterDA.IsExistInPreviousYear(tc, taxParamid);
                tc.End();
                if(isExist == true)
                {
                    throw new Exception("Tax Parameter is previously used");
                }
                new PayrollTypeService().UpdateTaxParam (taxParamid, payrollTypeID);
            }
            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, int payrollTypeID)
        {
            TransactionContext tc = null;
            try
            {
                tc = TransactionContext.Begin(true);
                TaxParameterDA.Delete(tc, id, payrollTypeID);
                tc.End();
            }
            catch (Exception e)
            {
                #region Handle Exception

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

                #endregion
            }
        }

        public  List<TaxParameterSlab> GetEmployeeSlab(PayrollType ptype, TaxParameter parameter, Employee employee)
        {

            foreach (TaxParameterSlab item in parameter.TaxParameterSlabs)
            {
                item.SlabTaxAmount = 0;
                item.SlabTaxableAmount = 0;
            }

            List<TaxParameterSlab> employeeSlab = null;
            EnumTaxSlabType SlabType = EnumTaxSlabType.Male;
            if (employee.PersonType == EnumPersonType.Disable)
                SlabType = EnumTaxSlabType.Disable;
            else if (employee.PersonType == EnumPersonType.Freedom_Fighter)
                SlabType = EnumTaxSlabType.Freedom_Fighter;
            else
            {
                if (employee.Gender == EnumGender.Female)
                    SlabType = EnumTaxSlabType.Female;
                else
                {

                    int NoOfMonth = Global.DateFunctions.DateDiff("m",
                        employee.BirthDate, ptype.TaxYearEndDate);
                    int NoOfYear = NoOfMonth / 12;
                    if (NoOfYear >= parameter.MaxAge) SlabType = EnumTaxSlabType.Age;
                }
            }
            employeeSlab = new List<TaxParameterSlab>();
            foreach (TaxParameterSlab item in parameter.TaxParameterSlabs)
            {
                if (item.ParamType == SlabType)
                    employeeSlab.Add(item);
            }

            return employeeSlab;
        }
        public List<TaxParameterSlab> CalculateTaxOnSlab(PayrollType ptype, TaxParameter parameter, Employee emp, double taxableIncome)
        {
            List<TaxParameterSlab> empTaxSlabs = this.GetEmployeeSlab(ptype, parameter, emp);
            if (empTaxSlabs == null || empTaxSlabs.Count == 0) throw new ServiceException("Employee Tax Slabs not found; Employee No:" + emp.EmployeeNo);
            int index = 0;


            //if (emp.ForeignExPat &&
            //        Ease.CoreV35.Utility.Global.DateFunctions.DateDiff("m", emp.JoiningDate, SystemInformation.CurrentSysInfo.NextPayProcessDate) > 6)
            //{
            //    empTaxSlabs[empTaxSlabs.Count - 1].SlabTaxAmount = empTaxSlabs[empTaxSlabs.Count].TaxPercent * (taxableIncome / 100);
            //    return empTaxSlabs;
            //}

            while (taxableIncome != 0)
            {
                TaxParameterSlab slab = empTaxSlabs[index];
                if (taxableIncome > slab.IncomeAmount && index != empTaxSlabs.Count - 1)
                {
                    slab.SlabTaxAmount = GlobalFunctions.Round((slab.IncomeAmount * slab.TaxPercent) / 100);
                    slab.SlabTaxableAmount = slab.IncomeAmount;
                    taxableIncome = taxableIncome - slab.IncomeAmount;
                }
                else
                {
                    slab.SlabTaxableAmount = taxableIncome;
                    slab.SlabTaxAmount = GlobalFunctions.Round(((taxableIncome * slab.TaxPercent) / 100));
                    taxableIncome = 0;
                }
                index = index + 1;
            }
            return empTaxSlabs;

        }


        #endregion
    }
}