using LHDN.CRM.BC.Common;
using LHDN.CRM.Models.Models;
using LHDN.CRM.Models.ViewModels;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Transactions;

namespace LHDN.CRM.BC.Services
{
    public class CaseService : ServiceBase<Models.ViewModels.CaseViewModel>
    {
        private Repositories.CaseRepository repo = new Repositories.CaseRepository();
        private Repositories.ActivityRepository repoAct = new Repositories.ActivityRepository();
        private Repositories.UserRepository user = new Repositories.UserRepository();
        private Repositories.WorkflowRepository repoWorkflow = new Repositories.WorkflowRepository();

        public CaseViewModel GetById(long CaseID, UserInfoViewModel user)
        {
            CaseViewModel data = null;
            data = repo.GetCase(CaseID, user);
            
            if (data == null)
                throw new NotFoundException("Case is deleted or not found!");
            else
            {
                data.NotaTemuduga = data.NotaTemuduga == null ? new NotaTemudugaViewModel() : data.NotaTemuduga;
                data.EnableDMSIntegration = Convert.ToBoolean(AdminService.ParameterSettings.Where(x => x.ParameterID == 11).FirstOrDefault().ParameterValue);
            } 

            return data;
        }

        public CaseViewModel GetCaseSummary(long id)
        {
            return repo.GetCaseSummary(id);
        }

        public byte[] GetChangeStampbyID(int intTableType, long ID)
        {
            return repo.GetChangeStampbyID(intTableType, ID);
        }

        public List<CaseViewModel> GetOpenCase(CasePagedListViewModel paging, out int intCount)
        {
            intCount = 0;

            DataSet ds = repo.GetOpenCase(paging.SortExpression, paging.PageIndex, paging.Length,
                                            paging.TPID);

            List<CaseViewModel> lstCaseVM = new List<CaseViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstCaseVM = repo.DataTableToList<CaseViewModel>(ds.Tables[0]).ToList(); //Repositories.DataTableExtensions.ToList<CaseViewModel>(ds.Tables[0]).ToList();

                if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
                    intCount = Convert.ToInt32(ds.Tables[1].Rows[0][0].ToString());
            }

            return lstCaseVM;
        }

        public CaseCatatanViewModel GetCaseCatatanByID(long lngCaseCatatanID)
        {
            return repo.GetActCatatanByID(lngCaseCatatanID);
        }

        public long InsertCaseCatatan(CaseCatatanViewModel model, string strUserName, string strUserID, DateTime dtUpdated)
        {
            long lngCaseCatatanID = repo.InsertCaseCatatan(model, strUserName, strUserID, dtUpdated);

            return lngCaseCatatanID;
        }

        public List<ChangeHistoryUpdateViewModel> UpdateCaseCatatan(CaseCatatanViewModel model, string strUserName, string strUserID, DateTime dtUpdated)
        {
            List<ChangeHistoryUpdateViewModel> lstChangeHist = new List<ChangeHistoryUpdateViewModel>();

            // Retrieve orginal records for audit and change history 
            CaseCatatanViewModel clsOriCatatan = GetCaseCatatanByID(model.CatatanID);

            // Check for update conflict
            if (clsOriCatatan == null || !Utilities.CompareByteArray(model.ChangeStamp, clsOriCatatan.ChangeStamp))
            {
                throw new UpdateConflictException();
            }

            //Get ChangeHistoryUpdateViewModel
            ChangeHistoryUpdateViewModel changeHistoryItem = new ChangeHistoryUpdateViewModel();
            changeHistoryItem.ID = model.CaseID; //store CaseID instead of CatatanID
            changeHistoryItem.FieldName = "Case_Catatan";
            changeHistoryItem.DisplayName = "Kes (Catatan)";
            changeHistoryItem.OldValue = clsOriCatatan.Catatan;
            changeHistoryItem.NewValue = model.Catatan;
            changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue); //TODO If user only update attachments
            lstChangeHist.Add(changeHistoryItem);

            repo.UpdateCaseCatatan(model, strUserName, strUserID, dtUpdated);

            lstChangeHist = InsertChangeHistory(lstChangeHist, strUserName, strUserID, dtUpdated);

