<!--- Dashboard Display Functions - Shared functions for dashboard display --->
<!--- Agency login session (handles both IsAgencyLogin and legacy iSAgencyLogin casing) --->
<cffunction name="isAgencyLoginSession" output="false" returntype="boolean">
    <cfreturn (
        (isDefined("session.IsAgencyLogin") AND session.IsAgencyLogin EQ 1)
        OR (isDefined("session.iSAgencyLogin") AND session.iSAgencyLogin EQ 1)
        OR (isDefined("session.isagencylogin") AND session.isagencylogin EQ 1)
    )>
</cffunction>

<!--- Expiring Visits dashboard tile and report: agency login, or Project Manager at Evergreen (1195) --->
<cffunction name="canViewExpiringVisitsDashboard" output="false" returntype="boolean">
    <cfif isAgencyLoginSession()>
        <cfreturn true>
    </cfif>
    <cfset var agencyId = 0>
    <cfif isDefined("session.agencyid") AND isNumeric(session.agencyid)>
        <cfset agencyId = val(session.agencyid)>
    <cfelseif isDefined("session.AgencyId") AND isNumeric(session.AgencyId)>
        <cfset agencyId = val(session.AgencyId)>
    <cfelseif isDefined("session.AgencyID") AND isNumeric(session.AgencyID)>
        <cfset agencyId = val(session.AgencyID)>
    </cfif>
    <cfif agencyId EQ 1195 AND isDefined("session.eaRole") AND session.eaRole CONTAINS "Project Manager">
        <cfreturn true>
    </cfif>
    <cfreturn false>
</cffunction>

<!--- Function to determine which role field to check based on dashboard item description --->
<cffunction name="getRoleFieldForDescription" output="false" returntype="string">
    <cfargument name="description" type="string" required="true">
    
    <!--- Normalize description for matching --->
    <cfset var descLower = LCase(Trim(arguments.description))>
    
    <!--- Map descriptions to role fields based on the dashboard structure --->
    <!--- Eligibility items --->
    <cfif descLower CONTAINS "eligibility" AND (descLower CONTAINS "new" OR descLower CONTAINS "expiring" OR descLower CONTAINS "missing")>
        <cfreturn "r_Elig">
    </cfif>
    
    <!--- Pending Admissions --->
    <cfif descLower CONTAINS "pending admissions">
        <cfreturn "r_Admit_Pend">
    </cfif>
    
    <!--- Careplan QA items --->
    <cfif descLower CONTAINS "careplan" OR descLower CONTAINS "coding updates" OR descLower CONTAINS "medication updates" OR descLower CONTAINS "procedures need" OR descLower CONTAINS "orphan symptoms" OR descLower CONTAINS "med reconciliation" OR descLower CONTAINS "disabled goals" OR descLower CONTAINS "incomplete assessment" OR descLower CONTAINS "vbp inconsistencies">
        <cfreturn "r_CP_QA">
    </cfif>
    
    <!--- Progress Note QA --->
    <cfif (descLower CONTAINS "pn" AND descLower CONTAINS "review") OR (descLower CONTAINS "pn" AND descLower CONTAINS "approve")>
        <cfreturn "r_PN_QA">
    </cfif>
    
    <!--- Authorizations --->
    <cfif descLower CONTAINS "authorization" AND (descLower CONTAINS "expiring" OR descLower CONTAINS "missing")>
        <cfreturn "r_Auth">
    </cfif>
    
    <!--- Scheduled Assessments / OASIS / Evaluations --->
    <cfif descLower CONTAINS "oasis" OR (descLower CONTAINS "evaluation" AND descLower CONTAINS "expiring") OR descLower CONTAINS "scheduled assessment">
        <cfreturn "r_Sched_Assmt">
    </cfif>
    
    <!--- Assessment QA items --->
    <cfif (descLower CONTAINS "assessment" AND descLower CONTAINS "qa") OR descLower CONTAINS "incomplete assessment">
        <cfreturn "r_Assmt_QA">
    </cfif>
    
    <!--- Careplan Tracker items --->
    <cfif descLower CONTAINS "tracker" OR descLower CONTAINS "episodic utilization" OR (descLower CONTAINS "vbp" AND descLower CONTAINS "hosp risks") OR descLower CONTAINS "discharges to review">
        <cfreturn "r_CP_Track">
    </cfif>
    
    <!--- Visit Frequency --->
    <cfif descLower CONTAINS "visit frequency" OR descLower CONTAINS "frequency non-compliance" OR descLower CONTAINS "supervision non-compliance">
        <cfreturn "r_Visit_Freq">
    </cfif>
    
    <!--- 485 Create (Missing 485s) --->
    <cfif descLower CONTAINS "missing 485" OR descLower CONTAINS "485" AND descLower CONTAINS "create">
        <cfreturn "r_485_Create">
    </cfif>
    
    <!--- 487 Create (New Orders Need 487) --->
    <cfif descLower CONTAINS "new orders need 487" OR descLower CONTAINS "487" AND descLower CONTAINS "create">
        <cfreturn "r_487_Create">
    </cfif>
    
    <!--- 485 QA --->
    <cfif descLower CONTAINS "485" AND descLower CONTAINS "qa" OR descLower CONTAINS "verbal order qa">
        <cfreturn "r_485_QA">
    </cfif>
    
    <!--- 485 Send (Un-Sent Orders, Un-Signed Orders) --->
    <cfif descLower CONTAINS "un-sent orders" OR descLower CONTAINS "un-signed orders" OR descLower CONTAINS "485" AND descLower CONTAINS "send">
        <cfreturn "r_485_Send">
    </cfif>
    
    <!--- Datasets --->
    <cfif descLower CONTAINS "datasets">
        <cfreturn "r_Datasets">
    </cfif>
    
    <!--- Procedures QA --->
    <cfif descLower CONTAINS "procedures require qa" OR descLower CONTAINS "scheduled procedures require qa">
        <cfreturn "r_Proc">
    </cfif>
    
    <!--- LUPA, Incoming Orders by Fax, etc. - use r_485_Send as default for orders-related --->
    <cfif descLower CONTAINS "lupa" OR descLower CONTAINS "incoming orders">
        <cfreturn "r_485_Send">
    </cfif>
    
    <!--- Default: return empty string if no match (will show for all users except agency login) --->
    <cfreturn "">
