package dev.inmo.tgbotapi.CommonAbstracts import dev.inmo.tgbotapi.types.MessageEntity.textsources.regular import dev.inmo.tgbotapi.types.MessageEntity.toTextParts import dev.inmo.tgbotapi.types.captionLength import dev.inmo.tgbotapi.types.textLength const val DirectInvocationOfTextSourceConstructor = "It is strongly not recommended to use constructors directly instead of factory methods" typealias TextSourcesList = List interface TextSource { val markdown: String val markdownV2: String val html: String val source: String val asText: String get() = source } @Suppress("NOTHING_TO_INLINE") inline operator fun TextSource.plus(other: TextSource) = listOf(this, other) @Suppress("NOTHING_TO_INLINE") inline operator fun TextSource.plus(other: List) = listOf(this) + other @Suppress("NOTHING_TO_INLINE") inline operator fun TextSource.plus(text: String) = listOf(this, regular(text)) @Suppress("NOTHING_TO_INLINE") inline operator fun List.plus(text: String) = this + regular(text) interface MultilevelTextSource : TextSource { val subsources: List } data class TextPart( val range: IntRange, val source: TextSource ) fun List.justTextSources() = map { it.source } fun List.makeString() = joinToString("") { it.source } internal fun MultilevelTextSource.textParts(offset: Int): List = subsources.toTextParts(offset) fun List.separateForMessage(limit: IntRange, numberOfParts: Int? = null): List> { if (isEmpty()) { return emptyList() } val resultList = mutableListOf>(mutableListOf()) var currentPartLength = 0 val maxSize = limit.last + 1 for (current in this) { if (current.source.length > maxSize) { error("Currently unsupported parts with size more than target one-message parts (${current.source.length} > ${maxSize})") } if (currentPartLength + current.source.length > maxSize) { if (numberOfParts == null || numberOfParts < resultList.size) { resultList.add(mutableListOf()) currentPartLength = 0 } else { break } } resultList.last().add(current) currentPartLength += current.source.length } return resultList } /** * This method will prepare [TextSource]s list for messages. Remember, that first part will be separated with * [captionLength] and all others with */ fun List.separateForCaption(): List> { val captionPart = separateForMessage(captionLength, 1).first() return listOf(captionPart) + minus(captionPart).separateForMessage(textLength) } /** * This method will prepare [TextSource]s list for messages with [textLength] */ @Suppress("NOTHING_TO_INLINE") inline fun List.separateForText(): List> = separateForMessage(textLength)