using LHDN.CRM.Models.ViewModels;
using LHDN.CRM.Models.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using LHDN.CRM.BC.Common;
using System.Collections;
using System.Reflection;
using System.Transactions;
using System.Net;
using System.Web.Security;
using System.Net.Http;
using Newtonsoft.Json;
using System.Net.Http.Headers;
using Newtonsoft.Json.Linq;

namespace LHDN.CRM.BC.Services
{
    public class ActivityService : ServiceBase<Models.ViewModels.ActivityViewModel>
    {
        private Repositories.ActivityRepository repo = new Repositories.ActivityRepository();
        private Repositories.TaxPayerRepository repoTP = new Repositories.TaxPayerRepository();
        private Repositories.CaseRepository repoCase = new Repositories.CaseRepository();
        private Repositories.AdminRepository repoAdmin = new Repositories.AdminRepository();
        private Repositories.OutboundRepository repoOutbound = new Repositories.OutboundRepository();
        private Repositories.TaskRepository repoTask = new Repositories.TaskRepository();
        private Repositories.EmailRepository repoEmail = new Repositories.EmailRepository();
        private Repositories.WorkflowRepository repoWorkflow = new Repositories.WorkflowRepository();
        private TaxPayerService tpSvc = new Services.TaxPayerService();
        private UserProfileService userSVC = new Services.UserProfileService();