</cffunction>

<!--- Function to check if user has permission to see dashboard item --->
<cffunction name="canViewDashboardItem" output="false" returntype="boolean">
    <cfargument name="description" type="string" required="true">
    <cfargument name="emp_permissions" type="string" required="false" default="">
    <cfargument name="itemLink" type="string" required="false" default="">
    
    <cfset var descLower = LCase(Trim(arguments.description))>
    <cfset var descNorm = Trim(REReplace(descLower, "^\d+\s*##+\s*", "", "ALL"))>
    <cfset var linkLower = LCase(Trim(arguments.itemLink))>
    <!--- #10591: remove VBP Inconsistencies (rpt=VBP_consist), keep VBP Analysis Inconsistencies --->
    <cfif descNorm EQ "vbp inconsistencies"
        OR REFindNoCase("rpt=vbp_consist($|&)", linkLower)>
        <cfreturn false>
    </cfif>
    <cfif descLower CONTAINS "expiring visits" OR descLower CONTAINS "expiring_visits">
        <cfreturn canViewExpiringVisitsDashboard()>
    </cfif>
    
    <!--- Agency login and Project Manager see everything - no role-based filtering --->
    <cfif (isDefined("session.IsAgencyLogin") AND session.IsAgencyLogin EQ 1) 
          OR (isDefined("session.eaRole") AND session.eaRole contains 'Project Manager')>
        <cfreturn true>
    </cfif>
    
    <!--- For non-Project Manager and non-agency login: check session.r_* based on Dashboard.emp_permissions --->
    <!--- Get emp_permissions from Dashboard table (e.g., "r_Datasets", "r_Elig", etc.) --->
    <cfset var permissionField = Trim(arguments.emp_permissions)>
    
    <!--- If emp_permissions is empty, show to all non-agency users --->
    <cfif permissionField EQ "">
        <cfreturn true>
    </cfif>
    
    <!--- Check if session variable exists for this permission field and equals 3 --->
    <!--- Example: If emp_permissions = "r_Datasets", check if session.r_Datasets = 3 --->
    <cfif isDefined("session.#permissionField#") AND session[permissionField] EQ 3>
        <cfreturn true>
    </cfif>
    
    <!--- Default: hide if session.r_* doesn't equal 3 --->
    <cfreturn false>
