AlphabetIndex.kt 45 lignes · 1688 octets
package fr.ebii.card2vcf.crm

import fr.ebii.card2vcf.data.CrmContactEntity

object AlphabetIndex {
    fun sortKey(c: CrmContactEntity, sort: ContactSort): String = when (sort) {
        ContactSort.LAST_NAME -> c.lastName ?: c.fullName ?: ""
        ContactSort.FIRST_NAME -> c.firstName ?: c.fullName ?: ""
        ContactSort.COMPANY -> c.company ?: ""
        ContactSort.CREATED_AT -> c.createdAt.toString().padStart(20, '0')
    }

    fun sectionLetter(key: String): Char {
        val c = key.trim().firstOrNull()?.uppercaseChar()
        return if (c != null && c in 'A'..'Z') c else '#'
    }

    /**
     * Alphabetical sorts: ordered A–Z then `#`, contacts sorted within each section.
     * [ContactSort.CREATED_AT]: single flat section (chrono desc), no A–Z rail sections.
     */
    fun group(
        contacts: List<CrmContactEntity>,
        sort: ContactSort,
    ): LinkedHashMap<Char, List<CrmContactEntity>> {
        if (sort == ContactSort.CREATED_AT) {
            val sorted = contacts.sortedByDescending { it.createdAt }
            return linkedMapOf('#' to sorted)
        }
        val sorted = contacts.sortedWith(
            compareBy(String.CASE_INSENSITIVE_ORDER) { sortKey(it, sort) },
        )
        val buckets = LinkedHashMap<Char, MutableList<CrmContactEntity>>()
        for (c in sorted) {
            val letter = sectionLetter(sortKey(c, sort))
            buckets.getOrPut(letter) { mutableListOf() }.add(c)
        }
        val out = LinkedHashMap<Char, List<CrmContactEntity>>()
        for ((k, v) in buckets) {
            if (k != '#') out[k] = v
        }
        buckets['#']?.let { out['#'] = it }
        return out
    }
}