Files
AAS_NewGeneration/src/database/MariaDB.kt
2025-10-06 08:30:09 +07:00

2305 lines
123 KiB
Kotlin

package database
import codes.Somecodes.Companion.ValiDateForLogHtml
import codes.Somecodes.Companion.toJsonString
import content.Category
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import max_channel
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.tinylog.Logger
import java.sql.Connection
import java.sql.DriverManager
import java.util.function.Consumer
import kotlin.math.max
/**
* A class to manage a connection to a MariaDB database.
*
* @property address The address of the MariaDB server.
* @property port The port number of the MariaDB server.
* @property dbName The name of the database to connect to.
* @property username The username for the database connection.
* @property password The password for the database connection.
*/
@Suppress("unused", "SqlSourceToSinkFlow")
class MariaDB(
address: String = "localhost",
port: Int = 3306,
dbName: String = "aas",
username: String = "admin",
password: String = "admin"
) {
var connected: Boolean = false
lateinit var connection: Connection
lateinit var soundDB: dbFunctions<Soundbank>
lateinit var messageDB: dbFunctions<Messagebank>
lateinit var languageDB: dbFunctions<LanguageLink>
lateinit var scheduleDB: dbFunctions<ScheduleBank>
lateinit var broadcastDB: dbFunctions<BroadcastZones>
lateinit var queuetableDB: dbFunctions<QueueTable>
lateinit var queuepagingDB: dbFunctions<QueuePaging>
lateinit var soundchannelDB: dbFunctions<SoundChannel>
lateinit var logDB: dbFunctions<Log>
lateinit var userDB: dbFunctions<UserDB>
companion object {
fun ValidDate(date: String): Boolean {
// Check if the date is in the format DD/MM/YYYY
val regex = Regex("""^\d{2}/\d{2}/\d{4}$""")
return regex.matches(date)
}
fun ValidTime(time: String): Boolean {
// Check if the time is in the format HH:MM:SS
val regex = Regex("""^\d{2}:\d{2}:\d{2}$""")
return regex.matches(time)
}
/**
* Convert SoundbankList, MessagebankList, LanguageLinkList, or SchedulebankList to a JSON String.
* @param list The ArrayList to convert to a String.
* @return A JSON String representation of the ArrayList.
*/
fun <T> ArrayListtoString(list: ArrayList<T>): String {
return try {
toJsonString(list)
} catch (e: Exception) {
Logger.error("Error converting list to JSON: ${e.message}" as Any)
"[]"
}
}
}
init {
try {
connection =
DriverManager.getConnection(
"jdbc:mysql://$address:$port/$dbName?sslMode=REQUIRED",
username,
password
) as Connection
Logger.info("Connected to MySQL" as Any)
connected = true
soundDB = object : dbFunctions<Soundbank>("soundbank", connection) {
override fun Create() {
val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"Description VARCHAR(1024) NOT NULL," + // Description of the soundbank
"TAG VARCHAR(45) NOT NULL," + // TAG of the soundbank
"Category VARCHAR(45) NOT NULL," + // Category of the soundbank
"Language VARCHAR(45) NOT NULL," + // Language of the soundbank
"VoiceType VARCHAR(45) NOT NULL," + // VoiceType of the soundbank
"Path VARCHAR(1024) NOT NULL" + // Path to the sound file
")"
super.Create(tabledefinition)
}
override fun Get() {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val soundbank = Soundbank(
resultSet.getLong("index").toUInt(),
resultSet.getString("Description"),
resultSet.getString("TAG"),
resultSet.getString("Category"),
resultSet.getString("Language"),
resultSet.getString("VoiceType"),
resultSet.getString("Path")
)
List.add(soundbank)
}
} catch (e: Exception) {
Logger.error("Error fetching soundbanks: ${e.message}" as Any)
}
}
fun Get_By_Index(index: Int): Soundbank? {
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName} WHERE `index` = $index")
if (resultSet?.next() == true) {
return Soundbank(
resultSet.getLong("index").toUInt(),
resultSet.getString("Description"),
resultSet.getString("TAG"),
resultSet.getString("Category"),
resultSet.getString("Language"),
resultSet.getString("VoiceType"),
resultSet.getString("Path")
)
}
} catch (_: Exception) {
Logger.error("Error finding ${super.dbName} with index $index" as Any)
}
return null
}
override fun Add(data: Soundbank): Boolean {
try {
val statement =
connection.prepareStatement("INSERT INTO ${super.dbName} (Description, TAG, Category, Language, VoiceType, Path) VALUES (?, ?, ?, ?, ?, ?)")
statement?.setString(1, data.Description)
statement?.setString(2, data.TAG)
statement?.setString(3, data.Category)
statement?.setString(4, data.Language)
statement?.setString(5, data.VoiceType)
statement?.setString(6, data.Path)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Soundbank added: ${data.Description}" as Any)
return true
} else {
Logger.warn("No soundbank entry added for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding soundbank entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<Soundbank>): Boolean {
// use mysql bulk insert
try {
connection.autoCommit = false
val sql =
"INSERT INTO ${super.dbName} (Description, TAG, Category, Language, VoiceType, Path) VALUES (?, ?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (sb in data) {
statement.setString(1, sb.Description)
statement.setString(2, sb.TAG)
statement.setString(3, sb.Category)
statement.setString(4, sb.Language)
statement.setString(5, sb.VoiceType)
statement.setString(6, sb.Path)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk soundbank insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
return true
} catch (e: Exception) {
Logger.error("Error adding soundbank entries: ${e.message}" as Any)
}
return false
}
override fun UpdateByIndex(index: Int, data: Soundbank): Boolean {
try {
val statement =
connection.prepareStatement("UPDATE ${super.dbName} SET Description = ?, TAG = ?, Category = ?, Language = ?, VoiceType = ?, Path = ? WHERE `index` = ?")
statement?.setString(1, data.Description)
statement?.setString(2, data.TAG)
statement?.setString(3, data.Category)
statement?.setString(4, data.Language)
statement?.setString(5, data.VoiceType)
statement?.setString(6, data.Path)
statement?.setLong(7, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Soundbank updated at index $index: ${data.Description}" as Any)
return true
} else {
Logger.warn("No soundbank entry updated at index $index for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating soundbank entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (Description, TAG, Category, Language, VoiceType, Path) SELECT Description, TAG, Category, Language, VoiceType, Path FROM ${super.dbName} ORDER BY Description ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (Description, TAG, Category, Language, VoiceType, Path) SELECT Description, TAG, Category, Language, VoiceType, Path FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
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 "Soundbank"
val sheet =
workbook.getSheet("Soundbank") ?: throw Exception("No sheet named 'Soundbank' found")
// check if the sheet contains header named "index", "Description", "TAG", "Category", "Language", "VoiceType", "Path"
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers =
arrayOf("Index", "Description", "TAG", "Category", "Language", "VoiceType", "Path")
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 soundbank
Clear()
// read each row and insert into database
val _soundbankList = ArrayList<Soundbank>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val description = row.getCell(1)?.stringCellValue ?: continue
val tag = row.getCell(2)?.stringCellValue ?: continue
val category = row.getCell(3)?.stringCellValue ?: continue
val language = row.getCell(4)?.stringCellValue ?: continue
val voiceType = row.getCell(5)?.stringCellValue ?: continue
val path = row.getCell(6)?.stringCellValue ?: continue
val soundbank = Soundbank(0u, description, tag, category, language, voiceType, path)
_soundbankList.add(soundbank)
}
return AddAll(_soundbankList)
} catch (e: Exception) {
Logger.error { "Error importing Soundbank, 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("Soundbank")
val headerRow = sheet.createRow(0)
val headers =
arrayOf("Index", "Description", "TAG", "Category", "Language", "VoiceType", "Path")
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("TAG"))
row.createCell(3).setCellValue(resultSet.getString("Category"))
row.createCell(4).setCellValue(resultSet.getString("Language"))
row.createCell(5).setCellValue(resultSet.getString("VoiceType"))
row.createCell(6).setCellValue(resultSet.getString("Path"))
}
for (i in 0 until headers.size) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting Soundbank, Msg: ${e.message}" }
}
return null
}
}
messageDB = object : dbFunctions<Messagebank>("messagebank", connection) {
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() {
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)
}
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName} : ${e.message}" as Any)
}
}
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()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (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 temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
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
}
}
languageDB = object : dbFunctions<LanguageLink>("languagelinking", connection) {
override fun Create() {
val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"TAG VARCHAR(45) NOT NULL," + // Language tag (e.g., EN, FR)
"Language VARCHAR(128) NOT NULL" + // Full language name (e.g., English, French)
")"
super.Create(tabledefinition)
}
override fun Get() {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val languageLink = LanguageLink(
resultSet.getLong("index").toUInt(),
resultSet.getString("TAG"),
resultSet.getString("Language")
)
List.add(languageLink)
}
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName} : ${e.message}" as Any)
}
}
override fun Add(data: LanguageLink): Boolean {
try {
val statement = connection.prepareStatement("INSERT INTO ${super.dbName} (TAG, Language) VALUES (?, ?)")
statement.setString(1, data.TAG)
statement.setString(2, data.Language)
val rowsAffected = statement.executeUpdate()
if (rowsAffected > 0) {
Logger.info("Language link added: ${data.TAG} -> ${data.Language}" as Any)
return true
} else {
Logger.warn("No language link entry added for: ${data.TAG} -> ${data.Language}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding language link entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<LanguageLink>): Boolean {
try {
connection.autoCommit = false
val sql = "INSERT INTO ${super.dbName} (TAG, Language) VALUES (?, ?)"
val statement = connection.prepareStatement(sql)
for (ll in List) {
statement.setString(1, ll.TAG)
statement.setString(2, ll.Language)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk languagelinking insert successful: ${List.size} entries" as Any)
connection.autoCommit = true
return true
} catch (e: Exception) {
Logger.error("Error adding languagelinking entries: ${e.message}" as Any)
}
return false
}
override fun UpdateByIndex(index: Int, data: LanguageLink): Boolean {
try {
val statement =
connection.prepareStatement("UPDATE ${super.dbName} SET TAG = ?, Language = ? WHERE `index` = ?")
statement?.setString(1, data.TAG)
statement?.setString(2, data.Language)
statement?.setLong(3, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Language link updated at index $index: ${data.TAG} -> ${data.Language}" as Any)
return true
} else {
Logger.warn("No language link entry updated at index $index for: ${data.TAG} -> ${data.Language}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating language link entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (TAG, Language) SELECT TAG, Language FROM ${super.dbName} ORDER BY TAG")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (TAG, Language) SELECT TAG, Language FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
Logger.info("${super.dbName} table resorted by TAG" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by TAG: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
try {
val sheet =
workbook.getSheet("LanguageLink") ?: throw Exception("No sheet named 'LanguageLink' found")
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers = arrayOf("Index", "TAG", "Language")
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 languagelink
Clear()
// read each row and insert into database
val _languageLinkList = ArrayList<LanguageLink>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val tag = row.getCell(1)?.stringCellValue ?: continue
val language = row.getCell(2)?.stringCellValue ?: continue
val languageLink = LanguageLink(0u, tag, language)
_languageLinkList.add(languageLink)
}
return AddAll(_languageLinkList)
} catch (e: Exception) {
Logger.error { "Error importing LanguageLink, 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("languagelinking")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "TAG", "Language")
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("TAG"))
row.createCell(2).setCellValue(resultSet.getString("Language"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting languagelinking, Msg: ${e.message}" }
}
return null
}
}
scheduleDB = object : dbFunctions<ScheduleBank>("schedulebank", connection) {
override fun Create() {
val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"Description VARCHAR(128) NOT NULL," + // Description of the schedule
"Day VARCHAR(255) NOT NULL," + // Day in format DD/MM/YYYY
"Time VARCHAR(20) NOT NULL," + // Time in format HH:MM:SS
"Soundpath VARCHAR(512) NOT NULL," + // Path to the sound file
"`Repeat` TINYINT UNSIGNED NOT NULL," + // Repeat type (0=Once, 1=Daily, 2=Weekly, 3=Monthly, 4=Yearly)
"Enable BOOLEAN NOT NULL," + // Enable or disable the schedule
"BroadcastZones TEXT NOT NULL," + // Comma-separated list of broadcast zones
"Language VARCHAR(45) NOT NULL" + // Language code (e.g., EN, FR)
")"
super.Create(tabledefinition)
}
override fun Get() {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val schedulebank = ScheduleBank(
resultSet.getLong("index").toUInt(),
resultSet.getString("Description"),
resultSet.getString("Day"),
resultSet.getString("Time"),
resultSet.getString("Soundpath"),
resultSet.getInt("Repeat").toUByte(),
resultSet.getBoolean("Enable"),
resultSet.getString("BroadcastZones"),
resultSet.getString("Language")
)
List.add(schedulebank)
}
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName}: ${e.message}" as Any)
}
}
override fun Add(data: ScheduleBank): Boolean {
if (!ValidDate(data.Day)) {
Logger.error("Error adding schedulebank entry: Invalid date format ${data.Day}" as Any)
return false
}
if (!ValidTime(data.Time)) {
Logger.error("Error adding schedulebank entry: Invalid time format ${data.Time}" as Any)
return false
}
try {
val statement =
connection.prepareStatement("INSERT INTO ${super.dbName} (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
statement?.setString(1, data.Description)
statement?.setString(2, data.Day)
statement?.setString(3, data.Time)
statement?.setString(4, data.Soundpath)
statement?.setInt(5, data.Repeat.toInt())
statement?.setBoolean(6, data.Enable)
statement?.setString(7, data.BroadcastZones)
statement?.setString(8, data.Language)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Schedulebank added: ${data.Description}" as Any)
return true
} else {
Logger.warn("No schedulebank entry added for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding schedulebank entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<ScheduleBank>): Boolean {
try {
connection.autoCommit = false
val sql =
"INSERT INTO ${super.dbName} (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (sb in data) {
if (!ValidDate(sb.Day) || !ValidTime(sb.Time)) {
Logger.error("Invalid date or time format for schedulebank: ${sb.Description}" as Any)
continue
}
statement.setString(1, sb.Description)
statement.setString(2, sb.Day)
statement.setString(3, sb.Time)
statement.setString(4, sb.Soundpath)
statement.setInt(5, sb.Repeat.toInt())
statement.setBoolean(6, sb.Enable)
statement.setString(7, sb.BroadcastZones)
statement.setString(8, sb.Language)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk schedulebank insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
return true
} catch (e: Exception) {
Logger.error("Error adding schedulebank entries: ${e.message}" as Any)
}
return false
}
override fun UpdateByIndex(index: Int, data: ScheduleBank): Boolean {
if (!ValidDate(data.Day)) {
Logger.error("Error updating schedulebank entry: Invalid date format ${data.Day}" as Any)
return false
}
if (!ValidTime(data.Time)) {
Logger.error("Error updating schedulebank entry: Invalid time format ${data.Time}" as Any)
return false
}
try {
val statement =
connection.prepareStatement("UPDATE ${super.dbName} SET Description = ?, Day = ?, Time = ?, Soundpath = ?, Repeat = ?, Enable = ?, BroadcastZones = ?, Language = ? WHERE `index` = ?")
statement?.setString(1, data.Description)
statement?.setString(2, data.Day)
statement?.setString(3, data.Time)
statement?.setString(4, data.Soundpath)
statement?.setInt(5, data.Repeat.toInt())
statement?.setBoolean(6, data.Enable)
statement?.setString(7, data.BroadcastZones)
statement?.setString(8, data.Language)
statement?.setLong(9, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Schedulebank updated at index $index: ${data.Description}" as Any)
return true
} else {
Logger.warn("No schedulebank entry updated at index $index for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating schedulebank entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) SELECT Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language FROM ${super.dbName} ORDER BY Day , Time ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) SELECT Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
Logger.info("${super.dbName} table resorted by Day and Time" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by Day and Time: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
try {
val sheet =
workbook.getSheet("Schedulebank") ?: throw Exception("No sheet named 'Schedulebank' found")
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers = arrayOf(
"Index",
"Description",
"Day",
"Time",
"Soundpath",
"Repeat",
"Enable",
"BroadcastZones",
"Language"
)
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 schedulebank
Clear()
// read each row and insert into database
val _schedulebankList = ArrayList<ScheduleBank>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val description = row.getCell(1)?.stringCellValue ?: continue
val day = row.getCell(2)?.stringCellValue ?: continue
val time = row.getCell(3)?.stringCellValue ?: continue
val soundpath = row.getCell(4)?.stringCellValue ?: continue
val repeat = row.getCell(5)?.stringCellValue?.toUByteOrNull() ?: continue
val enable = row.getCell(6)?.stringCellValue?.toBooleanStrictOrNull() ?: continue
val broadcastZones = row.getCell(7)?.stringCellValue ?: continue
val language = row.getCell(8)?.stringCellValue ?: continue
val schedulebank =
ScheduleBank(
0u,
description,
day,
time,
soundpath,
repeat,
enable,
broadcastZones,
language
)
_schedulebankList.add(schedulebank)
}
return scheduleDB.AddAll(_schedulebankList)
} catch (e: Exception) {
Logger.error { "Error importing Schedulebank, 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("Schedulebank")
val headerRow = sheet.createRow(0)
val headers = arrayOf(
"Index",
"Description",
"Day",
"Time",
"Soundpath",
"Repeat",
"Enable",
"BroadcastZones",
"Language"
)
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("Day"))
row.createCell(3).setCellValue(resultSet.getString("Time"))
row.createCell(4).setCellValue(resultSet.getString("Soundpath"))
row.createCell(5).setCellValue(resultSet.getString("Repeat"))
row.createCell(6).setCellValue(resultSet.getString("Enable"))
row.createCell(7).setCellValue(resultSet.getString("BroadcastZones"))
row.createCell(8).setCellValue(resultSet.getString("Language"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting Schedulebank, Msg: ${e.message}" }
}
return null
}
}
broadcastDB = object : dbFunctions<BroadcastZones>("broadcastzones", connection) {
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 broadcast zone
"SoundChannel VARCHAR(45) NOT NULL," + // Sound channel of the broadcast zone
"id VARCHAR(45) NOT NULL," + // Box of the broadcast zone
"bp VARCHAR(45) NOT NULL" + // Relay of the broadcast zone
")"
super.Create(tabledefinition)
}
override fun Get() {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val zone = BroadcastZones(
resultSet.getLong("index").toUInt(),
resultSet.getString("description"),
resultSet.getString("SoundChannel"),
resultSet.getString("id"),
resultSet.getString("bp")
)
List.add(zone)
}
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName} : ${e.message}" as Any)
}
}
override fun Add(data: BroadcastZones): Boolean {
try {
val statement =
connection.prepareStatement("INSERT INTO ${super.dbName} (description, SoundChannel, Box, Relay) VALUES (?, ?, ?, ?)")
statement?.setString(1, data.description)
statement?.setString(2, data.SoundChannel)
statement?.setString(3, data.id)
statement?.setString(4, data.bp)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Broadcast zone added: ${data.description}" as Any)
return true
} else {
Logger.warn("No broadcast zone entry added for: ${data.description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding broadcast zone entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<BroadcastZones>): Boolean {
try {
connection.autoCommit = false
val sql =
"INSERT INTO ${super.dbName} (description, SoundChannel, Box, Relay) VALUES (?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (bz in data) {
statement.setString(1, bz.description)
statement.setString(2, bz.SoundChannel)
statement.setString(3, bz.id)
statement.setString(4, bz.bp)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk ${super.dbName} insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
return true
} catch (e: Exception) {
Logger.error("Error adding ${super.dbName} entries: ${e.message}" as Any)
}
return false
}
override fun UpdateByIndex(index: Int, data: BroadcastZones): Boolean {
try {
val statement =
connection.prepareStatement("UPDATE ${super.dbName} SET description = ?, SoundChannel = ?, Box = ?, Relay = ? WHERE `index` = ?")
statement?.setString(1, data.description)
statement?.setString(2, data.SoundChannel)
statement?.setString(3, data.id)
statement?.setString(4, data.bp)
statement?.setLong(5, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Broadcast zone updated at index $index: ${data.description}" as Any)
return true
} else {
Logger.warn("No broadcast zone entry updated at index $index for: ${data.description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating broadcast zone entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (description, SoundChannel, Box, Relay) SELECT description, SoundChannel, Box, Relay FROM ${super.dbName} ORDER BY description ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (description, SoundChannel, Box, Relay) SELECT description, SoundChannel, Box, Relay FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
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 {
val sheet = workbook.getSheet("BroadcastZones")
?: throw Exception("No sheet named 'BroadcastZones' found")
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers = arrayOf("Index", "description", "SoundChannel", "Box", "Relay")
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 broadcast_zones
Clear()
// read each row and insert into database
val _broadcastZonesList = ArrayList<BroadcastZones>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val description = row.getCell(1)?.stringCellValue ?: continue
val soundChannel = row.getCell(2)?.stringCellValue ?: continue
val box = row.getCell(3)?.stringCellValue ?: continue
val relay = row.getCell(4)?.stringCellValue ?: continue
val broadcastZone = BroadcastZones(0u, description, soundChannel, box, relay)
_broadcastZonesList.add(broadcastZone)
}
return AddAll(_broadcastZonesList)
} catch (e: Exception) {
Logger.error { "Error importing BroadcastZones, 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("BroadcastZones")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "description", "SoundChannel", "Box", "Relay")
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("SoundChannel"))
row.createCell(3).setCellValue(resultSet.getString("Box"))
row.createCell(4).setCellValue(resultSet.getString("Relay"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting BroadcastZones, Msg: ${e.message}" }
}
return null
}
}
queuetableDB = object : dbFunctions<QueueTable>("queue_table", connection) {
override fun Create() {
val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"Date_Time VARCHAR(45) NOT NULL," + // Date and time of the entry
"Source VARCHAR(45) NOT NULL," + // Source of the entry
"Type VARCHAR(45) NOT NULL," + // Type of the entry
"Message VARCHAR(1024) NOT NULL," + // Message content
"SB_TAGS VARCHAR(1024)," + // Comma-separated soundbank tags
"BroadcastZones VARCHAR(1024) NOT NULL," + // Comma-separated broadcast zones
"`Repeat` INT NOT NULL," + // Number of repeats
"Language VARCHAR(45) NOT NULL" + // Language of the message
")"
super.Create(tabledefinition)
}
override fun Get() {
List.clear()
val queueList = ArrayList<QueueTable>()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val queueTable = QueueTable(
resultSet.getLong("index").toUInt(),
resultSet.getString("Date_Time"),
resultSet.getString("Source"),
resultSet.getString("Type"),
resultSet.getString("Message"),
resultSet.getString("SB_TAGS"),
resultSet.getString("BroadcastZones"),
resultSet.getInt("Repeat").toUInt(),
resultSet.getString("Language")
)
queueList.add(queueTable)
List.add(queueTable)
}
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName} : ${e.message}" as Any)
}
}
override fun Add(data: QueueTable): Boolean {
try {
val statement = connection.prepareStatement(
"INSERT INTO ${super.dbName} (Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
)
statement?.setString(1, data.Date_Time)
statement?.setString(2, data.Source)
statement?.setString(3, data.Type)
statement?.setString(4, data.Message)
statement?.setString(5, data.SB_TAGS)
statement?.setString(6, data.BroadcastZones)
statement?.setInt(7, data.Repeat.toInt())
statement?.setString(8, data.Language)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("QueueTable added: ${data.Message}" as Any)
return true
} else {
Logger.warn("No QueueTable entry added for: ${data.Message}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding QueueTable entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<QueueTable>): Boolean {
try {
connection.autoCommit = false
val sql =
"INSERT INTO ${super.dbName} (Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (qt in data) {
statement.setString(1, qt.Date_Time)
statement.setString(2, qt.Source)
statement.setString(3, qt.Type)
statement.setString(4, qt.Message)
statement.setString(5, qt.SB_TAGS)
statement.setString(6, qt.BroadcastZones)
statement.setInt(7, qt.Repeat.toInt())
statement.setString(8, qt.Language)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk QueueTable insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
return true
} catch (e: Exception) {
Logger.error("Error adding QueueTable entries: ${e.message}" as Any)
}
return false
}
override fun UpdateByIndex(index: Int, data: QueueTable): Boolean {
throw Exception("Update not supported")
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language) SELECT Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language FROM ${super.dbName} ORDER BY `index` ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language) SELECT Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
Logger.info("${super.dbName} table resorted by index" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by index: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
throw Exception("Import XLSX not supported for QueueTable")
}
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("QueueTable")
val headerRow = sheet.createRow(0)
val headers = arrayOf(
"Index",
"Date_Time",
"Source",
"Type",
"Message",
"SB_TAGS",
"BroadcastZones",
"Repeat",
"Language"
)
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("Date_Time"))
row.createCell(2).setCellValue(resultSet.getString("Source"))
row.createCell(3).setCellValue(resultSet.getString("Type"))
row.createCell(4).setCellValue(resultSet.getString("Message"))
row.createCell(5).setCellValue(resultSet.getString("SB_TAGS"))
row.createCell(6).setCellValue(resultSet.getString("BroadcastZones"))
row.createCell(7).setCellValue(resultSet.getString("Repeat"))
row.createCell(8).setCellValue(resultSet.getString("Language"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting QueueTable, Msg: ${e.message}" }
}
return null
}
}
queuepagingDB = object : dbFunctions<QueuePaging>("queue_paging", connection) {
override fun Create() {
val tabledefinition ="CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"Date_Time VARCHAR(45) NOT NULL," + // Date and time of the entry
"Source VARCHAR(45) NOT NULL," + // Source of the entry
"Type VARCHAR(45) NOT NULL," + // Type of the entry
"Message VARCHAR(512) NOT NULL," + // Message content
"BroadcastZones VARCHAR(1024)" + // Comma-separated soundbank tags
")"
super.Create(tabledefinition)
}
override fun Get() {
List.clear()
val queueList = ArrayList<QueuePaging>()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val queuePaging = QueuePaging(
resultSet.getLong("index").toUInt(),
resultSet.getString("Date_Time"),
resultSet.getString("Source"),
resultSet.getString("Type"),
resultSet.getString("Message"),
resultSet.getString("SB_TAGS"),
)
queueList.add(queuePaging)
List.add(queuePaging)
}
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName} : ${e.message}" as Any)
}
}
override fun Add(data: QueuePaging): Boolean {
try {
val statement = connection.prepareStatement(
"INSERT INTO ${super.dbName} (Date_Time, Source, Type, Message, BroadcastZones) VALUES (?, ?, ?, ?, ?)"
)
statement?.setString(1, data.Date_Time)
statement?.setString(2, data.Source)
statement?.setString(3, data.Type)
statement?.setString(4, data.Message)
statement?.setString(5, data.BroadcastZones)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("QueuePaging added: ${data.Message}" as Any)
return true
} else {
Logger.warn("No QueuePaging entry added for: ${data.Message}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding QueuePaging entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<QueuePaging>): Boolean {
return try {
connection.autoCommit = false
val sql =
"INSERT INTO ${super.dbName} (Date_Time, Source, Type, Message, BroadcastZones) VALUES (?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (qp in data) {
statement.setString(1, qp.Date_Time)
statement.setString(2, qp.Source)
statement.setString(3, qp.Type)
statement.setString(4, qp.Message)
statement.setString(5, qp.BroadcastZones)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk QueuePaging insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
true
} catch (e: Exception) {
Logger.error("Error adding QueuePaging entries: ${e.message}" as Any)
false
}
}
override fun UpdateByIndex(index: Int, data: QueuePaging): Boolean {
throw Exception("Update not supported")
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (Date_Time, Source, Type, Message, SB_TAGS) SELECT Date_Time, Source, Type, Message, SB_TAGS FROM ${super.dbName} ORDER BY `index` ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (Date_Time, Source, Type, Message, SB_TAGS) SELECT Date_Time, Source, Type, Message, SB_TAGS FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
Logger.info("${super.dbName} table resorted by index" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by index: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
throw Exception("Importing QueuePaging from XLSX is not supported")
}
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("QueuePaging")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "Date_Time", "Source", "Type", "Message", "SB_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("Date_Time"))
row.createCell(2).setCellValue(resultSet.getString("Source"))
row.createCell(3).setCellValue(resultSet.getString("Type"))
row.createCell(4).setCellValue(resultSet.getString("Message"))
row.createCell(5).setCellValue(resultSet.getString("SB_TAGS"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting QueuePaging, Msg: ${e.message}" }
}
return null
}
}
soundchannelDB = object : dbFunctions<SoundChannel>("soundchannel", connection) {
override fun Create() {
val tableDefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"channel VARCHAR(45) NOT NULL," + // Channel 01 to Channel 64
"ip VARCHAR(45) NOT NULL" + // IP address or empty string
")"
super.Create(tableDefinition)
// Check if table is empty, if so, populate with 64 channels
try {
val statement = connection.createStatement()
val countResult = statement?.executeQuery("SELECT COUNT(*) AS count FROM ${super.dbName}")
if (countResult?.next() == true) {
val count = countResult.getInt("count")
if (count < max_channel) {
Logger.info("SoundChannel table is empty, populating with default channels" as Any)
Clear()
}
}
} catch (e: Exception) {
Logger.error("Error creating SoundChannel table: ${e.message}" as Any)
}
}
override fun Get() {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName} ORDER BY `index` ")
while (resultSet?.next() == true) {
val channel = SoundChannel(
resultSet.getLong("index").toUInt(),
resultSet.getString("channel"),
resultSet.getString("ip")
)
List.add(channel)
}
} catch (e: Exception) {
Logger.error("Error fetching sound channels: ${e.message}" as Any)
}
}
override fun Add(data: SoundChannel): Boolean {
try {
val statement = connection.prepareStatement("UPDATE ${super.dbName} SET ip = ? WHERE channel = ?")
statement?.setString(1, data.ip)
statement?.setString(2, data.channel)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("SoundChannel updated: ${data.channel} -> ${data.ip}" as Any)
return true
} else {
Logger.warn("No SoundChannel entry updated for: ${data.channel} -> ${data.ip}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating SoundChannel entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<SoundChannel>): Boolean {
return try {
connection.autoCommit = false
val sql = "UPDATE ${super.dbName} SET ip = ? WHERE channel = ?"
val statement = connection.prepareStatement(sql)
for (sc in data) {
statement.setString(1, sc.ip)
statement.setString(2, sc.channel)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk SoundChannel update successful: ${data.size} entries" as Any)
connection.autoCommit = true
true
} catch (e: Exception) {
Logger.error("Error updating SoundChannel entries: ${e.message}" as Any)
false
}
}
override fun UpdateByIndex(index: Int, data: SoundChannel): Boolean {
try {
val statement =
connection.prepareStatement("UPDATE ${super.dbName} SET channel = ?, ip = ? WHERE `index` = ?")
statement?.setString(1, data.channel)
statement?.setString(2, data.ip)
statement?.setLong(3, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("SoundChannel updated at index $index: ${data.channel} -> ${data.ip}" as Any)
return true
} else {
Logger.warn("No SoundChannel entry updated at index $index for: ${data.channel} -> ${data.ip}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating SoundChannel entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (channel, ip) SELECT channel, ip FROM ${super.dbName} ORDER BY `index` ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (channel, ip) SELECT channel, ip FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
Logger.info("${super.dbName} table resorted by index" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by index: ${e.message}" as Any)
}
return false
}
override fun Clear(): Boolean {
try {
val statement = connection.createStatement()
// use TRUNCATE to reset auto increment index
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
Logger.info("${super.dbName} table cleared" as Any)
List.clear()
// create new rows from 1 to 64 with description "Channel 1" to "Channel 64" and empty ip
for (i in 1..max_channel) {
val channel = String.format("Channel %d", i)
val insertStatement =
connection.prepareStatement("INSERT INTO ${super.dbName} (channel, ip) VALUES (?, ?)")
insertStatement?.setString(1, channel)
insertStatement?.setString(2, "")
insertStatement?.executeUpdate()
}
return true
} catch (e: Exception) {
Logger.error("Error clearing soundchannel table: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
try {
val sheet =
workbook.getSheet("SoundChannel") ?: throw Exception("No sheet named 'SoundChannel' found")
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers = arrayOf("Index", "channel", "ip")
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 soundchannel
Clear()
// read each row and insert into database
val _soundChannelList = ArrayList<SoundChannel>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val channel = row.getCell(1)?.stringCellValue ?: continue
val ip = row.getCell(2)?.stringCellValue ?: continue
val soundChannel = SoundChannel(0u, channel, ip)
_soundChannelList.add(soundChannel)
}
// Bulk update IPs for channels
var success = true
for (sc in _soundChannelList) {
if (!soundchannelDB.Add(sc)) {
success = false
}
}
return success
} catch (e: Exception) {
Logger.error { "Error importing SoundChannel, 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("SoundChannel")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "channel", "ip")
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("channel"))
row.createCell(2).setCellValue(resultSet.getString("ip"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting SoundChannel, Msg: ${e.message}" }
}
return null
}
/**
* Delete entry by index, but only clear the IP field
* @param index The index of the entry to delete
* @return true if successful, false otherwise
*/
override fun DeleteByIndex(index: Int): Boolean {
try {
val statement = connection.prepareStatement("UPDATE ${super.dbName} SET ip = '' WHERE `index` = ?")
statement?.setLong(1, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("${super.dbName} IP cleared for index $index" as Any)
return true
} else {
Logger.warn("No ${super.dbName} entry cleared for index $index" as Any)
}
} catch (e: Exception) {
Logger.error("Error clearing ${super.dbName} entry for index $index: ${e.message}" as Any)
}
return false
}
}
logDB = object : dbFunctions<Log>("logs", connection) {
override fun Create() {
val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"datenya VARCHAR(20) NOT NULL," + // format DD/MM/YYYY
"timenya VARCHAR(20) NOT NULL," + // format HH:MM:SS
"machine VARCHAR(45) NOT NULL," +
"description TEXT NOT NULL" +
")"
super.Create(tabledefinition)
}
override fun Get() {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val log = Log(
resultSet.getLong("index").toULong(),
resultSet.getString("datenya"),
resultSet.getString("timenya"),
resultSet.getString("machine"),
resultSet.getString("description")
)
List.add(log)
}
} catch (e: Exception) {
Logger.error("Error fetching ${super.dbName}: ${e.message}" as Any)
}
}
override fun Add(data: Log): Boolean {
try {
val statement =
connection.prepareStatement("INSERT INTO logs (datenya, timenya, machine, description) VALUES (?, ?, ?, ?)")
statement?.setString(1, data.datenya)
statement?.setString(2, data.timenya)
statement?.setString(3, data.machine)
statement?.setString(4, data.description)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info{"Log added : $data"}
return true
} else {
Logger.warn{"Failed to add log entry : $data"}
}
} catch (e: Exception) {
Logger.error{"Error adding log entry: ${e.message}"}
}
return false
}
override fun AddAll(data: ArrayList<Log>): Boolean {
return try {
connection.autoCommit = false
val sql = "INSERT INTO logs (datenya, timenya, machine, description) VALUES (?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (log in data) {
statement.setString(1, log.datenya)
statement.setString(2, log.timenya)
statement.setString(3, log.machine)
statement.setString(4, log.description)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk log insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
true
} catch (e: Exception) {
Logger.error("Error adding log entries: ${e.message}" as Any)
false
}
}
override fun UpdateByIndex(index: Int, data: Log): Boolean {
throw Exception("Update not supported")
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate(
"INSERT INTO temp_${super.dbName} (datenya, timenya, machine, description) " +
"SELECT datenya, timenya, machine, description FROM ${super.dbName} " +
"ORDER BY datenya , timenya , machine "
)
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate(
"INSERT INTO ${super.dbName} (datenya, timenya, machine, description) " +
"SELECT datenya, timenya, machine, description FROM temp_${super.dbName}"
)
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
Logger.info("${super.dbName} table resorted by datenya, timenya, machine" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by datenya, timenya, machine: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
throw Exception("Importing Logs from XLSX is not supported")
}
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("Log")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "datenya", "timenya", "machine", "description")
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("datenya"))
row.createCell(2).setCellValue(resultSet.getString("timenya"))
row.createCell(3).setCellValue(resultSet.getString("machine"))
row.createCell(4).setCellValue(resultSet.getString("description"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting Log, Msg: ${e.message}" }
}
return null
}
}
userDB = object : dbFunctions<UserDB>("newuser", connection){
override fun Create() {
val tableDefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," +
"username VARCHAR(100) NOT NULL," +
"password VARCHAR(100) NOT NULL," +
"location VARCHAR(100) NOT NULL," +
"soundbank_tags TEXT NOT NULL,"+ // Comma-separated soundbank tags
"messagebank_ann_id TEXT NOT NULL,"+ // Comma-separated messagebank announcement index
"broadcastzones TEXT NOT NULL"+ // Comma-separated broadcast zones
")"
super.Create(tableDefinition)
}
override fun Get() {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
while (resultSet?.next() == true) {
val user = UserDB(
resultSet.getLong("index").toUInt(),
resultSet.getString("username"),
resultSet.getString("password"),
resultSet.getString("location"),
resultSet.getString("soundbank_tags"),
resultSet.getString("messagebank_ann_id"),
resultSet.getString("broadcastzones")
)
List.add(user)
}
} catch (e: Exception) {
Logger.error("Error fetching users: ${e.message}" as Any)
}
}
override fun Add(data: UserDB): Boolean {
try {
val statement = connection.prepareStatement("INSERT INTO ${super.dbName} (username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones) VALUES (?, ?, ?, ?, ?, ?)")
statement?.setString(1, data.username)
statement?.setString(2, data.password)
statement?.setString(3, data.location)
statement?.setString(4, data.soundbank_tags)
statement?.setString(5, data.messagebank_ann_id)
statement?.setString(6, data.broadcastzones)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("User added: ${data.username}" as Any)
return true
} else {
Logger.warn("No user entry added for: ${data.username}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding user entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<UserDB>): Boolean {
return try {
connection.autoCommit = false
val sql = "INSERT INTO ${super.dbName} (username, password, location,soundbank_tags, messagebank_ann_id, broadcastzones) VALUES (?, ?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (user in data) {
statement.setString(1, user.username)
statement.setString(2, user.password)
statement.setString(3, user.location)
statement.setString(4, user.soundbank_tags)
statement.setString(5, user.messagebank_ann_id)
statement.setString(6, user.broadcastzones)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk user insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
true
} catch (e: Exception) {
Logger.error("Error adding user entries: ${e.message}" as Any)
false
}
}
override fun UpdateByIndex(index: Int, data: UserDB): Boolean {
try {
val statement = connection.prepareStatement("UPDATE ${super.dbName} SET username = ?, password = ?, location = ?, soundbank_tags = ?, messagebank_ann_id = ?, broadcastzones = ? WHERE `index` = ?")
statement?.setString(1, data.username)
statement?.setString(2, data.password)
statement?.setString(3, data.location)
statement?.setString(4, data.soundbank_tags)
statement?.setString(5, data.messagebank_ann_id)
statement?.setString(6, data.broadcastzones)
statement?.setLong(7, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("User updated at index $index: ${data.username}" as Any)
return true
} else {
Logger.warn("No user entry updated at index $index for: ${data.username}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating user entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_${super.dbName} LIKE ${super.dbName}")
statement?.executeUpdate("INSERT INTO temp_${super.dbName} (username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones) SELECT username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones FROM ${super.dbName} ORDER BY username ")
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
statement?.executeUpdate("INSERT INTO ${super.dbName} (username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones) SELECT username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones FROM temp_${super.dbName}")
statement?.executeUpdate("DROP TABLE temp_${super.dbName}")
Logger.info("${super.dbName} table resorted by index" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by index: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
try {
val sheet = workbook.getSheet("User") ?: throw Exception("No sheet named 'User' found")
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers = arrayOf("Index", "username", "password", "location", "soundbank_tags", "messagebank_ann_id", "broadcastzones")
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 users
Clear()
// read each row and insert into database
val _userList = ArrayList<UserDB>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val username = row.getCell(1)?.stringCellValue ?: continue
val password = row.getCell(2)?.stringCellValue ?: continue
val location = row.getCell(3)?.stringCellValue ?: continue
val soundbank_tags = row.getCell(4)?.stringCellValue ?: continue
val messagebank_ann_id = row.getCell(5)?.stringCellValue ?: continue
val broadcastzones = row.getCell(6)?.stringCellValue ?: continue
val user = UserDB(0u, username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones)
_userList.add(user)
}
return AddAll(_userList)
} catch (e: Exception) {
Logger.error { "Error importing User, 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("User")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "username", "password", "location", "soundbank_tags", "messagebank_ann_id", "broadcastzones")
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("username"))
row.createCell(2).setCellValue(resultSet.getString("password"))
row.createCell(3).setCellValue(resultSet.getString("location"))
row.createCell(4).setCellValue(resultSet.getString("soundbank_tags"))
row.createCell(5).setCellValue(resultSet.getString("messagebank_ann_id"))
row.createCell(6).setCellValue(resultSet.getString("broadcastzones"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting User, Msg: ${e.message}" }
}
return null
}
}
runBlocking {
withContext(Dispatchers.IO) {
logDB.Create()
soundchannelDB.Create()
scheduleDB.Create()
broadcastDB.Create()
messageDB.Create()
soundDB.Create()
languageDB.Create()
queuetableDB.Create()
queuepagingDB.Create()
userDB.Create()
messageDB.Get()
soundDB.Get()
languageDB.Get()
scheduleDB.Get()
broadcastDB.Get()
soundchannelDB.Get()
userDB.Get()
}
}
Logger.info { "Loading MariaDB completed" }
Logger.info { "Soundbank count: ${soundDB.List.size}" }
Logger.info { "Messagebank count: ${messageDB.List.size}" }
Logger.info { "LanguageLink count: ${languageDB.List.size}" }
Logger.info { "Schedulebank count: ${scheduleDB.List.size}" }
Logger.info { "BroadcastZones count: ${broadcastDB.List.size}" }
Logger.info { "SoundChannel count: ${soundchannelDB.List.size}" }
Logger.info { "User count: ${userDB.List.size}" }
} catch (e: Exception) {
Logger.error("Failed to connect to MariaDB: ${e.message}" as Any)
}
}
/**
* Closes the MariaDB connection.
*/
fun close() {
try {
connection.close()
Logger.info("Connection to MariaDB closed" as Any)
} catch (e: Exception) {
Logger.error("Error closing MariaDB connection: ${e.message}" as Any)
}
connected = false
}
/**
* Adds a new log entry to the database with the current date and time.
* @param machine The machine name or identifier.
* @param description The log description.
* @return true if the log was added successfully, false otherwise.
*/
fun Add_Log(machine: String, description: String): Boolean {
val current = java.time.LocalDateTime.now()
val date = current.toLocalDate().toString() // format YYYY-MM-DD
val time = current.toLocalTime().withNano(0).toString() // format HH:MM:SS
val datenya = date.split("-").reversed().joinToString("/") // convert to DD/MM/YYYY
val log = Log(0u, datenya, time, machine, description)
return logDB.Add(log)
}
/**
* Get All Log from database
* @param consumer A Consumer that will receive the list of logs
*/
fun GetLog(consumer: Consumer<ArrayList<Log>>) {
val logList = ArrayList<Log>()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM logs")
while (resultSet?.next() == true) {
val log = Log(
resultSet.getLong("index").toULong(),
resultSet.getString("datenya"),
resultSet.getString("timenya"),
resultSet.getString("machine"),
resultSet.getString("description")
)
logList.add(log)
}
} catch (e: Exception) {
Logger.error("Error fetching logs table: ${e.message}" as Any)
}
consumer.accept(logList)
}
/**
* Get Log from database by date for HTML usage
* @param date The date to filter logs by (format: DD-MM-YYYY)
* @param consumer A Consumer that will receive the list of logs for the specified date
*/
fun GetLogForHtml(date: String, consumer: Consumer<ArrayList<Log>>) {
val logList = ArrayList<Log>()
//println("GetLogForHtml Date: $date" )
if (ValiDateForLogHtml(date)) {
try {
// must convert from DD-MM-YYYY to DD/MM/YYYY, because in database we use DD/MM/YYYY
val adjusteddate = date.replace("-", "/")
val statement = connection.prepareStatement("SELECT * FROM logs WHERE datenya = ?")
statement?.setString(1, adjusteddate)
//println("GetLogForHtml Date: $adjusteddate" )
// println("GetLogForHtml SQL: " +statement?.toString())
val resultSet = statement?.executeQuery()
while (resultSet?.next() == true) {
val log = Log(
resultSet.getLong("index").toULong(),
resultSet.getString("datenya"),
resultSet.getString("timenya"),
resultSet.getString("machine"),
resultSet.getString("description")
)
logList.add(log)
}
} catch (e: Exception) {
Logger.error("Error fetching logs table for date $date: ${e.message}" as Any)
}
}
consumer.accept(logList)
}
/**
* Get Log from database by date and filter for HTML usage
* @param date The date to filter logs by (format: DD-MM-YYYY)
* @param filter The filter string to search in description or machine
* @param consumer A Consumer that will receive the list of logs for the specified date and filter
*/
fun GetLogForHtml(date: String, filter: String, consumer: Consumer<ArrayList<Log>>) {
val logList = ArrayList<Log>()
//println("GetLogForHtml Date: $date Filter: $filter" )
if (ValiDateForLogHtml(date)) {
try {
// must convert from DD-MM-YYYY to DD/MM/YYYY, because in database we use DD/MM/YYYY
val adjusteddate = date.replace("-", "/")
val statement =
connection.prepareStatement("SELECT * FROM logs WHERE datenya = ? AND description LIKE ?")
statement?.setString(1, adjusteddate)
statement?.setString(2, "%$filter%")
//println("GetLogForHtml Date: $adjusteddate , Filter=$filter" )
//println("GetLogForHtml SQL: " +statement?.toString())
val resultSet = statement?.executeQuery()
while (resultSet?.next() == true) {
val log = Log(
resultSet.getLong("index").toULong(),
resultSet.getString("datenya"),
resultSet.getString("timenya"),
resultSet.getString("machine"),
resultSet.getString("description")
)
logList.add(log)
}
} catch (e: Exception) {
Logger.error("Error fetching logs for date $date with filter $filter: ${e.message}" as Any)
}
}
consumer.accept(logList)
}
/**
* Exports the log table to an XLSX workbook for a specific date and optional filter.
* @param logDate The date string in format "dd/MM/yyyy".
* @param logFilter The filter string for the description or machine. If empty, exports all logs for the date.
* @return An XSSFWorkbook containing the filtered log data, or null if an error occurred.
*/
fun Export_Log_XLSX(logDate: String, logFilter: String): XSSFWorkbook? {
try {
val statement = connection.prepareStatement(
if (logFilter.isBlank()) {
"SELECT * FROM logs WHERE datenya = ?"
} else {
"SELECT * FROM logs WHERE datenya = ? AND (description LIKE ?)"
}
)
statement?.setString(1, logDate)
if (!logFilter.isBlank()) {
val filter = "%$logFilter%"
statement?.setString(2, filter)
}
val resultSet = statement?.executeQuery()
val workbook = XSSFWorkbook()
val sheet = workbook.createSheet("Log")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "datenya", "timenya", "machine", "description")
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("datenya"))
row.createCell(2).setCellValue(resultSet.getString("timenya"))
row.createCell(3).setCellValue(resultSet.getString("machine"))
row.createCell(4).setCellValue(resultSet.getString("description"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting Log, Msg: ${e.message}" }
}
return null
}
/**
* Find all city soundbank by tag
* @param tag The tags to search for
* @return a list of Soundbank with Category City and matching tag
*/
fun Find_Soundbank_City(tag: String) : List<Soundbank>{
val lowerTag = tag.lowercase()
return soundDB.List
.filter{ it.Category== Category.City.name }
.filter { it.TAG.lowercase()==lowerTag}
}
fun Find_Soundbank_AirplaneName(tag: String) : List<Soundbank>{
val lowerTag = tag.lowercase()
return soundDB.List
.filter{ it.Category== Category.Airplane_Name.name }
.filter { it.TAG.lowercase()==lowerTag}
}
fun Find_Soundbank_Places(tag: String) : List<Soundbank>{
val lowerTag = tag.lowercase()
return soundDB.List
.filter{ it.Category== Category.Places.name }
.filter { it.TAG.lowercase()==lowerTag}
}
fun Find_Soundbank_Shalat(tag: String) : List<Soundbank>{
val lowerTag = tag.lowercase()
return soundDB.List
.filter{ it.Category== Category.Shalat.name }
.filter { it.TAG.lowercase()==lowerTag}
}
fun Find_Soundbank_Sequence(tag: String) : List<Soundbank>{
val lowerTag = tag.lowercase()
return soundDB.List
.filter{ it.Category== Category.Sequence.name }
.filter { it.TAG.lowercase()==lowerTag}
}
fun Find_Soundbank_Reason(tag: String) : List<Soundbank>{
val lowerTag = tag.lowercase()
return soundDB.List
.filter{ it.Category== Category.Reason.name }
.filter { it.TAG.lowercase()==lowerTag}
}
fun Find_Soundbank_Procedure(tag: String) : List<Soundbank> {
val lowerTag = tag.lowercase()
return soundDB.List
.filter { it.Category == Category.Procedure.name }
.filter { it.TAG.lowercase() == lowerTag }
}
}