</cffunction>

<!--- Function to map Dashboard Description to Email_Daily_QA Header --->
<cffunction name="getEmailQAHeaderFromDescription" output="false" returntype="string">
    <cfargument name="description" type="string" required="true">
    
    <cfset var descLower = LCase(Trim(arguments.description))>
    <cfset var descNormalized = REReplace(descLower, "^\d+\s*##+\s*", "", "ALL")>
    <cfset descNormalized = Trim(descNormalized)>
    
    <!--- Map descriptions to Email_Daily_QA headers --->
    <cfif descNormalized CONTAINS "incomplete assessment" OR descNormalized CONTAINS "incomplete assessment/eval">
        <cfreturn "incomplete assessment">
    <cfelseif descNormalized CONTAINS "orphan symptoms">
        <cfreturn "orphan symptoms to review">
    <cfelseif descNormalized CONTAINS "medication" AND (descNormalized CONTAINS "reconcil" OR descNormalized CONTAINS "review")>
        <cfreturn "medications to review">
    <cfelseif descNormalized CONTAINS "missed visit" AND descNormalized CONTAINS "communication">
        <cfreturn "missed visit communication">
    <cfelseif descNormalized CONTAINS "missed visit" AND descNormalized CONTAINS "documentation">
        <cfreturn "missed visit needs documentation">
    <cfelseif descNormalized CONTAINS "unread communication">
        <cfreturn "unread communication">
    <cfelseif descNormalized CONTAINS "late progress note">
        <cfreturn "late progress note">
    <cfelseif descNormalized CONTAINS "procedure" AND (descNormalized CONTAINS "explanation" OR descNormalized CONTAINS "correction")>
        <cfreturn "procedure needs field">
    <cfelseif descNormalized CONTAINS "procedure" AND descNormalized CONTAINS "qa">
        <cfreturn "procedure needs qa">
    <cfelseif descNormalized CONTAINS "incomplete careplan" OR descNormalized CONTAINS "missing/incomplete careplan">
        <cfreturn "incomplete careplan">
    <cfelseif descNormalized CONTAINS "vbp" AND descNormalized CONTAINS "inconsist">
        <cfreturn "VBP Inconsistencies">
    <cfelseif (descNormalized CONTAINS "qa med" AND descNormalized CONTAINS "recon")
        OR descNormalized CONTAINS "qa med reconciliation"
        OR descNormalized CONTAINS "qa med recon">
        <cfreturn "medications to review">
    <cfelseif descNormalized CONTAINS "medications need reconciliation">
        <cfreturn "Medications Need Reconciliation">
    <cfelseif descNormalized CONTAINS "missing oasis" OR descNormalized CONTAINS "missing oasis/evaluation">
        <cfreturn "Missing OASIS">
    <cfelseif descNormalized CONTAINS "missing authorization" OR descNormalized CONTAINS "authorizations required">
        <cfreturn "Authorizations required">
    <cfelseif descNormalized CONTAINS "expiring eligibility" OR descNormalized CONTAINS "expire eligibility">
        <cfreturn "expiring eligibility">
    <cfelseif descNormalized CONTAINS "new eligibility results" OR descNormalized CONTAINS "new eligibility">
        <cfreturn "new_eligibility_results">
    <cfelseif descNormalized CONTAINS "supervision_non_compliance" OR descNormalized CONTAINS "supervision_non_compliance">
        <cfreturn "supervision_non_compliance">
    <cfelseif descNormalized CONTAINS "medicare_utilization" OR descNormalized CONTAINS "medicare_utilization">
        <cfreturn "medicare_utilization">
    <cfelseif descNormalized CONTAINS "expiring visits" OR descNormalized CONTAINS "expiring_visits">
        <cfreturn "expiring_visits">
    <cfelseif descNormalized CONTAINS "required proc notes" OR descNormalized CONTAINS "required procedures qa" OR descNormalized CONTAINS "required_proc_notes_qa">
        <cfreturn "required_proc_notes_qa">
    <cfelseif descNormalized CONTAINS "unresolved incident" OR descNormalized CONTAINS "unresolve_incident">
        <cfreturn "unresolve_incident">
    <cfelseif descNormalized CONTAINS "frequency non-compliance">
        <cfreturn "Frequency Non-Compliance">
    <cfelseif descNormalized CONTAINS "missing 485">
        <cfreturn "Missing 485">
    <cfelseif descNormalized CONTAINS "scheduling needed">
        <cfreturn "scheduling needed">
    <cfelseif descNormalized CONTAINS "active patients with no visits" OR descNormalized CONTAINS "active_patients_no_visits">
        <cfreturn "active_patients_no_visits">
    <cfelseif descNormalized CONTAINS "caregiver alert">
        <cfreturn "caregiver alerts">
    <cfelseif descNormalized CONTAINS "vbp alert">
        <cfreturn "vbp alerts">
    <cfelseif descNormalized CONTAINS "forms">
        <cfreturn "forms">
    <cfelseif descNormalized CONTAINS "evv test">
        <cfreturn "evv test">
    </cfif>
    
    <!--- Default: return normalized description in case of exact match --->
    <cfreturn descNormalized>