        public ActivityViewModel GetById(long ActivityID, bool IsChangeHistoryUse = false, UserInfoViewModel currentUser = null)
        {
            ActivityViewModel vm = null;
            vm = repo.GetActivity(ActivityID);

            if (vm == null)
                throw new NotFoundException("Activity is deleted or not found! ");

            if (currentUser != null)
            {
                vm.CanCloseCase = currentUser.RolesObj.Any(x => x.RoleCode == Constant.Authentication.Cases.CloseCase);
                vm.CanCreateUpdateActCatatan = currentUser.RolesObj.Any(x => x.RoleCode == Constant.Authentication.Activity.CreateUpdateCatatan);

                //IsUnitManager
                if (!string.IsNullOrEmpty(vm.ManagerFuntionRoleID))
                {
                    bool blnIsUnitManager = false;
                    string[] lstRoles = vm.ManagerFuntionRoleID.Split("||");
                    foreach (var role in lstRoles)
                    {
                        if (currentUser.RoleGroups.Any(x => x.FunctionalRoleID == Convert.ToInt32(role)))
                        {
                            blnIsUnitManager = true;
                            break;
                        }
                    }
                    vm.IsUnitManager = blnIsUnitManager;
                }
            }

            //Temporary Comment first
            //if (vm.OutboundID > 0)
            //{
            //    vm.Outbound = GetOutboundDetails((long)vm.OutboundID, 0, 0);
            //}

            if (vm.HCLEmailBlastID > 0)
            {
                vm.EmailBlast = GetEmailBlastDetails((long)vm.HCLEmailBlastID);
            }

            if (IsChangeHistoryUse == false) //exclude when called for change history
            {
                if (vm.IsDraft == true && vm.TPID == null)
                {
                    vm.TPList = repoTP.SearchTaxPayer(vm.TPIDType, vm.TPIDNumber, vm.TPFBID, vm.TPTWID, vm.TPNoCukai);

                    if (vm.TPList != null && vm.TPList.Count > 0)
                    {
                        if (vm.TPList.Count == 1)
                        {
                            vm.TP = vm.TPList[0];
                            //vm.IsOrphanActivity = false;
                            vm.TPList = null;
                        }
                    }
                    else
                        vm.TPList = null;

                }
                else if (vm.TPID > 0)
                {
                    vm.TP = repoTP.GetTPForActivity(vm.TPID.GetValueOrDefault());
                    if (currentUser != null)
                        vm.TP.SearchTPProfile = currentUser.RolesObj.Any(x => x.RoleCode == Constant.Authentication.TaxPayer.SearchTPProfile);

                    // Check if user contains access to view verification tab
                    if (tpSvc.VerifyUserBranch(Constant.TableType.Activity, vm.TP.VIPCode, vm.TP.CWPenaksiranCPID,
                                vm.TP.CWPungutanCKHTID, vm.TP.CWPenaksiranCKHTID,
                                vm.TP.CWPungutanCPID, vm.TP.CWGuamanSivilID))
                    {
                        vm.TP.ViewVerificationTab = true;
                    }
                    // int intStatusID = 0;
                    // var status = AdminService.LookupParams.Where(x => x.LookupCode == "ActivityStatus" && x.IsActive == true && x.LookupParamID == vm.ActStatusID).FirstOrDefault();
                    // if ( Int32.TryParse(status.LookupValue, out intStatusID))
                    // {
                    if (vm.TP != null)
                    {
                        vm.TP.TPEjenCukais = repoTP.GetTaxPayerAgent(vm.TPID.GetValueOrDefault());

                        vm.TP.TPSpouseList = repoTP.GetAllSpouseDetail(vm.TPID.GetValueOrDefault());

                        vm.TP.TPShareholder = repoTP.GetTaxPayerShareHolderDetail(vm.TPID.GetValueOrDefault());

                        vm.TP.TPMajikanList = repoTP.GetTPActiveMajikanByID(vm.TPID.GetValueOrDefault());
                    }
                    //}
                }
            }
            //vm.IsPelangganPembayarSama has to be set even when draft time
            if (vm.PelangganTPID > 0 && vm.IsPelangganPembayarSama == false)
            {
                vm.TempPelanggan = repoTP.GetTPForActivity(vm.PelangganTPID.GetValueOrDefault());
                //// Check if user contains access to view verification tab
                //if (tpSvc.VerifyUserBranch(Constant.TableType.Activity, vm.TP.VIPCode, vm.TP.CWPenaksiranCPID,
                //            vm.TP.CWPungutanCKHTID, vm.TP.CWPenaksiranCKHTID,
                //            vm.TP.CWPungutanCPID, vm.TP.CWGuamanSivilID))
                //{
                //    vm.TP.ViewVerificationTab = true;
                //}
                if (vm.TempPelanggan != null)
                {
                    vm.TempPelanggan.TPEjenCukais = repoTP.GetTaxPayerAgent(vm.PelangganTPID.GetValueOrDefault());

                    vm.TempPelanggan.TPSpouseList = repoTP.GetAllSpouseDetail(vm.PelangganTPID.GetValueOrDefault());

                    vm.TempPelanggan.TPShareholder = repoTP.GetTaxPayerShareHolderDetail(vm.PelangganTPID.GetValueOrDefault());

                    vm.TempPelanggan.TPMajikanList = repoTP.GetTPActiveMajikanByID(vm.PelangganTPID.GetValueOrDefault());
                }
            }

            vm.IsCFFDraft = (vm.ActChannelID == (int)Constant.ActChannel.CFF && vm.AssignedOfficerLogin == Constant.System.Name && vm.CreatedBy == Constant.System.Name && vm.LastUpdatedBy == Constant.System.Name) ? true : false;
            if (vm.IsDraft == true && !vm.IsCFFDraft)
                return vm;

            vm.ActAttachmentList = repo.GetActAttachment(ActivityID);

            if (vm.TPID > 0)
                vm.ActVerification = repo.GetActVerification(ActivityID, (long)vm.TPID);

            vm.AdditionalKategoris = repo.GetActAdditionalKategori(ActivityID);

            vm.ActEmail = repo.GetActivityEmail(ActivityID);

            vm.ActCFF = repo.GetActivityCFF(ActivityID);

            vm.ActCatatans = GetAllActCatatan(ActivityID);

            if (vm.CaseID.GetValueOrDefault() > 0)
                vm.Case = repoCase.GetCaseForActivity(vm.CaseID.GetValueOrDefault());

            vm.NotaTemuduga = repo.GetAllNotaTemuduga(ActivityID);
            vm.ActDocReceived = repo.GetActDocReceived(ActivityID);

            if (vm.ActDocReceived != null && vm.ActDocReceived.Count > 0)
            {
                //distinct doc list
                var lstDistinctKatDoc = vm.ActDocReceived.GroupBy(x => x.DocListID).Select(grp => grp.First()).ToList();
                List<ActKategoriDocReceivedViewModel> lstActKategoriDocReceived = new List<ActKategoriDocReceivedViewModel>();
                foreach (var item in lstDistinctKatDoc)
                {
                    ActKategoriDocReceivedViewModel obj = new ActKategoriDocReceivedViewModel
                    {
                        DocListID = item.DocListID,
                        KategoriDocCode = item.KategoriDocCode,
                        KategoriDocName = item.KategoriDocName,
                        ActDocReceived = new List<ActDocReceivedViewModel>()
                    };
                    lstActKategoriDocReceived.Add(obj);
                }

                //get each doc list act doc received
                foreach (var item in lstActKategoriDocReceived)
                {
                    foreach (var actDocReceivedItem in vm.ActDocReceived)
                    {
                        if (actDocReceivedItem.DocListID == item.DocListID)
                            item.ActDocReceived.Add(actDocReceivedItem);
                    }
                }
                vm.KategoriDocReceived = lstActKategoriDocReceived;
            }

            //for transfer to case
            //TODO nid to put in Case Repo?
            vm.AllDocReceived = repo.GetCaseKategoriDocReceived(ActivityID);

            //vm.ActWorkflow = repoWorkflow.GetExistingWorkflowRecord(ActivityID, (int)Constant.TableType.Activity);
            vm.ActWorkflow = repoWorkflow.GetExistingWorkflowRecord(vm.WorkflowID);
            if (vm.ActWorkflow != null)
            {
                WorkflowUserViewModel assignedUser = new WorkflowUserViewModel();
                assignedUser.DisplayName = vm.ActWorkflow.AssignToName;
                assignedUser.ID = vm.ActWorkflow.AssignToLogin;
                assignedUser.Email = vm.ActWorkflow.AssignToEmail;
                assignedUser.AssignToType = vm.ActWorkflow.AssignToTypeID;
                vm.ActWorkflow.AssignTo = assignedUser;

                if (assignedUser.AssignToType == (int)Constant.LookupParamSys.AssignToTypeUnit) // Assigned Unit
                {
                    var objWfUser = vm.ActWorkflow.wfUser.Where(s => s.AssignToLogin == currentUser.LoginID).FirstOrDefault();
                    if (objWfUser != null)
                    {
                        if (objWfUser.AssignToLogin.ToLower() == currentUser.LoginID.ToLower())
                        {
                            vm.ActWorkflow.IsCurrentLogin = true;
                            vm.ActWorkflow.IsOtherLogin = false;
                        }
                        else if (objWfUser.AssignToLogin.ToLower() != currentUser.LoginID.ToLower() &&
                                  objWfUser.AssignBy.ToLower() != currentUser.LoginID.ToLower())
                        {
                            vm.ActWorkflow.IsOtherLogin = true;
                        }
                    }
                    else
                    {
                        if (vm.ActWorkflow.AssignBy.ToLower() == currentUser.LoginID.ToLower())
                        {
                            vm.ActWorkflow.IsOtherLogin = false;
                        }
                        else
                        {
                            vm.ActWorkflow.IsOtherLogin = true;
                        }
                    }
                }
                else if (assignedUser.AssignToType == (int)Constant.LookupParamSys.AssignToTypeUser)  //Assigned User
                {
                    if (vm.ActWorkflow.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 = repoCase.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
                        {
                            vm.ActWorkflow.AssignToTypeID = 0;
                        }

                        vm.ActWorkflow.IsCurrentLogin = true;
                        vm.ActWorkflow.IsOtherLogin = false;

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

                }
            }

            return vm;

        }

        public byte[] GetChangeStampbyID(long ID)
        {
            byte[] ChangeStamp = null;
            ChangeStamp = repo.GetChangeStampbyID(ID);

            return ChangeStamp;

        }

        public ActivityViewModel GetNewActivity(OpenNewActViewModel o, UserInfoViewModel currentUser = null)
        {
            ActivityViewModel vmAct = new ActivityViewModel();
            vmAct.IsPelangganPembayarSama = true;

            if (o.OutboundID > 0 || o.ReMSDataID > 0)
            {
                //From CC integration o.OutboundID 
                vmAct.OutboundID = o.OutboundID;
                //vmAct.AliranID = AdminService.LookupParams.Where(x => x.LookupCode == "Aliran" && x.IsActive == true && x.LookupValue == Constant.Aliran.Outbound).Select(x => x.LookupParamID).FirstOrDefault();

                int intCampaignID = 0;
                long? lngReMSTPID = null;
                vmAct.Outbound = GetOutboundDetails(o.OutboundID.GetValueOrDefault(), o.ReMSDataID.GetValueOrDefault(), o.JenisKempenID.GetValueOrDefault(), out intCampaignID, out lngReMSTPID);
                o.TPID = lngReMSTPID;

                if (intCampaignID > 0)
                {
                    OutboundCampaignViewModel outCampaign = GetOutboundCampaign(intCampaignID);
                    if (outCampaign != null)
                    {
                        vmAct.ActChannelID = outCampaign.InteractionChannelID;
                        vmAct.Kategori1ID = outCampaign.Kategori1ID;
                        vmAct.Kategori2ID = outCampaign.Kategori2ID;
                        vmAct.Kategori3ID = outCampaign.Kategori3ID;
                    }
                }

            }
            if (o.PrevActivityID > 0)
            {
                if (o.IsResendEmail == true)
                {
                    vmAct = GetById(o.PrevActivityID.GetValueOrDefault(), false, currentUser);
                    //Resend Email already populates TP model and TempPelanggan model

                    if (vmAct.ActAttachmentList != null && vmAct.ActAttachmentList.Count > 0)
                    {
                        foreach (var item in vmAct.ActAttachmentList)
                        {
                            item.TempAttachmentID = item.AttachmentID; //Indicates attachments were taken from previous activity's attachments
                        }
                    }

                    if (vmAct.ActCatatans != null && vmAct.ActCatatans.Count > 0)
                    {
                        int count = -1; 
                        foreach (var item in vmAct.ActCatatans)
                        {
                            item.ActivityID = 0;
                            item.CatatanID = count--;
                            if (item.CatatanAttachmentList != null) { 
                                foreach (var attachment in item.CatatanAttachmentList)
                                {
                                    attachment.TempAttachmentID = attachment.AttachmentID;  //Indicates attachments were taken from previous activity's attachments
                                }
                            }
                        }
                    }
                }
                else
                {
                    vmAct = repo.GetNewActivityByPrevActivity(o.PrevActivityID.GetValueOrDefault());  //From Activity - Orphan/Non-orphan

                    o.TPID = vmAct.TPID;
                    //Tambah Activity , Convert To Activity (additional kategori) at Activity Profile. No get linked CaseID.
                }


                if (o.IsReplyToTPCFF == true)
                {
                    vmAct.ActCFF = repo.GetNewActivityOutBoundCFF(o.PrevActivityID.GetValueOrDefault());
                }

                vmAct.ActivityID = 0;
                vmAct.ActRefNo = null;
                vmAct.ActStatus1ID = null;
                vmAct.ActStatus2ID = null;
                vmAct.ActStatus3ID = null;
                vmAct.ActStatusID = null;
            }

            //At AddActivity hidden Form , to include TPID/TPName etc except Resend Email as it get in function GetByID()
            if (o.TPID > 0)
            {
                vmAct.TPID = o.TPID;

                vmAct.TP = repoTP.GetTPForActivity(vmAct.TPID.GetValueOrDefault());
                // Check if user contains access to view verification tab
                if (tpSvc.VerifyUserBranch(Constant.TableType.Activity, vmAct.TP.VIPCode, vmAct.TP.CWPenaksiranCPID,
                            vmAct.TP.CWPungutanCKHTID, vmAct.TP.CWPenaksiranCKHTID,
                            vmAct.TP.CWPungutanCPID, vmAct.TP.CWGuamanSivilID))
                {
                    vmAct.TP.ViewVerificationTab = true;
                }

                if (vmAct.TP != null)
                {
                    //vmAct.IsOrphanActivity = false;
                    vmAct.TP.TPEjenCukais = repoTP.GetTaxPayerAgent(vmAct.TPID.GetValueOrDefault());

                    vmAct.TP.TPSpouseList = repoTP.GetAllSpouseDetail(vmAct.TPID.GetValueOrDefault());

                    vmAct.TP.TPShareholder = repoTP.GetTaxPayerShareHolderDetail(vmAct.TPID.GetValueOrDefault());

                    vmAct.TP.TPMajikanList = repoTP.GetTPActiveMajikanByID(vmAct.TPID.GetValueOrDefault());
                }

            }
            else
            {
                if (o.IsOrphanTP) //From orphan TP from CASE or Search Taxpayer page
                {
                    vmAct.TPName = o.TPName;
                    vmAct.TPIDType = o.IDType;
                    vmAct.TPJenisPengenalan = o.IDTypeDesc;
                    vmAct.TPIDNumber = o.IDNo;
                    vmAct.TPNoCukai = o.NoCukai;
                    vmAct.IsOrphanActivity = true;
                }
                else if (!string.IsNullOrEmpty(o.IDTypeCode) || !string.IsNullOrEmpty(o.NoCukai))  //From Integration screen pop
                {
                    var idType = AdminService.LookupParams.Where(x => x.LookupCode == "JenisPengenalan" && x.IsActive == true && x.LookupValue == o.IDTypeCode).FirstOrDefault();

                    vmAct.TPIDType = idType != null ? idType.LookupParamID : (int?)null;
                    vmAct.TPIDNumber = (vmAct.TPIDType != null) ? o.IDNo : null;
                    vmAct.TPNoCukai = o.NoCukai;

                    vmAct.TPList = repoTP.SearchTaxPayer(vmAct.TPIDType, vmAct.TPIDNumber, o.FBID, o.TWID, o.NoCukai);
                    if (vmAct.TPList != null)
                    {
                        foreach (TPForActivityViewModel objTP in vmAct.TPList)
                        {
                            // Check if user contains access to view verification tab
                            if (tpSvc.VerifyUserBranch(Constant.TableType.Activity, objTP.VIPCode, objTP.CWPenaksiranCPID,
                                        objTP.CWPungutanCKHTID, objTP.CWPenaksiranCKHTID,
                                        objTP.CWPungutanCPID, objTP.CWGuamanSivilID))
                            {
                                objTP.ViewVerificationTab = true;
                            }
                        }
                    }

                    if (vmAct.TPList != null && vmAct.TPList.Count > 0)
                    {
                        if (vmAct.TPList.Count == 1)
                        {
                            vmAct.TP = vmAct.TPList[0];
                            //vmAct.IsOrphanActivity = false;
                            vmAct.TPList = null;
                        }
                    }
                    else
                    {
                        vmAct.TPList = null;
                    }
                }

            }

            if (vmAct.PelangganTPID > 0 && vmAct.PelangganTPID != vmAct.TPID && vmAct.TempPelanggan == null)
            {
                vmAct.IsPelangganPembayarSama = false;//toDO : pelanggan do test is orpHAN
                vmAct.TempPelanggan = repoTP.GetTPForActivity(vmAct.PelangganTPID.GetValueOrDefault());
                //// Check if user contains access to view verification tab
                //if (tpSvc.VerifyUserBranch(Constant.TableType.Activity, vmAct.TP.VIPCode, vmAct.TP.CWPenaksiranCPID,
                //            vmAct.TP.CWPungutanCKHTID, vmAct.TP.CWPenaksiranCKHTID,
                //            vmAct.TP.CWPungutanCPID, vmAct.TP.CWGuamanSivilID))
                //{
                //    vmAct.TP.ViewVerificationTab = true;
                //}
                if (vmAct.TempPelanggan != null)
                {
                    vmAct.TempPelanggan.TPEjenCukais = repoTP.GetTaxPayerAgent(vmAct.PelangganTPID.GetValueOrDefault());

                    vmAct.TempPelanggan.TPSpouseList = repoTP.GetAllSpouseDetail(vmAct.PelangganTPID.GetValueOrDefault());

                    vmAct.TempPelanggan.TPShareholder = repoTP.GetTaxPayerShareHolderDetail(vmAct.PelangganTPID.GetValueOrDefault());

                    vmAct.TempPelanggan.TPMajikanList = repoTP.GetTPActiveMajikanByID(vmAct.PelangganTPID.GetValueOrDefault());
                }
            }

            if (o.CaseID > 0) //Tambah Activity , Reply To CFF at Case profile
            {
                vmAct.CaseID = o.CaseID;

                vmAct.Case = repoCase.GetCaseForActivity(o.CaseID.GetValueOrDefault());

            }
            if (vmAct.TP != null)
                vmAct.TP.SearchTPProfile = currentUser.RolesObj.Any(x => x.RoleCode == Constant.Authentication.TaxPayer.SearchTPProfile);

            return vmAct;
        }


        public DropdownViewModel GetActivityDDLOptions(List<TindakanSusulanViewModel> lstRoleTindakanSusulan)
        {
            DropdownViewModel ddlVM = new DropdownViewModel();
            ddlVM.LanguageOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "BahasaPehubungan" && x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.LookupParamID, Text = x.ParamDesc, IsDefault = x.IsDefault, Code = x.LookupValue, SeqNo = x.SeqNo }).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.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, Code = x.LookupValue, SeqNo = x.SeqNo }).ToList());
            ddlVM.LokasiOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "Lokasi" && x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.LookupParamID, Text = x.ParamDesc, IsDefault = x.IsDefault, 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.JenisCukaiOptions = Utilities.SortDDL(AdminService.LookupParams.Where(x => x.LookupCode == "Kelas" && x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.LookupParamID, Text = x.ParamDesc, IsDefault = x.IsDefault, SeqNo = x.SeqNo }).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.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.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.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.JenisKempenOptions = Utilities.SortDDL(AdminService.JenisKempens.Where(x => x.JenisKempenKategoriSysID != (int)Constant.KempenKategori.KempenHCL && x.IsActive == true).Select(x => new DropdownDetailViewModel { Value = x.JenisKempenID, Text = x.JenisKempenName }).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.KodSelesaiOptions = AdminService.KodSelesaiCCResult.Where(x => x.IsActive == true && x.IsAgentOption == true).OrderBy(x => x.KodSelesaiDesc).ToList();
            ddlVM.KodSelesaiOptions = AdminService.KodSelesaiCCResult.Where(x => x.IsActive == true).OrderBy(x => x.KodSelesaiDesc).ToList();

            ddlVM.JenisAnsuranOptions = AdminService.JenisKempens.Where(x => x.JenisKempenKategoriSysID == (int)Constant.KempenKategori.KesAnsuran).Select(x => new DropdownDetailViewModel { Value = x.JenisKempenID, Text = x.JenisKempenName }).ToList<DropdownDetailViewModel>(); //exclude KempenHCL
            ddlVM.JenisAnsuranOptions.Add(new DropdownDetailViewModel { Value = Constant.AnsuranStaticOption.SendiriID, Text = Constant.AnsuranStaticOption.Sendiri });
            ddlVM.JenisAnsuranOptions = Utilities.SortDDL(ddlVM.JenisAnsuranOptions);

            ddlVM.ActChannelOptions = AdminService.ActivityChannels; // Order at js
            ddlVM.Status1Options = AdminService.StatusLevels.Where(x => x.IsActive == true).ToList<StatusLevel1>(); // Order at js 
            ddlVM.MainKategoriOptions = AdminService.Kategoris.Where(x => x.IsActive == true).ToList<MainKategori>(); // Order at js 
            //ddlVM.TindakanSusulanOptions = AdminService.TindakanSusulan.ToList<TindakanSusulanViewModel>();// Order at js 
            ddlVM.TindakanSusulanOptions = lstRoleTindakanSusulan; // Order at js 

            ddlVM.RefDocList = AdminService.DocList;
            ddlVM.ParameterSettings = AdminService.ParameterSettings.Where(x => (x.ParameterID == 5 || x.ParameterID == 13 || x.ParameterID == 14 || x.ParameterID == 15 || x.ParameterID == 19 || x.ParameterID == 20 || x.ParameterID == 21)).ToList<ParameterSettings>(); //Email
            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();

            ddlVM.CFFMainKategoriOption = repoAdmin.GetCFFMainKategori().OrderBy(x => x.CFFMainKategoriName).ToList();
            ddlVM.CFFSubKategoriOption = repoAdmin.GetAllCFFSubKategori().OrderBy(x => x.SubKategoriName).ToList();
            ddlVM.FunctionRoleMemberOption = AdminService.FunctionRoleMember.ToList();

            return ddlVM;
        }

        public TemplatesViewModel GetActEmailTemplateDDLOptions(string strUserID, List<TypeViewModel> lstTemplateTypeA, List<TypeViewModel> lstTemplateTypeB)
        {
            TemplatesViewModel vm = new TemplatesViewModel();
            vm.lstEmailTemplateA = repoAdmin.GetAllEmailTemplatesByType(lstTemplateTypeA);
            vm.lstEmailTemplateB = repoAdmin.GetAllEmailTemplatesByType(lstTemplateTypeB);
            vm.lstSignatureTemplate = repoAdmin.GetAllTemplateSignatureByLoginID(strUserID);

            return vm;
        }

        public List<ActCatatanViewModel> GetAllActCatatan(long ActivityID)
        {
            return repo.GetAllActCatatan(ActivityID);
        }

        public ActCatatanViewModel GetActCatatanByID(long lngActCatatanID)
        {
            return repo.GetActCatatanByID(lngActCatatanID);
        }

        public List<ChangeHistoryUpdateViewModel> SaveActivity(ActivityUpdateViewModel model, DateTime dtUpdated, out long lngActivityID,
            out string strActRefNo, out bool blnIsStatusChanged, out byte[] arrChangeStamp, out TaskViewModel modelTask,
            out AuditService.ActionType taskAuditActionType, UserInfoViewModel currentUser = null)
        {
            List<ChangeHistoryUpdateViewModel> lstChgHistory = new List<ChangeHistoryUpdateViewModel>();
            DataTable dTblResult = null;
            blnIsStatusChanged = false;
            bool blnIsPTPDateChanged = false;
            lngActivityID = 0;
            strActRefNo = string.Empty;
            arrChangeStamp = null;

            string strSysEmail = AdminService.ParameterSettings.Where(x => x.ParameterID == 5).FirstOrDefault().ParameterValue;
            string strUserName = Constant.System.Name;
            string strUserID = Constant.System.Name;
            string strUserEmail = strSysEmail;

            if (currentUser != null)
            {
                strUserName = currentUser.DisplayName;
                strUserID = currentUser.LoginID;
                strUserEmail = currentUser.Email;
            }

            var Aliran = AdminService.LookupParams.Where(x => x.LookupCode == "Aliran" && x.IsActive == true && x.LookupParamID == model.Activity.AliranID).FirstOrDefault();

            int intCalledStatus = (int)Constant.OutboundStatus.Called;

            bool blnIsNewOrDraftActivity = (model.Activity.ActivityID == 0 && model.Activity.IsDraft == false) || (model.IsSaveDraft == true);//Is New activity(not for draft) or is it a saved draft activity

            //Outbound (model.Outbound  is for manual insert outbound when Convert to Activity from Outbound details view, model.Activity.OutboundID is only available at new activity from CC integration)
            if ((model.Outbound != null) && (blnIsNewOrDraftActivity == true || model.IsSelfSelectOutbound))
            {
                OutboundUpdateViewModel clsOriOutBound = model.Outbound.OutboundID > 0 ? new OutboundUpdateViewModel { OutboundID = (long)model.Activity.OutboundID } : repoOutbound.GetOutbound(0, model.Outbound.JenisKempenId, model.Outbound.ReMSDataID);

                if (clsOriOutBound != null)
                {
                    model.Activity.OutboundID = clsOriOutBound.OutboundID;
                    repoOutbound.UpdateOutboundStatus((long)model.Activity.OutboundID, intCalledStatus, strUserID, dtUpdated);
                }
                else
                {
                    model.Outbound.StatusID = intCalledStatus;
                    model.Activity.OutboundID = repoOutbound.InsertOutbound(model.Outbound, strUserID, dtUpdated);
                }
                repoOutbound.UpdateOutboundHistoryDetailsByUpdatedDate((int)model.Activity.OutboundID, intCalledStatus, strUserID, dtUpdated);
            }

            //Insert Activity
            if (model.Activity.ActivityID == 0)
            {
                //AssignedOfficer is Current User if not null
                model.Activity.AssignedOfficerName = strUserName;
                model.Activity.AssignedOfficerLogin = strUserID;
                model.Activity.AssignedOfficerEmail = strUserEmail;
                model.Activity.AssignedDateTime = dtUpdated;


                //After AssignedOfficer , set CreatedBy And LastUpdatedBy as System if is Draft
                if (model.Activity.IsDraft == true)
                {
                    strUserName = Constant.System.Name;
                    strUserID = Constant.System.Name;
                    strUserEmail = strSysEmail;
                }

                model.Activity.CreatedDateTime = dtUpdated;
                model.Activity.CreatedBy = strUserID;
                model.Activity.CreatedByName = strUserName;
                model.Activity.LastUpdatedDateTime = dtUpdated;
                model.Activity.LastUpdatedBy = strUserID;
                model.Activity.LastUpdatedByName = strUserName;

                //Special handle for CFF - CreatedDateTime = Kube Created Date
                model.IsCFFDraft = (model.Activity.ActChannelID == (int)Constant.ActChannel.CFF && model.Activity.LastUpdatedBy == Constant.System.Name) ? true : false;
                if (model.IsCFFDraft)
                {
                    model.Activity.CreatedDateTime = model.Activity.ActCFF.CFFReceivedDate; 
                }

                //Check if there is PTP Date
                blnIsPTPDateChanged = model.Activity.PromiseToPayDate.HasValue;

                if (model.Activity.CaseID > 0)
                { //Cater for New activity Link Case
                    CaseViewModel clsCase = repoCase.GetCaseForActivity(model.Activity.CaseID.GetValueOrDefault());
                    if (clsCase.CaseStatusLevel1ID == (int)Constant.StatusLevel1.Selesai)
                    {
                        throw new Exception("The case has been closed and is not allowed to be linked to the new activity.");
                    }
                }

                dTblResult = repo.InsertActivity(model);

            }
            else
            {
                // Retrieve orginal records for audit and change history 
                ActivityViewModel clsOriAct = GetById(model.Activity.ActivityID, true, currentUser);

                //set isDraft to false
                model.Activity.IsDraft = false;

                //Special handle for CFF 
                model.IsCFFDraft = (model.Activity.ActChannelID == (int)Constant.ActChannel.CFF && clsOriAct.LastUpdatedBy == Constant.System.Name) ? true : false;

                if (clsOriAct.IsDraft == true || (model.IsCFFDraft))
                {
                    if (clsOriAct.ActWorkflow == null) //route to agent
                    {
                        model.Activity.AssignedOfficerName = strUserName;
                        model.Activity.AssignedOfficerLogin = strUserID;
                        model.Activity.AssignedOfficerEmail = strUserEmail;
                        model.Activity.AssignedDateTime = dtUpdated;
                    }
                    model.Activity.CreatedBy = strUserID;
                    model.Activity.CreatedByName = strUserName;
                    //model.Activity.CreatedDateTime = dtUpdated;
                }

                model.Activity.LastUpdatedDateTime = dtUpdated;
                model.Activity.LastUpdatedBy = strUserID;
                model.Activity.LastUpdatedByName = strUserName;

                // Check for update conflict
                if (!Utilities.CompareByteArray(model.Activity.ChangeStamp, clsOriAct.ChangeStamp))
                {
                    throw new UpdateConflictException();
                }

                // Check whether previous activity is Closed
                blnIsStatusChanged = !(clsOriAct.ActStatusID == model.Activity.ActStatusID);

                //Check if PTP Date has changed
                blnIsPTPDateChanged = clsOriAct.PromiseToPayDate != model.Activity.PromiseToPayDate;

                dTblResult = repo.UpdateActivity(model);

                //cater for CFFSubKategori change
                if (model.Activity.ActCFF != null)
                {
                    if (clsOriAct.ActCFF.CFFSubKategori != model.Activity.ActCFF.CFFSubKategori && clsOriAct.Kategori1ID != model.Activity.Kategori1ID)
                    {
                        repoCase.UpdateCaseKategoriByCFFSubKategori((int)model.Activity.Kategori1ID, strUserID, strUserName, dtUpdated, (int)model.Activity.CaseID);
                    }
                }

                // Construct oldValue in ChangeHistory
                foreach (ChangeHistoryUpdateViewModel changeHistoryItem in model.ChangeHistory)
                {
                    //Get object original value
                    string strOriValue = string.Empty;
                    string[] arr = changeHistoryItem.FieldName.Split('_');
                    var objOriProperty = Utilities.GetPropertyValue(clsOriAct, arr[0]);

                    //for changes in ng-repeat field
                    if (Utilities.IsList(objOriProperty))
                    {

                        if (objOriProperty.GetType().GetGenericArguments().Single().Name == "ActAdditionalKategoriViewModel")
                        {

                            IList lstOriProperty = (IList)objOriProperty;
                            List<ActAdditionalKategoriViewModel> lstOriAdditionalKategori = lstOriProperty.Cast<ActAdditionalKategoriViewModel>().ToList();

                            ActAdditionalKategoriViewModel itemOriAdditionalKategori = lstOriAdditionalKategori.Where(x => x.ActAddKategoriID.ToString() == arr[1]).FirstOrDefault();
                            if (itemOriAdditionalKategori != null)
                            {
                                string strKategori2Name = string.IsNullOrEmpty(itemOriAdditionalKategori.Kategori2Name) == false ? itemOriAdditionalKategori.Kategori2Name : "-";
                                string strKategori3Name = string.IsNullOrEmpty(itemOriAdditionalKategori.Kategori3Name) == false ? itemOriAdditionalKategori.Kategori3Name : "-";
                                string strDescription = string.IsNullOrEmpty(itemOriAdditionalKategori.Description) == false ? itemOriAdditionalKategori.Description : "-";
                                changeHistoryItem.OldValue = string.Format("Kategori : {0} ;<br/> Sub Kategori : {1} ;<br/> Sub-sub Kategori : {2} ;<br/> Catatan : {3}", itemOriAdditionalKategori.Kategori1Name, strKategori2Name, strKategori3Name, strDescription);
                            }
                            changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue);
                        }

                        if (objOriProperty.GetType().GetGenericArguments().Single().Name == "ActDocReceivedViewModel")
                        {
                            IList lstOriProperty = (IList)objOriProperty;
                            List<ActDocReceivedViewModel> lstOriActDocReceived = lstOriProperty.Cast<ActDocReceivedViewModel>().ToList();
                            string strDesc = string.Empty;

                            foreach (ActDocReceivedViewModel item in lstOriActDocReceived)
                            {
                                if (item.DocListID == Convert.ToInt32(arr[1]) && item.Checked)
                                {
                                    string strTarikh = "-";
                                    if (item.TarikhDokumen.HasValue)
                                        strTarikh = item.TarikhDokumen.Value.ToString("dd MMM yyyy");

                                    string strTahun = "-";
                                    if (item.TahunTaksiran.HasValue)
                                        strTahun = item.TahunTaksiran.Value.ToString();

                                    string strRemarks = string.IsNullOrEmpty(item.Remarks) ? "-" : item.Remarks;

                                    strDesc += "Nama Dokumen: " + item.DocName + ";<br/> Salinan: " + item.Copy + ";<br/> Tarikh Dokumen: " + strTarikh + ";<br/> Tahun Taksiran: " + strTahun + ";<br/> Catatan: " + strRemarks + "<br/><br/>";
                                }

                            }
                            string strKatDocName = lstOriActDocReceived.Where(x => x.DocListID == Convert.ToInt32(arr[1])).Select(x => x.KategoriDocName).FirstOrDefault();
                            changeHistoryItem.OldValue = strKatDocName + "<br/>" + strDesc;
                            changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue);
                        }
                    }
                    //for single field changes
                    else
                    {
                        if (objOriProperty != null)
                        {
                            string strParentPropertyName = objOriProperty.GetType().Name;
                            var objOriParentProperty = objOriProperty;

                            for (int j = 1; j < arr.Length; j++)
                            {
                                objOriProperty = Utilities.GetPropertyValue(objOriProperty, arr[j]);

                            }

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

                                if (strParentPropertyName == "ActVerificationViewModel")
                                {
                                    ActVerificationViewModel oriActVerification = (ActVerificationViewModel)objOriParentProperty;
                                    string strPropertyName = objOriProperty.GetType().Name;
                                    if (strPropertyName == "TPSpouse")
                                    {
                                        TPSpouse oriSpouse = (TPSpouse)objOriProperty;
                                        var spouseIdentityType = AdminService.LookupParams.Where(x => x.LookupParamID == oriSpouse.IdentityTypeID).FirstOrDefault();
                                        string strTemp = string.IsNullOrEmpty(oriSpouse.IdentityNo) == false ? string.Format("({0} : {1})", spouseIdentityType != null ? spouseIdentityType.ParamDesc : "", oriSpouse.IdentityNo) : "";
                                        string strSpouseResult = oriActVerification.PasanganResult != null ? (oriActVerification.PasanganResult.Value ? "Ya" : "Tidak") : "-";
                                        string strSpouseRemarks = string.IsNullOrEmpty(oriActVerification.PasanganRemarks) == false ? oriActVerification.PasanganRemarks.ToString() : "-";
                                        strOriValue = string.Format("{0}{1}<br/> Keputusan Pengesahan : {2};<br/> Catatan Pengesahan : {3};", oriSpouse.SpouseName, strTemp, strSpouseResult, strSpouseRemarks);
                                    }
                                    else if (strPropertyName == "TaxAgent")
                                    {
                                        TaxAgent oriEjenCukai = (TaxAgent)objOriProperty;
                                        string strEjenCukaiResult = oriActVerification.EjenCukaiResult != null ? (oriActVerification.EjenCukaiResult.Value ? "Ya" : "Tidak") : "-";
                                        string strEjenCukaiRemarks = string.IsNullOrEmpty(oriActVerification.EjenCukaiRemarks) == false ? oriActVerification.EjenCukaiRemarks.ToString() : "-";
                                        strOriValue = string.Format("{0}<br/> Keputusan Pengesahan : {1};<br/> Catatan Pengesahan : {2};", oriEjenCukai.EjenCukaiName, strEjenCukaiResult, strEjenCukaiRemarks);
                                    }
                                    else if (strPropertyName == "TPShareholder")
                                    {
                                        TPShareholder oriShareholder = (TPShareholder)objOriProperty;
                                        string strShareholderIdentiti = string.IsNullOrEmpty(oriShareholder.ShareholderIdentityNo) == false ? oriShareholder.ShareholderIdentityNo : "-";
                                        string strShareholderResult = oriActVerification.ShareholderResult != null ? (oriActVerification.ShareholderResult.Value ? "Ya" : "Tidak") : "-";
                                        string strShareholderRemarks = string.IsNullOrEmpty(oriActVerification.ShareholderRemarks) == false ? oriActVerification.ShareholderRemarks.ToString() : "-";
                                        strOriValue = string.Format("{0} (No. Pengenalan : {1})<br/> Keputusan Pengesahan : {2};<br/> Catatan Pengesahan : {3};", oriShareholder.ShareholderName, strShareholderIdentiti, strShareholderResult, strShareholderRemarks);
                                    }
                                    else if (strPropertyName == "TPMajikan")
                                    {
                                        TPMajikan oriMajikan = (TPMajikan)objOriProperty;
                                        //string strNamaMajikan = string.IsNullOrEmpty(oriMajikan.NamaMajikan) == false ? oriMajikan.NamaMajikan : "-";
                                        string strMajikanResult = oriActVerification.NamaMajikanResult != null ? (oriActVerification.NamaMajikanResult.Value ? "Ya" : "Tidak") : "-";
                                        string strMajikanRemarks = string.IsNullOrEmpty(oriActVerification.NamaMajikanRemarks) == false ? oriActVerification.NamaMajikanRemarks.ToString() : "-";
                                        strOriValue = string.Format("{0} <br/> Keputusan Pengesahan : {1};<br/> Catatan Pengesahan : {2};", oriMajikan.NamaMajikan, strMajikanResult, strMajikanRemarks);
                                    }
                                }
                            }
                        }

                        changeHistoryItem.OldValue = strOriValue;

                        changeHistoryItem.IsChanged = !(changeHistoryItem.OldValue == changeHistoryItem.NewValue);
                    }
                }
            }

            if (dTblResult != null && dTblResult.Rows.Count > 0)
            {
                lngActivityID = Convert.ToInt64(dTblResult.Rows[0]["ActivityID"]);
                strActRefNo = dTblResult.Rows[0]["ActRefNo"].ToString(); //TODO put in service
                arrChangeStamp = (byte[])dTblResult.Rows[0]["ChangeStamp"];
            }

            if (model.Activity.ActivityID == 0 && model.Activity.ActCatatans != null)
            { //Cater for resend email for new activity

                foreach (var item in model.Activity.ActCatatans)
                {
                    item.ActivityID = lngActivityID;
                    repo.InsertActCatatan(item, strUserName, strUserID, dtUpdated);
                }
            }

            if (model.Activity.ActivityID > 0 && model.IsSaveDraft == false)
                lstChgHistory = InsertChangeHistory(model.ChangeHistory, strUserName, strUserID, dtUpdated);

            //string strConstDummyTPID= AdminService.ParameterSettings.Where(x => (x.ParameterID == 19)).Select(x=>x.ParameterValue).FirstOrDefault();
            long lngTPID = model.Activity.TPID.GetValueOrDefault();

            if (lngTPID > 0 && model.Activity.TP != null && model.Activity.IsDraft != true)
            {
                //Insert TP change history
                //model.Activity.TP is Original TP info before user changes 

                TPForActivityViewModel clsOriTP = model.Activity.TP;
                //TaxPayerViewModel updatedTP = tpSvc.GetById(model.Activity.TPID.GetValueOrDefault());

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

                AddHistoryByFieldName("IsPelangganPembayarSama", lngTPID, lstTPChgHistory, clsOriTP, "Pelanggan & Pembayar Cukai Orang yang Sama", model.Activity.IsPelangganPembayarSama == true ? "Ya" : "Tidak");
                AddHistoryByFieldName("FBID", lngTPID, lstTPChgHistory, clsOriTP, "ID Facebook", model.Activity.TPFBID);
                AddHistoryByFieldName("FBDisplayName", lngTPID, lstTPChgHistory, clsOriTP, "Nama Facebook", model.Activity.TPFBDisplayName);
                AddHistoryByFieldName("TWID", lngTPID, lstTPChgHistory, clsOriTP, "ID Twitter", model.Activity.TPTWID);
                AddHistoryByFieldName("TWDisplayName", lngTPID, lstTPChgHistory, clsOriTP, "Nama Twitter", model.Activity.TPTWDisplayName);
                if (model.Activity.IsPelangganPembayarSama == true)
                    AddHistoryByFieldName("LanguageName", lngTPID, lstTPChgHistory, clsOriTP, "Bahasa", AdminService.LookupParams.Where(x => x.LookupParamID == model.Activity.LanguageID).Select(x => x.ParamDesc).FirstOrDefault());

                if (Aliran.LookupValue.ToUpper() == Constant.Aliran.Outbound)
                {
                    AddHistoryByFieldName("OutEmailMB", lngTPID, lstTPChgHistory, clsOriTP, "Outbound Emel Kedua/MB", model.Activity.TPEmailMB);
                    AddHistoryByFieldName("OutTelefonBimbit", lngTPID, lstTPChgHistory, clsOriTP, "No. Telefon Bimbit Baru", model.Activity.TPTelefonMB);
                    AddHistoryByFieldName("OutTelefonPejabat", lngTPID, lstTPChgHistory, clsOriTP, "No. Tel Pejabat", model.Activity.TPTelefonPejabat);
                }
                else
                {
                    AddHistoryByFieldName("InEmailMB", lngTPID, lstTPChgHistory, clsOriTP, "Inbound Emel Kedua/MB", model.Activity.TPEmailMB);
                    AddHistoryByFieldName("InTelefonMB", lngTPID, lstTPChgHistory, clsOriTP, "No. Telefon Bimbit/MB", model.Activity.TPTelefonMB);
                }

                if (lstTPChgHistory.Where(x => x.IsChanged).Count() > 0)
                    repoTP.UpdateTPCorrespondence(model, Aliran.LookupValue.ToUpper(), strUserName, strUserID, dtUpdated);

                repoTP.InsertChangeHistory(lstTPChgHistory.Where(x => x.IsChanged).ToList(), strUserName, strUserID, dtUpdated);
            }

            //Update ReMS Details from Activity
            long lngReMSActivityID = 0;
            bool blnIsUpdateReMS = false;
            if (model.OutboundInfo != null && (blnIsNewOrDraftActivity == true || model.IsEditAnsuranActData == true || model.IsSelfSelectOutbound))
            {
                lngReMSActivityID = repoOutbound.GetOutboundReMSActivityIDByDataID(model.Outbound.ReMSDataID, model.OutboundInfo.ReMSTableName);
                blnIsUpdateReMS = (lngActivityID >= lngReMSActivityID);
            }

            if (blnIsUpdateReMS)
            {
                //model.IsAnsuranActDetailsChanged
                var jenisAnsuran = AdminService.JenisKempens.Where(x => x.JenisKempenID == model.Activity.JenisAnsuranID).FirstOrDefault();

                var tindakanSusulan = AdminService.TindakanSusulan.Where(x => x.TindakanSusulanID == model.Activity.TindakanSusulanID).FirstOrDefault();
                var kodSelesai = AdminService.KodSelesai.Where(x => x.KodSelesaiID == model.Activity.KodSelesaiID).FirstOrDefault();
                string strAssignedRemarks = model.IsSelfSelectOutbound ? Constant.ReMSAssignRemarks.AutoPickedUp : Constant.ReMSAssignRemarks.AssignedThroughCC;

                OutboundReMSForActivityViewModel vmReMSDetails = new OutboundReMSForActivityViewModel()
                {
                    ReMSDataID = model.Outbound.ReMSDataID,
                    ACT_BilanganAnsuran = model.Activity.BilanganAnsuran,
                    ACT_MajikanNoCukai = model.Activity.MajikanNoCukai,
                    ACT_MajikanTelefon = model.Activity.MajikanTelefon,
                    ACT_MajikanEmail = model.Activity.MajikanEmail,
                    ACT_TarikhMulaAnsuran = model.Activity.TarikhMulaAnsuran,
                    ACT_JenisAnsuran = jenisAnsuran != null ? jenisAnsuran.JenisKempenName : (model.Activity.JenisAnsuranID == Constant.AnsuranStaticOption.SendiriID ? Constant.AnsuranStaticOption.Sendiri : null),
                    ACT_TarikhJanjiBayar = model.Activity.PromiseToPayDate,
                    ACT_KodSelesaiID = model.Activity.KodSelesaiID,
                    CALL_STATUS = kodSelesai != null ? kodSelesai.KodSelesaiCode : null,
                    CALL_STATUS_DESC = kodSelesai != null ? kodSelesai.KodSelesaiDesc : null,
                    ACT_AnggaranAnsuranPC = model.Activity.AnggaranAnsuranPC,
                    TINDAKAN_SUSULAN = tindakanSusulan != null ? tindakanSusulan.TindakanSusulanCode : null,
                    TINDAKAN_SUSULAN_DESC = tindakanSusulan != null ? tindakanSusulan.TindakanSusulanDesc : null,
                    StatusID = intCalledStatus,
                    AssignedDateTime = model.Activity.AssignedDateTime,
                    AssignedBy = strUserID,
                    AssignedByName = strUserName,
                    AssignedToLogin = model.Activity.AssignedOfficerLogin,
                    AssignedToName = model.Activity.AssignedOfficerName,
                    AssignedToEmail = model.Activity.AssignedOfficerEmail,
                    AssignedRemarks = strAssignedRemarks, //TODO as now not yet have indicator if it is from CC or Manual: Kew - to check InteractionID
                    PKP_RETURN_STATUS = "C",
                    Act_CallDate = model.Activity.CreatedDateTime,
                    //Act_CallAgentUserID = model.Activity.CreatedBy == Constant.System.Name ? (model.Activity.AssignedOfficerLogin.IndexOf('\\') >= 0 ? model.Activity.AssignedOfficerLogin.Split('\\')[1] : model.Activity.AssignedOfficerLogin) : (model.Activity.CreatedBy.IndexOf('\\') >= 0 ? model.Activity.CreatedBy.Split('\\')[1] : model.Activity.CreatedBy),
                    Act_CallAgentUserID = model.Activity.CreatedBy == Constant.System.Name ? model.Activity.AssignedOfficerLogin : model.Activity.CreatedBy,//to include domain to match user name when send back to ReMS
                    Act_NewTelefonMB = model.Activity.TPTelefonMB,
                    IsUpdatedReMS = false,
                    ActivityID = lngActivityID

                };

                repoOutbound.UpdateOutboundReMSActDetails(vmReMSDetails, model.OutboundInfo.ReMSTableName, strUserName, strUserID, dtUpdated);

            }

            //SaveTaskForPromiseToPay
            modelTask = null;
            taskAuditActionType = new AuditService.ActionType();
            if (model.Activity.IsDraft == false && blnIsPTPDateChanged == true)
            {
                DateTime? dtPromiseToPay = model.Activity.PromiseToPayDate;
                TaskViewModel oriTask = model.Activity.ActivityID != 0 ? repoTask.GetPTPTaskByActivityID(lngActivityID) : null;
                //List<ChangeHistoryUpdateViewModel> lstTaskChgHistory = new List<ChangeHistoryUpdateViewModel>();
                //string strTaskRefNo = "";
                long lngTaskID = oriTask != null ? oriTask.TaskID : 0;
                taskAuditActionType = oriTask != null ? AuditService.ActionType.Update : AuditService.ActionType.Add;

                //Outbound and Update Task
                //TODO Activity Assigned Person is same as the Task PTP??

                string strPTPDesc = Resources.Messages.PromiseToPayMessage;
                if (model.Activity.TP != null)
                {
                    strPTPDesc = String.Format(strPTPDesc, model.Activity.TPNoCukai);
                }
                else
                    strPTPDesc = String.Format(strPTPDesc, model.Activity.TPNoCukai);

                int intBelumSelesaiActStatusID = AdminService.LookupParams.Where(x => x.LookupCode == "ActivityStatus" && x.IsActive == true && x.LookupValue == ((int)Constant.StatusLevel1.BelumSelesai).ToString()).FirstOrDefault().LookupParamID;

                modelTask = new TaskViewModel()
                {
                    TaskID = lngTaskID,
                    ActivityID = lngActivityID,
                    AssignToLogin = model.Activity.AssignedOfficerLogin,
                    AssignToName = model.Activity.AssignedOfficerName,
                    AssignToEmail = model.Activity.AssignedOfficerEmail,
                    //StartDate = dtPromiseToPay.HasValue? dtPromiseToPay.Value.Date.Add(DateTime.Now.TimeOfDay) : (DateTime?)null,
                    //DueDate = dtPromiseToPay,
                    StartDate = dtPromiseToPay.HasValue ? dtPromiseToPay.Value.Date : (DateTime?)null, //DateOnly instead of DateTime
                    DueDate = dtPromiseToPay.HasValue ? dtPromiseToPay.Value.Date : (DateTime?)null,
                    Title = Resources.Messages.PromiseToPayTitle,
                    Description = strPTPDesc,
                    TaskStatusID = intBelumSelesaiActStatusID,
                    IsPTP = true
                };

                bool blnIsChanged = oriTask != null ? model.Activity.ActStatusID != oriTask.TaskStatusID || dtPromiseToPay != oriTask.DueDate : false;

                //Update or Insert
                if ((blnIsChanged || lngTaskID == 0) && dtPromiseToPay != null)
                {
                    DataTable dTblResultTask = repoTask.UpdateTask(modelTask, strUserID, dtUpdated, strUserName, strUserEmail);

                    if (dTblResultTask != null && dTblResultTask.Rows.Count > 0)
                    {
                        modelTask.TaskID = Convert.ToInt64(dTblResultTask.Rows[0]["TaskID"]);
                        modelTask.TaskRefNo = dTblResultTask.Rows[0]["TaskRefNo"].ToString();
                    }

                }
                else if (dtPromiseToPay == null && lngTaskID > 0) //Delete
                {
                    repoTask.DeleteTask(lngTaskID);
                    taskAuditActionType = AuditService.ActionType.Delete;
                }
            }


            //Cancel voice queue from Contact centre
            if (model.Outbound != null && model.OutboundInfo != null && model.OutboundInfo.IsCancelVoiceQueue)
            {
                OutboundCancelVoiceQueueViewModel cancelQueueModel = new OutboundCancelVoiceQueueViewModel()
                {
                    ActivityID = lngActivityID,
                    GSW_PHONE = model.OutboundInfo.OutboundPhone,
                    GSW_CAMPAIGN_NAME = model.OutboundInfo.CCCampaignName,
                    GSW_CALLING_LIST = model.OutboundInfo.CCCampaignName + "_CallingList",
                    LastUpdatedBy = strUserID,
                    OutboundID = model.Activity.OutboundID != null ? model.Activity.OutboundID : model.Outbound.OutboundID,
                    JenisKempenID = model.Outbound.JenisKempenId,
                    ReMSDataID = model.Outbound.ReMSDataID,
                    ReMSTableName = model.OutboundInfo.ReMSTableName
                };

                repo.InsertOutboundCancelVoiceQueue(cancelQueueModel);
            }
            return lstChgHistory;
        }

        public void InsertCFFQueue(CRMUpdateFieldViewModel model, string strUserID)
        {
            repo.InsertCFFQueue(model, strUserID);
        }

        public void InsertSlipKedatanganAction(PrintActionViewModel model)
        {
            repo.InsertSlipKedatanganAction(model);
        }

        public bool LinkUnlinkActivity(EntityUpdateViewModel model, string strUserName, string strUserID, DateTime dtUpdated, out ActivityViewModel clsNewAct, out List<ChangeHistoryUpdateViewModel> lstChgHistory, out byte[] ChangeStamp, bool isDeleteCase = false)
        {
            clsNewAct = null;
            lstChgHistory = new List<ChangeHistoryUpdateViewModel>();
            ChangeStamp = null;
            ActivityViewModel clsOriAct = null;
            long lngActivityID = model.ActivityID.GetValueOrDefault();
            //Get Current Activity Data
            clsOriAct = repo.GetActivity(lngActivityID);

            if (isDeleteCase == false)
            {  //if call from Delete Case Api , no need to check Activity ChangeStamp
               //byte[] oriChangeStamp = GetChangeStampbyID(lngActivityID());

                if (!Utilities.CompareByteArray(model.ChangeStamp, clsOriAct.ChangeStamp))
                {
                    throw new UpdateConflictException();
                }
            }

            bool blnIsSuccess = repo.LinkUnlinkActivity(lngActivityID, model.CaseID.GetValueOrDefault(), model.IsLinkCase, strUserName, strUserID, dtUpdated, out clsNewAct, isDeleteCase);

            if (blnIsSuccess == true)
            {
                ChangeStamp = clsNewAct.ChangeStamp;

                //if (model.IsLinkCase == true)
                //{
                //    //Construct Change History   
                //    AddHistoryByFieldName("Kategori1Name", lngActivityID, lstChgHistory, clsOriAct, "Kategori", clsNewAct.Kategori1Name);
                //    AddHistoryByFieldName("Kategori2Name", lngActivityID, lstChgHistory, clsOriAct, "Sub Kategori", clsNewAct.Kategori2Name);
                //    AddHistoryByFieldName("Kategori3Name", lngActivityID, lstChgHistory, clsOriAct, "Sub-sub Kategori", clsNewAct.Kategori2Name);
                //    AddHistoryByFieldName("ActStatusLevel1Name", lngActivityID, lstChgHistory, clsOriAct, "Status Aktiviti Level 1", clsNewAct.ActStatusLevel1Name);
                //    AddHistoryByFieldName("ActStatusLevel2Name", lngActivityID, lstChgHistory, clsOriAct, "Status Aktiviti Level 2", clsNewAct.ActStatusLevel2Name);
                //    AddHistoryByFieldName("ActStatusLevel3Name", lngActivityID, lstChgHistory, clsOriAct, "Status Aktiviti Level 3", clsNewAct.ActStatusLevel3Name);
                //    AddHistoryByFieldName("KodSelesaiDesc", lngActivityID, lstChgHistory, clsOriAct, "Kod Selesai", clsNewAct.KodSelesaiDesc);
                //    AddHistoryByFieldName("NoBaucer", lngActivityID, lstChgHistory, clsOriAct, "No Baucer", clsNewAct.NoBaucer);
                //    AddHistoryByFieldName("TindakanSusulanDesc", lngActivityID, lstChgHistory, clsOriAct, "Tindakan Susulan", clsNewAct.TindakanSusulanDesc);
                //    AddHistoryByFieldName("NilaiKes", lngActivityID, lstChgHistory, clsOriAct, "Nilai Kes", clsNewAct.NilaiKes.ToString());
                //    AddHistoryByFieldName("StatusBayaranS104S22", lngActivityID, lstChgHistory, clsOriAct, "Status Bayaran S104/S22", clsNewAct.StatusBayaranS104S22);
                //    AddHistoryByFieldName("Tahap", lngActivityID, lstChgHistory, clsOriAct, "Tahap", clsNewAct.Tahap);
                //    AddHistoryByFieldName("JenisKempenName", lngActivityID, lstChgHistory, clsOriAct, "Jenis Kempen", clsNewAct.JenisKempenName);
                //}
            }

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

            return blnIsSuccess;
            //List<ChangeHistoryUpdateViewModel> lst = InsertChangeHistory(model.ChangeHistory, strUserName, strUserID, dtUpdated); 
        }
        public byte[] ReopenActivity(EntityUpdateViewModel model, string strUserName, string strUserID, DateTime dtUpdated, out int intActStatusID)
        {
            List<ChangeHistoryUpdateViewModel> lstChgHistory = new List<ChangeHistoryUpdateViewModel>();
            long lngActivityID = model.ActivityID.GetValueOrDefault();
            ActivityViewModel clsOriAct = repo.GetActivity(lngActivityID);
            long lngCaseID = clsOriAct.CaseID.GetValueOrDefault();

            if (!Utilities.CompareByteArray(model.ChangeStamp, clsOriAct.ChangeStamp))
            {
                throw new UpdateConflictException();
            }

            var status1 = AdminService.StatusLevels.Where(x => x.IsActive == true && x.StatusLevel1ID == (int)Constant.StatusLevel1.BelumSelesai).FirstOrDefault();
            var status2 = status1.StatusLevel2.Where(x => x.IsActive == true && x.StatusLevel2ID == (int)Constant.StatusLevel2.Normal).FirstOrDefault();
            var status = AdminService.LookupParams.Where(x => x.LookupCode == "ActivityStatus" && x.IsActive == true && x.LookupValue == ((int)Constant.StatusLevel1.BelumSelesai).ToString()).FirstOrDefault();
            intActStatusID = status.LookupParamID;

            byte[] changeStamp = repo.UpdateActivityStatus(lngActivityID, intActStatusID, (int)Constant.StatusLevel1.BelumSelesai, (int)Constant.StatusLevel2.Normal, null, strUserName, strUserID, dtUpdated);

            if (lngCaseID == 0)
            {
                AddHistoryByFieldName("ActStatusLevel1Name", lngActivityID, lstChgHistory, clsOriAct, "Status Aktiviti Level 1", status1.StatusLevel1Name);
                AddHistoryByFieldName("ActStatusLevel2Name", lngActivityID, lstChgHistory, clsOriAct, "Status Aktiviti Level 2", status2.StatusLevel2Name);
                AddHistoryByFieldName("ActStatusLevel3Name", lngActivityID, lstChgHistory, clsOriAct, "Status Aktiviti Level 3", null);
            }

            AddHistoryByFieldName("ActStatus", lngActivityID, lstChgHistory, clsOriAct, "Status Aktiviti", status.ParamDesc);
            InsertChangeHistory(lstChgHistory, strUserName, strUserID, dtUpdated);

            return changeStamp;
            //List<ChangeHistoryUpdateViewModel> lst = InsertChangeHistory(model.ChangeHistory, strUserName, strUserID, dtUpdated); 
        }

        public byte[] CloseActivityAndLinkedInboundActivities(EntityUpdateViewModel model, string strUserName, string strUserID, DateTime dtUpdated)
        {
            List<ChangeHistoryUpdateViewModel> lstChgHistory = new List<ChangeHistoryUpdateViewModel>();
            long lngActivityID = model.ActivityID.GetValueOrDefault();
            ActivityViewModel clsOriAct = repo.GetActivity(lngActivityID);
            long lngCaseID = clsOriAct.CaseID.GetValueOrDefault();

            if (!Utilities.CompareByteArray(model.ChangeStamp, clsOriAct.ChangeStamp))
            {
                throw new UpdateConflictException();
            }

            int intAliranID = AdminService.LookupParams.Where(x => x.LookupCode == "Aliran" && x.IsActive == true && x.LookupValue == Constant.Aliran.Inbound).Select(x => x.LookupParamID).FirstOrDefault();
            var status1 = AdminService.StatusLevels.Where(x => x.IsActive == true && x.StatusLevel1ID == (int)Constant.StatusLevel1.Selesai).FirstOrDefault();
            var status2 = status1.StatusLevel2.Where(x => x.IsActive == true && x.StatusLevel2ID == (int)Constant.StatusLevel2.Sepenuhnya_Muktamad).FirstOrDefault();
            var status = AdminService.LookupParams.Where(x => x.LookupCode == "ActivityStatus" && x.IsActive == true && x.LookupValue == ((int)Constant.StatusLevel1.Selesai).ToString()).FirstOrDefault();

            List<ActivityViewModel> lstOriAct = null;
            List<EntityIDViewModel> lstOpenActivityID = null;
            if (lngCaseID > 0)
            {
                lstOriAct = repo.GetAllOpenActivityByCaseID(lngCaseID, intAliranID, (int)model.ActChannelID);

                if (lstOriAct != null)
                {
                    lstOpenActivityID = lstOriAct.Select(x => new EntityIDViewModel { ID = x.ActivityID }).ToList();
                    //dtblOpenActivityID = Common.Extensions.ToDataTable<EntityIDViewModel>(lstOriAct.Select(x => new EntityIDViewModel{ ID = x.ActivityID }).ToList());
                }
            }

            byte[] changeStamp = repo.UpdateActivityStatus(lngActivityID, status.LookupParamID, (int)Constant.StatusLevel1.Selesai, (int)Constant.StatusLevel2.Sepenuhnya_Muktamad, null, strUserName, strUserID, dtUpdated, lstOpenActivityID);

            if (lstOriAct == null)
                lstOriAct = new List<ActivityViewModel>();

            lstOriAct.Add(clsOriAct);
            foreach (var item in lstOriAct)
            {
                if (lngCaseID == 0)
                {
                    AddHistoryByFieldName("ActStatusLevel1Name", item.ActivityID, lstChgHistory, item, "Status Aktiviti Level 1", status1.StatusLevel1Name);
                    AddHistoryByFieldName("ActStatusLevel2Name", item.ActivityID, lstChgHistory, item, "Status Aktiviti Level 2", status2.StatusLevel2Name);
                    AddHistoryByFieldName("ActStatusLevel3Name", item.ActivityID, lstChgHistory, item, "Status Aktiviti Level 3", null);
                }
                AddHistoryByFieldName("ActStatus", item.ActivityID, lstChgHistory, item, "Status Aktiviti", status.ParamDesc);
            }

            InsertChangeHistory(lstChgHistory, strUserName, strUserID, dtUpdated);

            return changeStamp;
        }

        public bool DeleteActivity(EntityUpdateViewModel model, string strUserName, string strUserID, DateTime dtUpdated)
        {

            byte[] oriChangeStamp = GetChangeStampbyID(model.ActivityID.GetValueOrDefault());
            bool blnIsSuccess = false;
            List<ChangeHistoryUpdateViewModel> lst = new List<ChangeHistoryUpdateViewModel>();

            if (!Utilities.CompareByteArray(model.ChangeStamp, oriChangeStamp))
            {
                throw new UpdateConflictException();
            }

            blnIsSuccess = repo.DeleteActivity(model.ActivityID.GetValueOrDefault(), strUserName, strUserID, dtUpdated);
            //if (blnIsSuccess) { 
            //  lst = InsertChangeHistory(model.ChangeHistory, strUserName, strUserID, dtUpdated);
            //}
            return blnIsSuccess;
        }

        public long InsertActCatatan(ActCatatanViewModel model, string strUserName, string strUserID, DateTime dtUpdated)
        {
            long lngActCatatanID = repo.InsertActCatatan(model, strUserName, strUserID, dtUpdated);

            return lngActCatatanID;
        }

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

            //Get ChangeHistoryUpdateViewModel
            ChangeHistoryUpdateViewModel changeHistoryItem = new ChangeHistoryUpdateViewModel();
            changeHistoryItem.ID = model.ActivityID; //store CaseID instead of CatatanID
            changeHistoryItem.FieldName = "Act_Catatan";
            changeHistoryItem.DisplayName = "Aktiviti (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.DeleteActCatatan(model.CatatanID);

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

            return lstChangeHist;
        }

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

            // Retrieve orginal records for audit and change history 
            ActCatatanViewModel clsOriCatatan = GetActCatatanByID(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.ActivityID; //store CaseID instead of CatatanID
            changeHistoryItem.FieldName = "Act_Catatan";
            changeHistoryItem.DisplayName = "Aktiviti (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.UpdateActCatatan(model, strUserName, strUserID, dtUpdated);

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

            return lstChangeHist;
        }

        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 void InsertActSession(List<ActSession> lstActSession)
        {
            repo.InsertActSession(lstActSession);
        }

        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();
            if (lst.Count > 0)
                intReturnValue = repo.InsertChangeHistory(lst, strUserName, strUserID, dtUpdated);

            return lst;
        }

        public List<ActivityListViewModel> GetActivityListByID(ActivityListPagedListViewModel paging, out int intCount)
        {
            intCount = 0;

            DataSet ds = repo.GetActivityListByID(paging.SortExpression, paging.PageIndex, paging.Length,
                                            paging.TPID, paging.CaseID, paging.ReMSDataID, paging.JenisKempenID, paging.EmailDataID, paging.ActChannelID, paging.AliranID, paging.ActStatusID, paging.Kategori1ID, paging.Kategori2ID, paging.Kategori3ID, paging.ActivityNo);

            List<ActivityListViewModel> lstActListVM = new List<ActivityListViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstActListVM = repo.DataTableToList<ActivityListViewModel>(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 lstActListVM;

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

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

        public List<PendingActivityPagedListViewModel> GetPendingActivityByName(string CreatedBy, PendingActivityPagedListViewModel paging, out int intCount)
        {
            intCount = 0;

            DataSet ds = repo.GetPendingActivityByName(CreatedBy, paging);

            List<PendingActivityPagedListViewModel> lstDashboardPendingActivity = new List<PendingActivityPagedListViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstDashboardPendingActivity = repo.DataTableToList<PendingActivityPagedListViewModel>(ds.Tables[0]).ToList();

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

            return lstDashboardPendingActivity;
        }

        public List<PendingActivityPagedListViewModel> GetPendingActByManagerPool(PendingActivityPagedListViewModel paging, string strLoginID, out int intCount)
        {
            intCount = 0;
            DataSet ds = repo.GetPendingActByManagerPool(paging, strLoginID);

            List<PendingActivityPagedListViewModel> lstDashboardPendingActivityByManagerPool = new List<PendingActivityPagedListViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstDashboardPendingActivityByManagerPool = repo.DataTableToList<PendingActivityPagedListViewModel>(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 lstDashboardPendingActivityByManagerPool;
        }


        public List<PendingActivityPagedListViewModel> GetAssignedInboundCFFDraftActivity(string strAssignedToLogin, PendingActivityPagedListViewModel paging, out int intCount)
        {
            intCount = 0;

            DataSet ds = repo.GetAssignedInboundCFFDraftActivity(strAssignedToLogin, paging);

            List<PendingActivityPagedListViewModel> lstInboundCFFDraftActivity = new List<PendingActivityPagedListViewModel>();

            if (ds != null && ds.Tables.Count > 0)
            {
                if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
                    lstInboundCFFDraftActivity = repo.DataTableToList<PendingActivityPagedListViewModel>(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 lstInboundCFFDraftActivity;
        }

        public DataTable GetCFFSummaryAttachment(long id)
        {
            return repo.GetCFFSummaryAttachment(id);
        }

        private void AddHistoryByFieldName(string strFieldName, long lngID, List<ChangeHistoryUpdateViewModel> lstChgHistory, dynamic clsOri, string strDisplayName, string strNewValue)
        {
            strNewValue = strNewValue == null ? "" : strNewValue;
            var objOldValue = Utilities.GetPropertyValue(clsOri, strFieldName);
            string strOldValue = "";
            if (objOldValue != null)
            {
                if (objOldValue.GetType().Name == "Boolean")
                {

                    bool flag = (bool)objOldValue;
                    if (flag == true)
                        strOldValue = "Ya";
                    else
                        strOldValue = "Tidak";
                }
                else if (strFieldName == "NilaiKes" || strFieldName == "AnggaranAnsuranPC")
                {

                    strOldValue = string.IsNullOrEmpty(strNewValue) ? strNewValue : String.Format("{0:N}", Convert.ToDouble(strNewValue));
                }
                else
                {
                    strOldValue = objOldValue.ToString();
                }
            }
            ChangeHistoryUpdateViewModel changeHistVM = BindChangeHistVM(lngID, strFieldName, strDisplayName, strOldValue, strNewValue);

            lstChgHistory.Add(changeHistVM);
        }

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

            return changeHistVM;
        }

        public OutboundCampaignViewModel GetOutboundCampaign(int intCampaignID)
        {
            OutboundCampaignViewModel vm = repoOutbound.GetOutboundCampaign(0, intCampaignID);

            return vm;

        }

        public dynamic GetOutboundDetails(long lngOutboundID, long lngDataID, int JenisKempenID)
        {
            JenisKempenDetailViewModel objJenisKempenDetails = repoOutbound.GetJenisKempenDetailByID(JenisKempenID, lngOutboundID);

            if (objJenisKempenDetails == null)
            {
                throw new NotFoundException("Jenis kempen kategori not found!");
            }

            lngDataID = lngDataID > 0 ? lngDataID : (long)objJenisKempenDetails?.ReMSDataID;

            dynamic obj = null;
            switch (objJenisKempenDetails.JenisKempenKategoriSysID)
            {
                case ((int)Constant.KempenKategori.KesTunggakan):
                    obj = repoOutbound.GetOutboundDetailsTunggakan(objJenisKempenDetails.ReMSTableName, objJenisKempenDetails.JenisKempenID, lngDataID);
                    break;
                case ((int)Constant.KempenKategori.KesAnsuran):
                    obj = repoOutbound.GetOutboundDetailsAnsuran(objJenisKempenDetails.ReMSTableName, objJenisKempenDetails.JenisKempenID, lngDataID);
                    break;
                case ((int)Constant.KempenKategori.KesCTL):
                    obj = repoOutbound.GetOutboundDetailsCTL(objJenisKempenDetails.ReMSTableName, objJenisKempenDetails.JenisKempenID, lngDataID);
                    break;
            }

            if (obj == null)
            {
                throw new NotFoundException("Outbound details not found!");
            }

            obj.JenisKempenDetails = objJenisKempenDetails;

            return obj;
        }

        public dynamic GetOutboundDetails(long lngOutboundID, long lngDataID, int JenisKempenID, out int intCampaignID, out long? lngTPID)
        {
            JenisKempenDetailViewModel objJenisKempenDetails = repoOutbound.GetJenisKempenDetailByID(JenisKempenID, lngOutboundID);

            if (objJenisKempenDetails == null)
            {
                throw new NotFoundException("Jenis kempen kategori not found!");
            }

            lngDataID = objJenisKempenDetails.ReMSDataID > 0 ? (long)objJenisKempenDetails.ReMSDataID : lngDataID;

            dynamic obj = null;
            intCampaignID = 0;
            lngTPID = null;
            switch (objJenisKempenDetails.JenisKempenKategoriSysID)
            {
                case ((int)Constant.KempenKategori.KesTunggakan):
                    var outTunggakan = repoOutbound.GetOutboundDetailsTunggakan(objJenisKempenDetails.ReMSTableName, objJenisKempenDetails.JenisKempenID, lngDataID);
                    if (outTunggakan != null)
                    {
                        intCampaignID = outTunggakan.CampaignID;
                        lngTPID = outTunggakan.TPID;
                    }
                    obj = outTunggakan;
                    break;
                case ((int)Constant.KempenKategori.KesAnsuran):
                    var outAnsuran = repoOutbound.GetOutboundDetailsAnsuran(objJenisKempenDetails.ReMSTableName, objJenisKempenDetails.JenisKempenID, lngDataID);
                    if (outAnsuran != null)
                    {
                        intCampaignID = outAnsuran.CampaignID;
                        lngTPID = outAnsuran.TPID;
                    }
                    obj = outAnsuran;
                    break;
                case ((int)Constant.KempenKategori.KesCTL):
                    var outCTL = repoOutbound.GetOutboundDetailsCTL(objJenisKempenDetails.ReMSTableName, objJenisKempenDetails.JenisKempenID, lngDataID);
                    if (outCTL != null)
                    {
                        intCampaignID = outCTL.CampaignID;
                        lngTPID = outCTL.TPID;
                    }
                    obj = outCTL;
                    break;
            }

            if (obj == null)
            {
                throw new NotFoundException("Outbound details not found!");
            }

            obj.JenisKempenDetails = objJenisKempenDetails;
            return obj;
        }

        public HCLEmailBlastDetailsViewModel GetEmailBlastDetails(long lngEmailBlastID)
        {
            JenisKempenDetailViewModel objJenisKempenDetails = repoOutbound.GetJenisKempenDetailByID(0, 0, lngEmailBlastID);

            if (objJenisKempenDetails == null)
            {
                throw new NotFoundException("Jenis kempen kategori not found!");
            }

            HCLEmailBlastDetailsViewModel obj = null;
            obj = repoOutbound.GetEmailBlastDetails(objJenisKempenDetails.JenisKempenID, (long)objJenisKempenDetails.EmailDataID);

            if (obj == null)
            {
                throw new NotFoundException("Email Blast details not found!");
            }

            return obj;
        }

        public string PrintSlipKedatangan(long lngActID, string strLoginName)
        {
            EmailService svcEmail = new EmailService();
            return svcEmail.GetHTMLParsedContent((int)Constant.EmailTemplate.PrintSlipKedatangan, lngActID, "", "", "", strLoginName);
        }

        public int GetOutboundCountByTP(CountOutboundByTPViewModel model)
        {
            return repoOutbound.GetOutboundCountByTP(model);
        }

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

        public bool RouteToAgent(long lngActID, string strUserID)
        {
            bool blnIsSuccess = false;
            //Get data before route
            RouteToAgentViewModel model = repo.GetRouteToAgentData(lngActID);

            if (model != null && model.SkillSet != null)
            {
                RouteToAgentQueueViewModel vm = new RouteToAgentQueueViewModel();
                vm.ActivityID = lngActID;
                repo.InsertRouteToAgentQueue(vm, strUserID);
                blnIsSuccess = true;
            }
            else
            {
                throw new RouteToAgentException();
            }

            return blnIsSuccess;
        }

        //public RouteToAgentReturnViewModel RouteToAgent(long lngActID, string strUserID)
        //{
        //    RouteToAgentReturnViewModel returnVM = new RouteToAgentReturnViewModel();
        //    ErrorService svcErr = new ErrorService();

        //    try
        //    {
        //        //Get data before route
        //        RouteToAgentViewModel model = repo.GetRouteToAgentData(lngActID);

        //        if (model != null && model.SkillSet != null)
        //        {
        //            string result = "";
        //            string URL = Utilities.GetAppSetting("RouteToAgentFunc"); //"http://172.20.229.55:8090/genesys/2/email/webemail";
        //            var formContent = new FormUrlEncodedContent(new[]
        //            {
        //            new KeyValuePair<string, string>("firstName", model.FirstName),
        //            new KeyValuePair<string, string>("lastName", model.LastName),
        //            new KeyValuePair<string, string>("fromAddress", model.FromAddress),
        //            new KeyValuePair<string, string>("subject", model.Subject),
        //            new KeyValuePair<string, string>("text", model.Text),
        //            //new KeyValuePair<string, string>("emailAddress", model.FromAddress),
        //            new KeyValuePair<string, string>("userData", "RoutingCategory=" + model.SkillSet),
        //            new KeyValuePair<string, string>("userData", "main_category=" + model.Category),
        //            new KeyValuePair<string, string>("userData", "subcategory=" + model.SubCategory),
        //            new KeyValuePair<string, string>("userData", "idtype=" + model.IDType.ToString()),
        //            new KeyValuePair<string, string>("userData", "idnumber=" + model.IDNo),
        //            new KeyValuePair<string, string>("userData", "phone=" + model.Phone),
        //            new KeyValuePair<string, string>("userData", "activityid=" + model.ActivityID.ToString())
        //        });

        //            var myHttpClient = new HttpClient();
        //            myHttpClient.BaseAddress = new Uri(URL);
        //            // Add an Accept header for JSON format.
        //            myHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        //            var response = myHttpClient.PostAsync(URL, formContent).Result;

        //            if (response.IsSuccessStatusCode)
        //            {
        //                result = response.Content.ReadAsStringAsync().Result;
        //                returnVM = JsonConvert.DeserializeObject<RouteToAgentReturnViewModel>(result);

        //                if (returnVM.StatusCode == 0) //success - Update InteractionID
        //                {
        //                    repo.UpdateInteractionID(returnVM.InteractionID, lngActID);
        //                }
        //                else //error - Insert error log
        //                {
        //                    svcErr.LogError("Genesys - Route To Agent failed. Returned Status Code: 1 - Activity ID: " + lngActID, strUserID);
        //                }
        //            }
        //            else //error - Insert error log
        //            {
        //                svcErr.LogError(string.Format("Genesys - Route To Agent failed for Activity ID: {0} with error: {1}", lngActID, response.ReasonPhrase), strUserID);
        //            }
        //            myHttpClient.Dispose();
        //        }
        //        else
        //        {
        //            throw new Exception("This activity is not allowed to route to agent.");
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        svcErr.LogError(ex.ToString(), strUserID);
        //    }
        //    return returnVM;
        //}
    }
}