            return lstChangeHist;
        }

        public List<ChangeHistoryUpdateViewModel> DeleteCaseCatatan(CaseCatatanViewModel model, string strUserName, string strUserID, DateTime dtUpdated)
        {
            List<ChangeHistoryUpdateViewModel> lstChangeHist = new List<ChangeHistoryUpdateViewModel>();
            CaseCatatanViewModel clsOriCatatan = GetCaseCatatanByID(model.CatatanID);
            if (clsOriCatatan == null || !Utilities.CompareByteArray(model.ChangeStamp, clsOriCatatan.ChangeStamp))
            {
                throw new UpdateConflictException();
            }

            //Get ChangeHistoryUpdateViewModel
            ChangeHistoryUpdateViewModel changeHistoryItem = new ChangeHistoryUpdateViewModel();
            changeHistoryItem.ID = model.CaseID; //store CaseID instead of CatatanID
            changeHistoryItem.FieldName = "Case_Catatan";
            changeHistoryItem.DisplayName = "Kes (Catatan) - Hapus";
            changeHistoryItem.OldValue = clsOriCatatan.Catatan;
            changeHistoryItem.NewValue = string.Empty;
            changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue); //TODO If user only update attachments
            lstChangeHist.Add(changeHistoryItem);

            repo.DeleteCaseCatatan(model.CatatanID);

            lstChangeHist = InsertChangeHistory(lstChangeHist, strUserName, strUserID, dtUpdated);

            return lstChangeHist;
        }

        //public long UpdateCaseCatatan2(CaseCatatanViewModel catatanVM, out List<ChangeHistoryUpdateViewModel> lstChangeHist)
        //{
        //    lstChangeHist = new List<ChangeHistoryUpdateViewModel>();
        //    string oriCatatan = "";
        //    byte[] oriChangeStamp;

        //    if (catatanVM.Indicator == 2 || catatanVM.Indicator == 3) //if UPDATE/DELETE, check update conflict and get change history
        //    {
        //        // Retrieve orginal records for audit and change history 
        //        List<CaseCatatanViewModel> oriLst = GetAllCaseCatatan(catatanVM.CaseID, 0);
        //        if (oriLst.Count > 0)
        //        {
        //            CaseCatatanViewModel c = oriLst.Where(o => o.CatatanID == catatanVM.CatatanID).FirstOrDefault();
        //            oriChangeStamp = c.ChangeStamp;
        //            oriCatatan = c.Catatan;

        //            // Check for update conflict
        //            if (!Utilities.CompareByteArray(catatanVM.ChangeStamp, oriChangeStamp))
        //            {
        //                //TODO Update conflict
        //                //throw new Exception("Update Conflict!");
        //                throw new UpdateConflictException();
        //            }
        //            //Get ChangeHistoryUpdateViewModel
        //            ChangeHistoryUpdateViewModel changeHistoryItem = new ChangeHistoryUpdateViewModel();
        //            changeHistoryItem.ID = catatanVM.CaseID; //store CaseID instead of CatatanID
        //            changeHistoryItem.FieldName = "Case_Catatan";
        //            changeHistoryItem.DisplayName = catatanVM.Indicator == 3 ? "Removed Case (Catatan)" : "Case (Catatan)";
        //            changeHistoryItem.OldValue = oriCatatan;
        //            changeHistoryItem.NewValue = catatanVM.Catatan;
        //            changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue);
        //            lstChangeHist.Add(changeHistoryItem);
        //        }
        //        lstChangeHist = InsertChangeHistory(lstChangeHist, catatanVM.CreatedByName, catatanVM.CreatedBy, catatanVM.LastUpdatedDateTime); //if update, InsertChangeHistory
        //    }

        //    // TODO : Transaction Scope
        //    long lngCatatanID = repo.UpdateCaseCatatan(catatanVM);

        //    return lngCatatanID;
        //}

        public DataTable GetAttachment(string type, long AttachmentID)
        {
            return repo.GetAttachment(type, AttachmentID);
        }

        public TempAttachmentViewModel InsertTempAttachment(TempAttachmentViewModel model)
        {
            return repo.InsertTempAttachment(model);
        }

        public void DeleteTempAttachment(long TempAttachmentID)
        {
            repo.DeleteTempAttachment(TempAttachmentID);
        }

        public List<CaseCatatanViewModel> GetAllCaseCatatan(long CaseID, long ActID)
        {
            return repo.GetAllCaseCatatan(CaseID, ActID);
        }

        public string GetAllCatatanInString(long CaseID, long ActID)
        {
            return repo.GetAllCatatanInString(CaseID, ActID);
        }

        public DropdownViewModel GetCaseDropdown(List<TindakanSusulanViewModel> lstRoleTindakanSusulan)
        {
            DropdownViewModel ddlVM = new DropdownViewModel();
            ddlVM.MainKategoriOptions = AdminService.Kategoris.Where(x => x.IsActive == true).OrderBy(x => x.Kategori1Name).ToList<MainKategori>();
            ddlVM.Status1Options = AdminService.StatusLevels.Where(x => x.IsActive == true).ToList<StatusLevel1>();
            ddlVM.KodSelesaiOptions = AdminService.KodSelesaiCCResult.Where(x => x.IsActive == true && x.IsAgentOption == true).OrderBy(x => x.KodSelesaiDesc).ToList();

            // ddlVM.KodSelesaiOptions = AdminService.KodSelesai.Where(x => x.IsActive == true && x.IsAgentOption == true).ToList<KodSelesai>();
            //ddlVM.TindakanSusulanOptions = AdminService.TindakanSusulan.ToList<TindakanSusulanViewModel>();
            ddlVM.TindakanSusulanOptions = lstRoleTindakanSusulan;
            ddlVM.JenisKempenOptions = Utilities.SortDDL(AdminService.JenisKempens.Where(x => x.JenisKempenKategoriSysID != 26 && x.IsActive == true) //exclude KempenHCL
                                                                .Select(x => new DropdownDetailViewModel
                                                                {
                                                                    Value = x.JenisKempenID,
                                                                    Text = x.JenisKempenName
                                                                }).ToList());
            ddlVM.ActChannelOptions = AdminService.ActivityChannels.OrderBy(x => x.ActChannelName).ToList<ActivityChannel>();

            ddlVM.StatusBayaranOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "StatusBayaranS104S22" && x.IsActive == true)
                                            .Select(x => new DropdownDetailViewModel
                                            {
                                                Value = x.LookupParamID,
                                                Text = x.ParamDesc,
                                                IsDefault = x.IsDefault,
                                                SeqNo = x.SeqNo
                                            }).ToList());

            ddlVM.TahapOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "Tahap" && x.IsActive == true)
                                    .Select(x => new DropdownDetailViewModel
                                    {
                                        Value = x.LookupParamID,
                                        Text = x.ParamDesc,
                                        IsDefault = x.IsDefault,
                                        SeqNo = x.SeqNo
                                    }).ToList());

            ddlVM.DocCawanganTindakanOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "DocCawanganTindakan" && x.IsActive == true)
                                                               .Select(x => new DropdownDetailViewModel
                                                               {
                                                                   Value = x.LookupParamID,
                                                                   Text = x.ParamDesc,
                                                                   IsDefault = x.IsDefault,
                                                                   SeqNo = x.SeqNo
                                                               }).ToList());

            ddlVM.JenisPengenalanOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "JenisPengenalan" && x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.LookupParamID, Text = x.ParamDesc, IsDefault = x.IsDefault }).ToList());


            ddlVM.ActStatusOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "ActivityStatus" && x.IsActive == true)
                                    .Select(x => new DropdownDetailViewModel
                                    {
                                        Value = x.LookupParamID,
                                        Text = x.ParamDesc,
                                        IsDefault = x.IsDefault,
                                        Code = x.LookupValue,
                                        SeqNo = x.SeqNo
                                    }).ToList());

            ddlVM.AliranOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "Aliran" && x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.LookupParamID, Text = x.ParamDesc, IsDefault = x.IsDefault, Code = x.LookupValue, SeqNo = x.SeqNo }).ToList());
            //ddlVM.UnitPenerimaanDocOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeUnit && x.IsActive == true)
            //                               .Select(x => new WorkflowUserViewModel
            //                               {
            //                                   ID = x.UnitID.ToString(),
            //                                   DisplayName = x.UnitName,
            //                                   AdditionalInfo = x.AdditionalInfo,
            //                               }).OrderBy(x => x.DisplayName).ToList();


            ddlVM.WorkflowAssignToTypeOption = AdminService.LookupParamSys.Where(x => x.LookupCode == "AssignToType" && (x.LookupParamSysID == (int)Constant.LookupParamSys.AssignToTypeUser || x.LookupParamSysID == (int)Constant.LookupParamSys.AssignToTypeUnit))
                        .Select(x => new DropdownDetailViewModel
                        {
                            Value = x.LookupParamSysID,
                            Text = x.ParamDesc,
                            IsDefault = x.LookupParamSysID == (int)Constant.LookupParamSys.AssignToTypeUser
                        }).ToList();

            ddlVM.JenisPelangganOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "JenisPelanggan" && x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.LookupParamID, Code = x.LookupValue, Text = x.ParamDesc, IsDefault = x.IsDefault, SeqNo = x.SeqNo }).ToList());



            ddlVM.WorkflowAssignToSeksyenOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeSeksyen && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            ddlVM.WorkflowAssignToJabatanOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeJabatan && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            ddlVM.WorkflowAssignToCawanganOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeCawangan && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            ddlVM.WorkflowAssignToUnitOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeUnit && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            ddlVM.ParameterSettings = AdminService.ParameterSettings.Where(x => (x.ParameterID == 14 || x.ParameterID == 15)).ToList<ParameterSettings>();
            ddlVM.FunctionRoleMemberOption = AdminService.FunctionRoleMember.ToList();
            return ddlVM;
        }


        public List<ChangeHistoryUpdateViewModel> UpdateCase(CaseUpdateViewModel caseVM, out long lngCaseID, out string strCaseRefNo, UserInfoViewModel currentUser = null)
        {
            List<ChangeHistoryUpdateViewModel> lst = new List<ChangeHistoryUpdateViewModel>();
            lngCaseID = 0;
            strCaseRefNo = string.Empty;

            // Retrieve orginal records for audit and change history 
            CaseViewModel oriCase = GetById(Convert.ToInt64(caseVM.Case.CaseID), currentUser);
            // 1. Check for update conflict
            if (!Utilities.CompareByteArray(caseVM.Case.ChangeStamp, oriCase.ChangeStamp))
            {
                throw new UpdateConflictException();
            }
            if (caseVM.Case.ActChannelID == (int)Constant.ActChannel.CFF && caseVM.Case.CreatedBy == Constant.System.Name) { 
                caseVM.Case.CreatedBy = caseVM.Case.LastUpdatedBy;
                caseVM.Case.CreatedByName = caseVM.Case.LastUpdatedByName;
                //caseVM.Case.CreatedDateTime = caseVM.Case.LastUpdatedDateTime;
                if (oriCase.WorkflowDetail == null) { //route to agent
                    caseVM.Case.AssignedTo = caseVM.Case.LastUpdatedBy;
                    caseVM.Case.AssignedToName = caseVM.Case.LastUpdatedByName;
                    caseVM.Case.AssignedDateTime = caseVM.Case.LastUpdatedDateTime;
                    caseVM.Case.AssignedToEmail = currentUser.Email;
                }
            }
            // 2. Update Case
            DataTable dTblResult = repo.UpdateCase(caseVM);

            // 3. Get ChangeHistory
            foreach (ChangeHistoryUpdateViewModel changeHistoryItem in caseVM.ChangeHistory)
            {
                //Get object original value
                string strOriValue = string.Empty;
                string[] arr = changeHistoryItem.FieldName.Split('_');
                var obj = Utilities.GetPropertyValue(oriCase, arr[0]);

                if (obj != null)
                {
                    for (int j = 1; j < arr.Length; j++)
                    {
                        obj = Utilities.GetPropertyValue(obj, arr[j]);
                    }

                    //strOriValue = obj == null ? "" : obj.ToString();

                    if (obj != null)
                    {
                        switch (obj.GetType().Name)
                        {
                            case "DateTime":
                                strOriValue = Convert.ToDateTime(obj).ToString("dd MMM yyyy");
                                break;
                            case "Boolean":
                                bool flag = (bool)obj;
                                if (flag == true)
                                    strOriValue = "Ya";
                                else
                                    strOriValue = "Tidak";
                                break;
                            case "Decimal":
                                strOriValue = String.Format("{0:N}", Convert.ToDouble(obj));
                                break;
                            default:
                                strOriValue = obj.ToString();
                                break;
                        }
                    }
                }
                //else
                //    changeHistoryItem.NewValue = string.Empty;


                //switch (changeHistoryItem.FieldName)
                //{
                //    case "NilaiKes":
                //        changeHistoryItem.OldValue = (string.IsNullOrEmpty(strOriValue) ? strOriValue : String.Format("{0:N}", Convert.ToDouble(strOriValue)));
                //        break;
                    //case "NotaTemuduga_NTTarikhTerima":
                    //    DateTime dt = Convert.ToDateTime(strOriValue);
                    //    changeHistoryItem.OldValue = (string.IsNullOrEmpty(strOriValue) ? strOriValue : dt.ToString("dd MMM yyyy"));
                    //    break;
                    //case "NotaTemuduga_NTStatusSuratKeluar":
                    //case "NotaTemuduga_NTStatusSegera":
                    //case "NotaTemuduga_NTStatusTidakPerluTindakan":
                    //case "NotaTemuduga_NTStatusCetakSurat":
                    //    changeHistoryItem.OldValue = strOriValue == "True" ? "Yes" : "No";
                    //    break;
                //    default:
                //        changeHistoryItem.OldValue = strOriValue;
                //        break;
                //}

                changeHistoryItem.OldValue = strOriValue;

                //changeHistoryItem.OldValue = changeHistoryItem.FieldName == "NilaiKes" ? (string.IsNullOrEmpty(oriValue) ? oriValue : String.Format("{0:N}", Convert.ToDouble(oriValue))) : oriValue;
                changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue);
            }
            GetChangeHistoryForCloseCase(caseVM, oriCase);
            lst = InsertChangeHistory(caseVM.ChangeHistory, caseVM.Case.LastUpdatedByName, caseVM.Case.LastUpdatedBy, caseVM.Case.LastUpdatedDateTime); //if INSERT, skip InsertChangeHistory

            if (dTblResult != null && dTblResult.Rows.Count > 0)
            {
                lngCaseID = Convert.ToInt64(dTblResult.Rows[0]["CaseID"]);
                strCaseRefNo = dTblResult.Rows[0]["CaseRefNo"].ToString();
            }

            //Check if activity == System && CFF, Update AssignTo to Case AssignTo
            var caseID = lngCaseID;
            List<ChangeHistoryUpdateViewModel> lstActChgHistory = new List<ChangeHistoryUpdateViewModel>();
            List<Activity> lstAct = repoAct.GetAll().Where(x => x.CaseID == caseID && x.ActChannelID == (int)Constant.ActChannel.CFF && x.LastUpdatedBy == Constant.System.Name).ToList();
            if (lstAct.Count > 0)
            {
                foreach (var item in lstAct)
                {
                    item.IsDraft = false;
                    if (oriCase.WorkflowDetail == null)
                    { //route to agent
                        item.AssignedOfficerLogin = caseVM.Case.LastUpdatedBy;
                        item.AssignedOfficerName = caseVM.Case.LastUpdatedByName;
                        item.AssignedDateTime = caseVM.Case.LastUpdatedDateTime;
                        item.AssignedOfficerEmail = caseVM.Case.AssignedToEmail;
                    }
                    item.CreatedBy = caseVM.Case.LastUpdatedBy;
                    item.CreatedByName = caseVM.Case.LastUpdatedByName;
                    //item.CreatedDateTime = caseVM.Case.LastUpdatedDateTime;
                    item.LastUpdatedBy = caseVM.Case.LastUpdatedBy;
                    item.LastUpdatedByName = caseVM.Case.LastUpdatedByName;
                    item.LastUpdatedDateTime = caseVM.Case.LastUpdatedDateTime;
                    repoAct.Edit(item);
                    repoAct.Save();
                }
            }

            // If Case Closed 
            if ((bool)caseVM.Case.IsCaseClosed)
            {
                caseID = lngCaseID;
                // Update Closed to all related Activity which is "belum selesai"
                var actCompletedStatus = AdminService.LookupParams.Where(x => x.LookupCode == "ActivityStatus" && x.LookupValue == ((int)Constant.StatusLevel1.Selesai).ToString()).FirstOrDefault();
                lstAct = repoAct.GetAll().Where(x => x.CaseID == caseID && x.ActStatusID != actCompletedStatus.LookupParamID).ToList();

                lstActChgHistory = new List<ChangeHistoryUpdateViewModel>();
                foreach (Activity act in lstAct)
                {
                    var activityStatus = AdminService.LookupParams.Where(x => x.LookupParamID == act.ActStatusID).FirstOrDefault();

                    act.ActStatusID = actCompletedStatus.LookupParamID; //set ActStatusID = Completed
                    act.LastUpdatedBy = caseVM.Case.LastUpdatedBy;
                    act.LastUpdatedByName = caseVM.Case.LastUpdatedByName;
                    act.LastUpdatedDateTime = caseVM.Case.LastUpdatedDateTime;
                    repoAct.Edit(act);
                    repoAct.Save();

                    //Add History For activity
                    lstActChgHistory.Add(BindChangeHistVM(act.ActivityID, "ActStatus", "Activity Status", activityStatus.ParamDesc, actCompletedStatus.ParamDesc));
                }

                repoAct.InsertChangeHistory(lstActChgHistory.Where(x => x.IsChanged == true).ToList(), caseVM.Case.LastUpdatedByName, caseVM.Case.LastUpdatedBy, caseVM.Case.LastUpdatedDateTime);

                // Insert WF History
                InsertWorkflowForClosedCase(caseVM, currentUser);
            }

            return lst;
        }

        public List<long> GetCFFListByCaseID(long lngCaseID)
        {
            return repo.GetCFFListByCaseID(lngCaseID);
        }

        public List<ChangeHistoryUpdateViewModel> InsertCase(CaseUpdateViewModel caseVM, out long lngCaseID, out string strCaseRefNo, UserInfoViewModel currentUser = null)
        {
            List<ChangeHistoryUpdateViewModel> lst = new List<ChangeHistoryUpdateViewModel>();
            lngCaseID = 0;
            strCaseRefNo = string.Empty;

            // Transfer to case, get Activity ChangeStamp
            byte[] changeStampToCompare = GetChangeStampbyID((int)Constant.TableType.Activity, caseVM.ActivityID);

            // 1. Check for update conflict
            if (!Utilities.CompareByteArray(caseVM.Case.ChangeStamp, changeStampToCompare))
            {
                throw new UpdateConflictException();
            }

            using (var scope = new TransactionScope(TransactionScopeOption.Required))
            {
                // 2. Insert Case
                DataTable dTblResult = repo.InsertCase(caseVM);

                // 3. Update CaseID to Activity
                Activity act = repoAct.GetByID(caseVM.ActivityID);
                if (dTblResult != null && dTblResult.Rows.Count > 0)
                {
                    lngCaseID = Convert.ToInt64(dTblResult.Rows[0]["CaseID"]);
                    strCaseRefNo = dTblResult.Rows[0]["CaseRefNo"].ToString();

                    act.CaseID = lngCaseID;
                    act.Kategori1ID = caseVM.Case.Kategori1ID;
                    act.Kategori2ID = caseVM.Case.Kategori2ID;
                    act.Kategori3ID = caseVM.Case.Kategori3ID;
                    act.ActStatus1ID = caseVM.Case.CaseStatusLevel1ID; //SL added for transfer to case, in case user enter in the new case.
                    act.ActStatus2ID = caseVM.Case.CaseStatusLevel2ID; //no need change history
                    act.ActStatus3ID = caseVM.Case.CaseStatusLevel3ID;
                    act.TahunTaksiran = caseVM.Case.TahunTaksiran;
                    act.NilaiKes = caseVM.Case.NilaiKes;
                    act.NoBaucer = caseVM.Case.NoBaucer;
                    act.TahapID = caseVM.Case.TahapID;
                    act.IsTransferToCase = true;
                    act.LastUpdatedBy = caseVM.Case.LastUpdatedBy;
                    act.LastUpdatedByName = caseVM.Case.LastUpdatedByName;
                    act.LastUpdatedDateTime = caseVM.Case.LastUpdatedDateTime;

                    if ((bool)caseVM.Case.IsCaseClosed)
                    {
                        var actCompletedStatus = AdminService.LookupParams.Where(x => x.LookupCode == "ActivityStatus" && x.LookupValue == ((int)Constant.StatusLevel1.Selesai).ToString()).FirstOrDefault();
                        var activityStatus = AdminService.LookupParams.Where(x => x.LookupParamID == act.ActStatusID).FirstOrDefault();
                        act.ActStatusID = actCompletedStatus.LookupParamID; //set ActStatusID = Completed

                        List<ChangeHistoryUpdateViewModel> lstActChgHistory = new List<ChangeHistoryUpdateViewModel>();

                        //Add History For activity
                        lstActChgHistory.Add(BindChangeHistVM(act.ActivityID, "ActStatus", "Activity Status", activityStatus.ParamDesc, actCompletedStatus.ParamDesc));
                        repoAct.InsertChangeHistory(lstActChgHistory.Where(x => x.IsChanged == true).ToList(), caseVM.Case.LastUpdatedByName, caseVM.Case.LastUpdatedBy, caseVM.Case.LastUpdatedDateTime);
                    }
                }
                repoAct.Edit(act);
                repoAct.Save();

                // Update Case TP Info from activity
                repo.UpdateCaseTPInfo(lngCaseID);

                // If Case Closed, then insert WF History
                if ((bool)caseVM.Case.IsCaseClosed)
                    InsertWorkflowForClosedCase(caseVM, currentUser);

                scope.Complete();
            }
            return lst;
        }

        private void InsertWorkflowForClosedCase(CaseUpdateViewModel caseVM, UserInfoViewModel currentUser)
        {
            DateTime dtNow = DateTime.Now;
            List<ChangeHistoryUpdateViewModel> lst = new List<ChangeHistoryUpdateViewModel>();
            //Get Existing Data in Workflow Table
            CasesWorkflowActionViewModel workflowcase = GetCurrentWorkFlowById(caseVM.Case.CaseID, currentUser);
            if (workflowcase != null)
            {
                if (workflowcase.CaseID > 0)
                {
                    // Closed current Case Workflow
                    workflowcase.AssignBy = caseVM.Case.LastUpdatedBy;
                    workflowcase.AssignByName = caseVM.Case.LastUpdatedByName;
                    workflowcase.DecisionID = (int)Constant.WorkFlow.WorkflowDecision.Close;
                    workflowcase.CloseRemarks = WorkflowSystemAutoRemark(workflowcase.DecisionID, caseVM.Case.LastUpdatedByName);
                    repo.InsertWorkflowHistory(workflowcase, dtNow);
                    repoWorkflow.UpdateCaseClosedForWorkflow(workflowcase, dtNow);

                    // Add Workflow Status Old and new value to Change History Table
                    var strWorkflowOldStatus = AdminService.LookupParamSys.Where(x => x.LookupParamSysID == workflowcase.WFStatusID).FirstOrDefault();
                    var strWorkflowNewStatus = Utilities.GetEnumDescription(Constant.WorkFlow.WorkflowStatus.Closed);
                    lst.Add(BindChangeHistVM(workflowcase.CaseID, "WorkflowStatus", "Status Aliran Kerja", strWorkflowOldStatus.ParamDesc, strWorkflowNewStatus));
                    repo.InsertChangeHistory(lst, workflowcase.AssignByName, workflowcase.AssignBy, dtNow);
                }
            }
        }

        public bool DeleteCase(EntityUpdateViewModel model, string strUserID, string strUserName, DateTime dtUpdated, out DataTable dtblLinkedActivity)
        {
            byte[] oriChangeStamp = repo.GetChangeStampbyID((int)Constant.TableType.Case, model.CaseID.GetValueOrDefault());
            bool blnIsSuccess = false;
            dtblLinkedActivity = null;
            if (!Utilities.CompareByteArray(model.ChangeStamp, oriChangeStamp))
            {
                throw new UpdateConflictException();
            }
            blnIsSuccess = repo.DeleteCase(model.CaseID.GetValueOrDefault(), strUserID, strUserName, dtUpdated, out dtblLinkedActivity);

            return blnIsSuccess;
        }

        public List<ChangeHistoryUpdateViewModel> InsertChangeHistory(List<ChangeHistoryUpdateViewModel> model, string strUserName, string strUserID, DateTime dtUpdated)
        {
            int intReturnValue = 0;
            List<ChangeHistoryUpdateViewModel> lst = model.Where(x => x.IsChanged).ToList();
            intReturnValue = repo.InsertChangeHistory(lst, strUserName, strUserID, dtUpdated);

            return lst;
        }

        public List<ChangeHistoryUpdateViewModel> UpdateCaseWorkflow(CaseWorkflowUpdateViewModel caseworkflow, out string strCaseRefNo, ref WorkflowUserViewModel assignedUser, DateTime now)
        {
            List<ChangeHistoryUpdateViewModel> lst = new List<ChangeHistoryUpdateViewModel>();
            // Retrieve orginal records for audit and change history 
            CasesWorkflowActionViewModel OriCaseWorkflowData = new CasesWorkflowActionViewModel();
            strCaseRefNo = string.Empty;
            OriCaseWorkflowData = repo.GetExistingWorkflowRecord(caseworkflow.Workflow.CaseID);
            if (OriCaseWorkflowData == null)
            {
                // Check for update conflict
                if (caseworkflow.Workflow.WorkflowID != 0)
                {
                    //TODO Update conflict
                    throw new UpdateConflictException();
                }

                foreach (ChangeHistoryUpdateViewModel changeHistoryItem in caseworkflow.WorkflowChangeHistory)
                {
                    //Get object original value
                    string oriValue = string.Empty;
                    if (changeHistoryItem.FieldName.IndexOf('_') > 0)
                    {
                        string[] arr = changeHistoryItem.FieldName.Split('_');
                        var obj = Utilities.GetPropertyValue(OriCaseWorkflowData, arr[0]);

                        for (int j = 1; j < arr.Length; j++)
                        {
                            obj = Utilities.GetPropertyValue(obj, arr[j]);
                        }
                        oriValue = obj == null ? "" : obj.ToString();
                    }
                    else
                    {
                        oriValue = "";
                    }
                    changeHistoryItem.OldValue = oriValue;
                    changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue);
                }

                if (caseworkflow.Workflow.DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Assign)
                {
                    caseworkflow.Workflow.WFStatusID = (int)Constant.WorkFlow.WorkflowStatus.PendingAction;
                    assignedUser = caseworkflow.Workflow.AssignTo;
                    caseworkflow.Workflow.Remarks = WorkflowSystemAutoRemark(caseworkflow.Workflow.DecisionID, assignedUser.DisplayName);
                }
            }
            else
            {
                if (caseworkflow.Workflow.WorkflowID != OriCaseWorkflowData.WorkflowID)
                {
                    //TODO Update conflict
                    throw new UpdateConflictException();
                }

                foreach (ChangeHistoryUpdateViewModel changeHistoryItem in caseworkflow.WorkflowChangeHistory)
                {
                    //Get object original value
                    string oriValue = string.Empty;
                    if (changeHistoryItem.FieldName.IndexOf('_') > 0)
                    {
                        string[] arr = changeHistoryItem.FieldName.Split('_');
                        var obj = Utilities.GetPropertyValue(OriCaseWorkflowData, arr[0]);

                        for (int j = 1; j < arr.Length; j++)
                        {
                            obj = Utilities.GetPropertyValue(obj, arr[j]);
                        }
                        oriValue = obj == null ? "" : obj.ToString();
                    }
                    else
                    {
                        var obj = Utilities.GetPropertyValue(OriCaseWorkflowData, changeHistoryItem.FieldName);
                        oriValue = obj == null ? "" : obj.ToString();
                    }
                    changeHistoryItem.OldValue = oriValue;
                    changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue);
                }

                if (caseworkflow.Workflow.DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Assign)
                {
                    caseworkflow.Workflow.WFStatusID = (int)Constant.WorkFlow.WorkflowStatus.PendingAction;
                    OriCaseWorkflowData.WFStatusID = caseworkflow.Workflow.WFStatusID;
                    OriCaseWorkflowData.DecisionID = caseworkflow.Workflow.DecisionID;
                    assignedUser = caseworkflow.Workflow.AssignTo;
                }
                else if (caseworkflow.Workflow.DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Recall)
                {
                    caseworkflow.Workflow.WFStatusID = (int)Constant.WorkFlow.WorkflowStatus.PendingAction;
                    assignedUser.ID = caseworkflow.Workflow.AssignBy;
                    assignedUser.DisplayName = caseworkflow.Workflow.AssignByName;
                    assignedUser.Email = caseworkflow.Workflow.AssignByEmail;
                    assignedUser.AssignToType = (int)Constant.WorkFlow.AssignToType.User;//caseworkflow.Workflow.AssignTo.AssignToType;
                    OriCaseWorkflowData.WFStatusID = caseworkflow.Workflow.WFStatusID;
                    OriCaseWorkflowData.DecisionID = caseworkflow.Workflow.DecisionID;
                }
                else if (caseworkflow.Workflow.DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Return)
                {
                    caseworkflow.Workflow.WFStatusID = (int)Constant.WorkFlow.WorkflowStatus.PendingAction;
                    OriCaseWorkflowData.WFStatusID = caseworkflow.Workflow.WFStatusID;
                    OriCaseWorkflowData.DecisionID = caseworkflow.Workflow.DecisionID;

                    assignedUser.AssignToType = (int)Constant.WorkFlow.AssignToType.User; //caseworkflow.Workflow.AssignTo.AssignToType;
                    assignedUser.ID = OriCaseWorkflowData.AssignBy;
                    assignedUser.DisplayName = OriCaseWorkflowData.AssignByName;
                    var userdata = user.GetUserEmailByLoginID(assignedUser.ID);
                    if (userdata != null)
                    {
                        assignedUser.Email = userdata.Email;
                    }
                    else
                    {
                        assignedUser.Email = "";
                    }
                }

                // Construct workflow remarks according to decision status
                caseworkflow.Workflow.Remarks = WorkflowSystemAutoRemark(caseworkflow.Workflow.DecisionID, assignedUser.DisplayName);
            }

            if (assignedUser.Email == null)
            {
                assignedUser.Email = "";
            }

            if (assignedUser.ManagerFunctionRoleID == null)
            {
                assignedUser.ManagerFunctionRoleID = "";
            }

            // TODO : Transaction Scope
            using (var scope = new TransactionScope(TransactionScopeOption.Required))
            {
                if (OriCaseWorkflowData != null && OriCaseWorkflowData.CaseID != 0)
                {
                    OriCaseWorkflowData.AssignBy = caseworkflow.Workflow.AssignBy;
                    OriCaseWorkflowData.AssignByName = caseworkflow.Workflow.AssignByName;
                    repo.InsertWorkflowHistory(OriCaseWorkflowData, now);
                }

                DataTable dTblResult = repo.InsertCaseWorkflow(caseworkflow, assignedUser, now);
                if (dTblResult != null && dTblResult.Rows.Count > 0)
                {
                    strCaseRefNo = dTblResult.Rows[0]["CaseRefNo"].ToString();
                }

                lst = InsertChangeHistory(caseworkflow.WorkflowChangeHistory, caseworkflow.Workflow.LastUpdatedBy, caseworkflow.Workflow.LastUpdatedBy, now);
                scope.Complete();
            }

            return lst;
        }

        public CasesWorkflowActionViewModel GetCurrentWorkFlowById(long caseId, UserInfoViewModel currentUser = null)
        {
            CasesWorkflowActionViewModel obj = repo.GetExistingWorkflowRecord(caseId);
            WorkflowUserViewModel assignedUser = new WorkflowUserViewModel();
            if (obj != null)
            {
                assignedUser.DisplayName = obj.AssignToName;
                assignedUser.ID = obj.AssignToLogin;
                assignedUser.Email = obj.AssignToEmail;
                assignedUser.AssignToType = obj.AssignToTypeID;
                obj.AssignTo = assignedUser;

                if (assignedUser.AssignToType == (int)Constant.LookupParamSys.AssignToTypeUnit) // Assigned Unit
                {
                    var objWfUser = obj.wfUser.Where(s => s.AssignToLogin == currentUser.LoginID).FirstOrDefault();
                    if (objWfUser != null)
                    {
                        if (objWfUser.AssignToLogin.ToLower() == currentUser.LoginID.ToLower())
                        {
                            obj.IsCurrentLogin = true;
                            obj.IsOtherLogin = false;
                        }
                        else if (objWfUser.AssignToLogin.ToLower() != currentUser.LoginID.ToLower() &&
                                  objWfUser.AssignBy.ToLower() != currentUser.LoginID.ToLower())
                        {
                            obj.IsOtherLogin = true;
                        }
                    }
                    else
                    {
                        if (obj.AssignBy.ToLower() == currentUser.LoginID.ToLower())
                        {
                            obj.IsOtherLogin = false;
                        }
                        else
                        {
                            obj.IsOtherLogin = true;
                        }
                    }
                }
                else if (assignedUser.AssignToType == (int)Constant.LookupParamSys.AssignToTypeUser)  //Assigned User
                {
                    if (obj.AssignToLogin.ToLower() == currentUser.LoginID.ToLower())
                    {
                        var managerLoginId = currentUser.Manager != null ? currentUser.Manager.ID : null; //Get Manager LoginId
                        if (managerLoginId != null)
                        {
                            assignedUser.ManagerId = managerLoginId != null ? managerLoginId : "";
                            assignedUser.keyword = "";
                            var managerDetail = repo.GetWorkFlowAllUserOrUnit(assignedUser);
                            var objManagerDetail = managerDetail.Where(s => s.ID == assignedUser.ManagerId).FirstOrDefault();
                            if (objManagerDetail != null)
                            {
                                assignedUser.DisplayName = objManagerDetail.DisplayName;
                                assignedUser.ID = objManagerDetail.ID;
                                assignedUser.Email = objManagerDetail.Email;
                            }
                        }
                        else
                        {
                            obj.AssignToTypeID = 0;
                        }

                        obj.IsCurrentLogin = true;
                        obj.IsOtherLogin = false;

                    }
                    else if (obj.AssignToLogin.ToLower() != currentUser.LoginID.ToLower() &&
                              obj.AssignBy.ToLower() != currentUser.LoginID.ToLower())
                    {
                        obj.IsOtherLogin = true;
                    }

                }
            }
            return obj;
        }

        public List<CaseListViewModel> GetCaseListByID(CaseListPagedListViewModel paging, out int intCount)
        {
            intCount = 0;

            DataSet ds = repo.GetCaseListByID(paging.SortExpression, paging.PageIndex, paging.Length,
                                            paging.TPID, paging.Kategori1IDCase, paging.Kategori2IDCase, paging.Kategori3IDCase);

            List<CaseListViewModel> lstCaseListVM = new List<CaseListViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstCaseListVM = repo.DataTableToList<CaseListViewModel>(ds.Tables[0]).ToList();
                if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
                    intCount = Convert.ToInt32(ds.Tables[1].Rows[0][0].ToString());
            }

            return lstCaseListVM;

            //return repo.GetChangesHistory(TPID, ActivityID, CaseID);
        }

        public void InsertBackOfficeQueueForCase(long lngCaseID)
        {
            ReMSBackOfficeQueueViewModel cls = repo.GetBackOfficeFromCase(lngCaseID);

            repo.InsertBackOfficeQueue(cls);
             
            //return repo.GetChangesHistory(TPID, ActivityID, CaseID);
        }

        public CaseWorkflowAssignToUnitIDViewModel GetWorkFlowAssignToByKategoryId(CaseWorkflowAssignToUnitIDViewModel KategoryId)
        {
            return repo.GetWorkflowAssignToValue(KategoryId);
        }

        public List<WorkflowUserViewModel> GetWorkFlowAllUserOrUnit(WorkflowUserViewModel data)
        {
            List<WorkflowUserViewModel> workflowUser = new List<WorkflowUserViewModel>();
            workflowUser = repo.GetWorkFlowAllUserOrUnit(data);

            return workflowUser;
        }

        public List<CaseBelumSelesaiAssignToDashboardViewModel> GetDashboardMyCreatedCase(string CreatedBy, CaseBelumSelesaiAssignToDashboardViewModel paging, out int intCount)
        {
            intCount = 0;
            DataSet ds = repo.GetDashboardMyCreatedCase(CreatedBy, paging);

            List<CaseBelumSelesaiAssignToDashboardViewModel> lstDashBoardAssignToMe = new List<CaseBelumSelesaiAssignToDashboardViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstDashBoardAssignToMe = repo.DataTableToList<CaseBelumSelesaiAssignToDashboardViewModel>(ds.Tables[0]).ToList();
                if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
                    intCount = Convert.ToInt32(ds.Tables[1].Rows[0][0].ToString());
            }

            return lstDashBoardAssignToMe;
        }

        public List<CaseBelumSelesaiAssignToDashboardViewModel> GetDashboardMyPendingCase(string CreatedBy, CaseBelumSelesaiAssignToDashboardViewModel paging, out int intCount)
        {
            intCount = 0;
            DataSet ds = repo.GetDashboardMyPendingCase(CreatedBy, paging);

            List<CaseBelumSelesaiAssignToDashboardViewModel> lstDashBoardAssignFrom = new List<CaseBelumSelesaiAssignToDashboardViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstDashBoardAssignFrom = repo.DataTableToList<CaseBelumSelesaiAssignToDashboardViewModel>(ds.Tables[0]).ToList();
                if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
                    intCount = Convert.ToInt32(ds.Tables[1].Rows[0][0].ToString());
            }

            return lstDashBoardAssignFrom;

        }

        public List<CaseBelumSelesaiAssignToDashboardViewModel> GetDashboardAssignCaseForUnit(CaseBelumSelesaiAssignToDashboardViewModel paging, out int intCount)
        {
            intCount = 0;
            List<CaseBelumSelesaiAssignToDashboardViewModel> lstUnitCase = new List<CaseBelumSelesaiAssignToDashboardViewModel>();
            DataSet ds = repo.GetDashboardAssignCaseForUnit(paging);

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstUnitCase = repo.DataTableToList<CaseBelumSelesaiAssignToDashboardViewModel>(ds.Tables[0]).ToList();
                if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
                    intCount = Convert.ToInt32(ds.Tables[1].Rows[0][0].ToString());
            }

            return lstUnitCase;
        }

        public List<CaseAssignmentViewModel> GetCaseBulkAssignListing(CaseAssignmentViewModel paging, out int intCount, out List<WorkFlowIDs> WorkflowList)
        {
            intCount = 0;
            List<CaseAssignmentViewModel> lstCaseListing = new List<CaseAssignmentViewModel>();
            DataSet ds = repo.GetCaseBulkAssignListing(paging);
            WorkflowList = new List<WorkFlowIDs>();
            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstCaseListing = repo.DataTableToList<CaseAssignmentViewModel>(ds.Tables[0]).ToList();
                if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
                    intCount = Convert.ToInt32(ds.Tables[1].Rows[0][0].ToString());
                if (ds.Tables[1] != null && ds.Tables[2].Rows.Count > 0)
                    WorkflowList = repo.DataTableToList<WorkFlowIDs>(ds.Tables[2]).ToList();
            }

            return lstCaseListing;
        }

        public List<CaseAssignmentViewModel> GetCaseReassignListing(CaseAssignmentViewModel paging, out int intCount, out List<WorkFlowIDs> WorkflowList)
        {
            intCount = 0;
            List<CaseAssignmentViewModel> lstCaseListing = new List<CaseAssignmentViewModel>();
            DataSet ds = repo.GetCaseReassignListing(paging);
            WorkflowList = new List<WorkFlowIDs>();
            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstCaseListing = repo.DataTableToList<CaseAssignmentViewModel>(ds.Tables[0]).ToList();
                if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
                    intCount = Convert.ToInt32(ds.Tables[1].Rows[0][0].ToString());
                if (ds.Tables[1] != null && ds.Tables[2].Rows.Count > 0)
                    WorkflowList = repo.DataTableToList<WorkFlowIDs>(ds.Tables[2]).ToList();
            }

            return lstCaseListing;
        }

        public string WorkflowSystemAutoRemark(int? DecisionID, string username)
        {
            var remark = string.Empty;
            if (DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Assign)
            {
                remark = string.Format("{0}: {1} {2} ", Constant.WorkFlow.WorkflowDecision.Assign, " Pending Action By ", username);
            }
            else if (DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Recall)
            {
                remark = string.Format("{0}: {1} {2} ", Constant.WorkFlow.WorkflowDecision.Recall, " Pending Action By ", username);
            }
            else if (DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Return)
            {
                remark = string.Format("{0}: {1} {2} ", Constant.WorkFlow.WorkflowDecision.Return, " Pending Action By ", username);
            }
            else if (DecisionID == (int)Constant.WorkFlow.WorkflowDecision.Close)
            {
                remark = string.Format("{0}: {1} {2} ", Constant.WorkFlow.WorkflowDecision.Close, " Closed By ", username);
            }

            return remark;
        }

        public byte[] ReopenCase(EntityUpdateViewModel model, string strUserName, string strUserID, UserInfoViewModel userSvc, DateTime now)
        {
            CaseViewModel oriCase = GetById(Convert.ToInt64(model.CaseID), userSvc);

            if (!Utilities.CompareByteArray(model.ChangeStamp, oriCase.ChangeStamp))
            {
                //TODO Update conflict
                throw new UpdateConflictException();
            }
            byte[] changeStamp = repo.ReopenCase(model, strUserName, strUserID, now);

            List<ChangeHistoryUpdateViewModel> lstChgHistory = new List<ChangeHistoryUpdateViewModel>();
            var status1 = AdminService.StatusLevels.Where(x => x.StatusLevel1ID == model.CaseStatusLevel1ID && x.IsActive == true).FirstOrDefault();
            var status2 = status1.StatusLevel2.Where(x => x.StatusLevel2ID == model.CaseStatusLevel2ID && x.IsActive == true).FirstOrDefault();

            AddHistoryByFieldName("CaseStatusLevel1Name", (long)model.CaseID, lstChgHistory, oriCase, "Status Level 1", status1.StatusLevel1Name);
            AddHistoryByFieldName("CaseStatusLevel2Name", (long)model.CaseID, lstChgHistory, oriCase, "Status Level 2", status2.StatusLevel2Name);
            if (oriCase.CaseStatusLevel3ID != null)
                AddHistoryByFieldName("CaseStatusLevel3Name", (long)model.CaseID, lstChgHistory, oriCase, "Status Level 3", string.Empty);
            InsertChangeHistory(lstChgHistory, strUserName, strUserID, now);

            return changeStamp;
        }

        public DropdownViewModel GetCaseReassignDropdown()
        {
            DropdownViewModel ddlVM = new DropdownViewModel();

            ddlVM.Kategori1Options = Utilities.SortDDL(AdminService.Kategori1.Where(x => x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.Kategori1ID, Text = x.Kategori1Name, IsDefault = false, SeqNo = 0 }).ToList());
           
            ddlVM.WorkflowAssignToTypeOption = AdminService.LookupParamSys.Where(x => x.LookupCode == "AssignToType" && (x.LookupParamSysID == (int)Constant.LookupParamSys.AssignToTypeUser || x.LookupParamSysID == (int)Constant.LookupParamSys.AssignToTypeUnit))
                        .Select(x => new DropdownDetailViewModel
                        {
                            Value = x.LookupParamSysID,
                            Text = x.ParamDesc,
                            IsDefault = x.LookupParamSysID == (int)Constant.LookupParamSys.AssignToTypeUser
                        }).ToList();

            ddlVM.WorkflowAssignToSeksyenOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeSeksyen && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            ddlVM.WorkflowAssignToJabatanOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeJabatan && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            ddlVM.WorkflowAssignToCawanganOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeCawangan && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            ddlVM.WorkflowAssignToUnitOption = AdminService.Units.Where(x => x.HierarchyType == (int)Constant.LookupParamSys.HierarchyTypeUnit && x.IsActive == true)
                .Select(x => new WorkflowUserViewModel
                {
                    ID = x.UnitID.ToString(),
                    DisplayName = x.UnitName,
                    ParentUnitID = x.ParentUnitID,
                    AdditionalInfo = x.AdditionalInfo,
                    HierarchyType = x.HierarchyType,
                    ManagerFunctionRoleID = x.ManagerFunctionRoleID,
                    AssignToType = Convert.ToInt16(Constant.LookupParamSys.AssignToTypeUnit)
                }).OrderBy(x => x.DisplayName).ToList();

            //Enhancement List Purpose
            ddlVM.MainKategoriOptions = AdminService.Kategoris.Where(x => x.IsActive == true).ToList<MainKategori>();

            return ddlVM;
        }


        public string PrintPenerimaanDoc(long lngCaseID, string strLoginName, string strBranchName, byte[] qrcode, DateTime dtnow, string DocKategoryActID)
        {
            EmailService svcEmail = new EmailService();
            return svcEmail.GetHTMLParsedContentForPreview((int)Constant.EmailTemplate.PrintPenerimaanDoc, lngCaseID, "", "", "", qrcode, dtnow, strBranchName, strLoginName, (int)Constant.TableType.Case, DocKategoryActID);
        }

        //public List<CaseAttachmentResponseViewModel> GetCaseAttachmentToReMS(long CaseID)
        //{
        //    List<CaseAttachmentResponseViewModel> lstCaseAttachment = new List<CaseAttachmentResponseViewModel>();
        //    lstCaseAttachment = repo.GetCaseAttachmentToReMS(CaseID);
        //    return lstCaseAttachment;
        //}

        #region Private methods
        /// <summary>
        /// INSERT HISTORY when close case & old status = belum selesai, set to Selesai
        /// </summary>
        /// <param name="caseVM"></param>
        /// <param name="oriCase"></param>
        private void GetChangeHistoryForCloseCase(CaseUpdateViewModel caseVM, CaseViewModel oriCase)
        {
            bool blnIsCaseStatusLevel1Exists = caseVM.ChangeHistory.Any(x => x.FieldName == "CaseStatusLevel1Name");
            if (!blnIsCaseStatusLevel1Exists)
            {
                if (caseVM.Case.IsCaseClosed == true && oriCase.CaseStatusLevel1ID == 2) //if close case & old status = belum selesai, set to Selesai
                {
                    var status1 = AdminService.StatusLevels.Where(x => x.StatusLevel1ID == caseVM.Case.CaseStatusLevel1ID && x.IsActive == true).FirstOrDefault();
                    var status2 = status1.StatusLevel2.Where(x => x.StatusLevel2ID == caseVM.Case.CaseStatusLevel2ID && x.IsActive == true).FirstOrDefault();
                    ChangeHistoryUpdateViewModel changeHistVM = new ChangeHistoryUpdateViewModel();

                    AddHistoryByFieldName("CaseStatusLevel1Name", caseVM.Case.CaseID, caseVM.ChangeHistory, oriCase, "Status Level 1", status1.StatusLevel1Name);
                    AddHistoryByFieldName("CaseStatusLevel2Name", caseVM.Case.CaseID, caseVM.ChangeHistory, oriCase, "Status Level 2", status2.StatusLevel2Name);
                    if (oriCase.CaseStatusLevel3ID != null)
                        AddHistoryByFieldName("CaseStatusLevel3Name", caseVM.Case.CaseID, caseVM.ChangeHistory, oriCase, "Status Level 3", string.Empty);
                }
            }
        }

        private void AddHistoryByFieldName(string strFieldName, long lngCaseID, List<ChangeHistoryUpdateViewModel> lstChgHistory, CaseViewModel oriAct, string strDisplayName, string strNewValue)
        {
            string strOldValue = Utilities.GetPropertyValue(oriAct, strFieldName).ToString();
            ChangeHistoryUpdateViewModel changeHistVM = BindChangeHistVM(lngCaseID, strFieldName, strDisplayName, strOldValue, strNewValue);

            lstChgHistory.Add(changeHistVM);
        }

        private ChangeHistoryUpdateViewModel BindChangeHistVM(long lngCaseID, string strFieldName, string strDisplayName, string strOldValue, string strNewValue)
        {
            ChangeHistoryUpdateViewModel changeHistVM = new ChangeHistoryUpdateViewModel();
            changeHistVM.ID = lngCaseID;
            changeHistVM.FieldName = strFieldName;
            changeHistVM.DisplayName = strDisplayName;
            changeHistVM.OldValue = strOldValue;
            changeHistVM.NewValue = strNewValue;
            changeHistVM.IsChanged = !(changeHistVM.OldValue == changeHistVM.NewValue);

            return changeHistVM;
        }

        #endregion
    }
}