</cffunction>

<!--- Map Dashboard cron_header / description / link to Dash_emp_count.Header key (lowercase) --->
<cffunction name="resolveDashEmpCountHeaderKey" output="false" returntype="string">
    <cfargument name="cronHeader" type="string" required="false" default="">
    <cfargument name="description" type="string" required="false" default="">
    <cfargument name="itemLink" type="string" required="false" default="">
    <cfset var key = LCase(Trim(arguments.cronHeader))>
    <cfset var desc = LCase(Trim(arguments.description))>
    <cfset var linkLower = LCase(Trim(arguments.itemLink))>
    <cfset var descNorm = REReplace(desc, "^\d+\s*##+\s*", "", "ALL")>
    <cfset descNorm = Trim(descNorm)>

    <cfif FindNoCase("rpt=caregiver_alerts", linkLower) OR FindNoCase("rpt=caregiver alerts", linkLower)>
        <cfreturn "caregiver alerts">
    </cfif>
    <cfif (FindNoCase("rpt=vbp_alerts", linkLower) OR FindNoCase("rpt=vbp alerts", linkLower))
        AND NOT FindNoCase("inconsist", linkLower)>
        <cfreturn "vbp alerts">
    </cfif>

    <cfif key EQ "caregiver_alerts" OR key EQ "caregiver alert" OR key CONTAINS "caregiver alert">
        <cfreturn "caregiver alerts">
    </cfif>
    <cfif (key EQ "vbp_alerts" OR key EQ "vbp alert" OR key CONTAINS "vbp alert") AND NOT key CONTAINS "inconsist">
        <cfreturn "vbp alerts">
    </cfif>
    <cfif descNorm CONTAINS "caregiver alert">
        <cfreturn "caregiver alerts">
    </cfif>
    <cfif descNorm CONTAINS "vbp alert" AND NOT descNorm CONTAINS "inconsist">
        <cfreturn "vbp alerts">
    </cfif>
    <cfif key EQ "medications to review"
        OR (descNorm CONTAINS "qa med" AND descNorm CONTAINS "recon")
        OR key CONTAINS "qa med">
        <cfreturn "medications to review">
    </cfif>
    <cfif key EQ "procedure needs qa" OR key EQ "procedure needs QA"
        OR FindNoCase("rpt=procedure_qa", linkLower)>
        <cfreturn "procedure needs qa">
    </cfif>
    <cfif key EQ "procedure needs field" OR key EQ "procedure needs explanation"
        OR FindNoCase("rpt=procedure_field", linkLower)
        OR (descNorm CONTAINS "procedure" AND (descNorm CONTAINS "explanation" OR descNorm CONTAINS "correction"))>
        <cfreturn "procedure needs field">
    </cfif>
    <cfif key NEQ "">
        <cfreturn key>
    </cfif>
    <cfreturn LCase(Trim(getEmailQAHeaderFromDescription(arguments.description)))>
</cffunction>

