Files
AAS_NewGeneration/src/database/table/Table_Messagebank.kt
2026-02-10 17:05:39 +07:00

261 lines
12 KiB
Kotlin

package database.table
import database.data.Messagebank
import database.dbFunctions
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.tinylog.Logger
import java.sql.Connection
import java.util.function.Consumer
class Table_Messagebank(connection: Connection) : dbFunctions<Messagebank>("messagebank", connection, listOf("index", "Description", "Language", "ANN_ID", "Voice_Type", "Message_Detail", "Message_TAGS")) {
override fun Create() {
val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"Description VARCHAR(512) NOT NULL," + // Description of the message
"Language VARCHAR(45) NOT NULL," + // Language of the message
"ANN_ID INT NOT NULL," + // ANN ID of the message
"Voice_Type VARCHAR(45) NOT NULL," + // Voice type of the message
"Message_Detail VARCHAR(1024) NOT NULL," + // Full message text
"Message_TAGS VARCHAR(1024)" + // Comma-separated tags for the message
")"
super.Create(tabledefinition)
}
override fun Get(cbOK: Consumer<Unit>?, cbFail: Consumer<String>?) {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val messagebank = Messagebank(
resultSet.getLong("index").toUInt(),
resultSet.getString("Description"),
resultSet.getString("Language"),
resultSet.getInt("ANN_ID").toUInt(),
resultSet.getString("Voice_Type"),
resultSet.getString("Message_Detail"),
resultSet.getString("Message_TAGS")
)
List.add(messagebank)
}
cbOK?.accept(Unit)
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName} : ${e.message}" as Any)
cbFail?.accept("Error fetching ${super.dbName} : ${e.message}")
}
}
override fun Add(data: Messagebank): Boolean {
try {
val statement =
connection.prepareStatement("INSERT INTO ${super.dbName} (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) VALUES (?, ?, ?, ?, ?, ?)")
statement?.setString(1, data.Description)
statement?.setString(2, data.Language)
statement?.setInt(3, data.ANN_ID.toInt())
statement?.setString(4, data.Voice_Type)
statement?.setString(5, data.Message_Detail)
statement?.setString(6, data.Message_TAGS)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Messagebank added: ${data.Description}" as Any)
return true
} else {
Logger.warn("No messagebank entry added for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding messagebank entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<Messagebank>): Boolean {
try {
connection.autoCommit = false
val sql =
"INSERT INTO ${super.dbName} (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) VALUES (?, ?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (mb in data) {
statement.setString(1, mb.Description)
statement.setString(2, mb.Language)
statement.setInt(3, mb.ANN_ID.toInt())
statement.setString(4, mb.Voice_Type)
statement.setString(5, mb.Message_Detail)
statement.setString(6, mb.Message_TAGS)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk messagebank insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
return true
} catch (e: Exception) {
Logger.error("Error adding messagebank entries: ${e.message}" as Any)
}
return false
}
override fun UpdateByIndex(index: Int, data: Messagebank): Boolean {
try {
val statement =
connection.prepareStatement("UPDATE ${super.dbName} SET Description = ?, Language = ?, ANN_ID = ?, Voice_Type = ?, Message_Detail = ?, Message_TAGS = ? WHERE `index` = ?")
statement?.setString(1, data.Description)
statement?.setString(2, data.Language)
statement?.setInt(3, data.ANN_ID.toInt())
statement?.setString(4, data.Voice_Type)
statement?.setString(5, data.Message_Detail)
statement?.setString(6, data.Message_TAGS)
statement?.setLong(7, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Messagebank updated at index $index: ${data.Description}" as Any)
return true
} else {
Logger.warn("No messagebank entry updated at index $index for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating messagebank entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
val tempdb_name = "temp_${super.dbName}"
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS $tempdb_name LIKE ${super.dbName}")
statement?.executeUpdate("TRUNCATE TABLE $tempdb_name")
statement?.executeUpdate("INSERT INTO $tempdb_name (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) SELECT Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS FROM ${super.dbName} ORDER BY ANN_ID ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) SELECT Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS FROM $tempdb_name")
statement?.executeUpdate("DROP TABLE $tempdb_name")
Logger.info("${super.dbName} table resorted by Description" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by Description: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
try {
// check if there is sheet named "Messagebank"
val sheet =
workbook.getSheet("Messagebank") ?: throw Exception("No sheet named 'Messagebank' found")
// check if the sheet contains header named "Index", "Description", "Language", "ANN_ID", "Voice_Type", "Message_Detail", "Message_TAGS"
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers =
arrayOf(
"Index",
"Description",
"Language",
"ANN_ID",
"Voice_Type",
"Message_Detail",
"Message_TAGS"
)
for ((colIndex, header) in headers.withIndex()) {
val cell = headerRow.getCell(colIndex) ?: throw Exception("Header '$header' not found")
if (cell.stringCellValue != header) throw Exception("Header '$header' not found")
}
// clear existing messagebank
Clear()
// read each row and insert into database
val _messagebankList = ArrayList<Messagebank>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val description = row.getCell(1)?.stringCellValue ?: continue
val language = row.getCell(2)?.stringCellValue ?: continue
val annId = row.getCell(3)?.stringCellValue?.toUIntOrNull() ?: continue
val voiceType = row.getCell(4)?.stringCellValue ?: continue
val messageDetail = row.getCell(5)?.stringCellValue ?: continue
val messageTags = row.getCell(6)?.stringCellValue ?: continue
val messagebank =
Messagebank(0u, description, language, annId, voiceType, messageDetail, messageTags)
_messagebankList.add(messagebank)
}
return AddAll(_messagebankList)
} catch (e: Exception) {
Logger.error { "Error importing Messagebank, Msg: ${e.message}" }
}
return false
}
override fun Export_XLSX(): XSSFWorkbook? {
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
val workbook = XSSFWorkbook()
val sheet = workbook.createSheet("Messagebank")
val headerRow = sheet.createRow(0)
val headers =
arrayOf(
"Index",
"Description",
"Language",
"ANN_ID",
"Voice_Type",
"Message_Detail",
"Message_TAGS"
)
for ((colIndex, header) in headers.withIndex()) {
val cell = headerRow.createCell(colIndex)
cell.setCellValue(header)
}
var rowIndex = 1
while (resultSet?.next() == true) {
val row = sheet.createRow(rowIndex++)
row.createCell(0).setCellValue(resultSet.getString("index"))
row.createCell(1).setCellValue(resultSet.getString("Description"))
row.createCell(2).setCellValue(resultSet.getString("Language"))
row.createCell(3).setCellValue(resultSet.getString("ANN_ID"))
row.createCell(4).setCellValue(resultSet.getString("Voice_Type"))
row.createCell(5).setCellValue(resultSet.getString("Message_Detail"))
row.createCell(6).setCellValue(resultSet.getString("Message_TAGS"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting Messagebank, Msg: ${e.message}" }
}
return null
}
/**
* Get all distinct message ID from messagebank
* @return a list of distinct ANN_ID sorted numerically
*/
fun Get_MessageID_List(): List<UInt> {
return List
.distinctBy { it.ANN_ID }
.map { it.ANN_ID }
.sorted()
}
// valid messagedetail is message_name [ann_id]
// so we need regex to check if messagedetail matches that format
private val messageDetailRegex = """^(.*?)\s*\[(\d+)]$""".toRegex()
/**
* Check if a messagebank entry exists based on messagedetail and languages
* @param messagedetail the messagedetail in format "message_name [ann_id]"
* @param languages a comma or semicolon separated string of languages to check
* @return true if the messagebank entry exists for all specified languages, false otherwise
*/
fun Messagebank_Exists(messagedetail: String, languages: String) : Boolean{
val match = messageDetailRegex.find(messagedetail)
val ll = languages.split(",",";").map { it.trim() }
if (match != null){
val msg = match.groupValues[1].trim()
val annid = match.groupValues[2].toUIntOrNull() ?: return false // kalau bukan number, return false
val ff = List.filter{ it.ANN_ID == annid && it.Description == msg }
return ll.all{ lang -> ff.any{ it.Language.equals(lang, ignoreCase = true) } }
}
return false
}
}