<!--- #10591: always show counts for Caregiver Alerts and VBP Alerts --->
<cffunction name="shouldShowDashboardCount" output="false" returntype="boolean">
    <cfargument name="headerKey" type="string" required="true">
    <cfargument name="itemCount" type="numeric" required="true">
    <cfargument name="showPatti" type="boolean" required="false" default="false">
    <cfset var h = LCase(Trim(arguments.headerKey))>
    <cfif h EQ "caregiver alerts" OR h EQ "caregiver_alerts" OR h EQ "vbp alerts" OR h EQ "vbp_alerts">
        <cfreturn true>
    </cfif>
    <cfreturn (Val(arguments.itemCount) GT 0 AND NOT arguments.showPatti)>
</cffunction>

<!--- Function to get random pastel icon and color for dashboard items --->
<!--- Uses description as seed to ensure same item always gets same icon --->
<cffunction name="getPastelIcon" output="false" returntype="struct">
    <cfargument name="description" type="string" required="true">
    <cfargument name="itemID" type="numeric" required="false" default="0">
    
    <!--- Create seed from description and ID for consistent icon per item --->
    <!--- Convert hash string to numeric value for calculations --->
    <cfset var hashString = Hash(arguments.description & arguments.itemID)>
    <cfset var seed = 0>
    <cfset var i = 0>
    <!--- Convert hash string to number by summing character codes --->
    <cfloop from="1" to="#Len(hashString)#" index="i">
        <cfset seed = seed + Asc(Mid(hashString, i, 1))>
    </cfloop>
    <cfset seed = seed + Val(arguments.itemID)>
    
    <cfset var iconArray = ArrayNew(1)>
    <cfset var colorArray = ArrayNew(1)>
    <cfset var result = StructNew()>
    
    <!--- Array of pastel-colored Font Awesome icons --->
    <cfset iconArray[1] = "fa-star">
    <cfset iconArray[2] = "fa-diamond">
    <cfset iconArray[3] = "fa-bell">
    <cfset iconArray[4] = "fa-tag">
    <cfset iconArray[5] = "fa-flag">
     
    <!--- Array of pastel color styles (actual pastel colors) --->
    <cfset colorArray[1] = "background-color: ##FFB6C1; color: ##8B4A5C;">
    <cfset colorArray[2] = "background-color: ##FFD9E3; color: ##8B4A5C;">
    <cfset colorArray[3] = "background-color: ##E6E6FA; color: ##6A5ACD;">
    <cfset colorArray[4] = "background-color: ##DDA0DD; color: ##8B4789;">
    <cfset colorArray[5] = "background-color: ##B0E0E6; color: ##4682B4;">
    <cfset colorArray[6] = "background-color: ##AFEEEE; color: ##008B8B;">
    <cfset colorArray[7] = "background-color: ##F0E68C; color: ##8B7355;">
    <cfset colorArray[8] = "background-color: ##FFE4B5; color: ##CD853F;">
    <cfset colorArray[9] = "background-color: ##FFEFD5; color: ##DAA520;">
    <cfset colorArray[10] = "background-color: ##E0FFE0; color: ##228B22;">
    <cfset colorArray[11] = "background-color: ##F5FFFA; color: ##2E8B57;">
    <cfset colorArray[12] = "background-color: ##FFF0F5; color: ##CD5C5C;">
    <cfset colorArray[13] = "background-color: ##FFE4E1; color: ##DC143C;">
    <cfset colorArray[14] = "background-color: ##F5F5DC; color: ##8B7355;">
    <cfset colorArray[15] = "background-color: ##FFFACD; color: ##B8860B;">
    <cfset colorArray[16] = "background-color: ##E6F3FF; color: ##4169E1;">
    <cfset colorArray[17] = "background-color: ##F0F8FF; color: ##4682B4;">
    <cfset colorArray[18] = "background-color: ##F5F5F5; color: ##696969;">
    <cfset colorArray[19] = "background-color: ##FFE4E1; color: ##8B4513;">
    <cfset colorArray[20] = "background-color: ##FFF8DC; color: ##8B7355;">
    
    <!--- Use seed to pick consistent icon and color --->
    <cfset var iconIndex = (Abs(seed) MOD ArrayLen(iconArray)) + 1>
    <cfset var colorIndex = (Abs(seed * 7) MOD ArrayLen(colorArray)) + 1>
    
    <cfset result.icon = iconArray[iconIndex]>
    <cfset result.color = colorArray[colorIndex]>
    
    <cfreturn result>
</cffunction>
