diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index 96fdc1b..60716d7 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -1,15 +1,14 @@ - - mariadb + + mysql.8 true - org.mariadb.jdbc.Driver - jdbc:mariadb://localhost:3306/aas + com.mysql.cj.jdbc.Driver + jdbc:mysql://localhost:3306/aas - $ProjectFileDir$ diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml index fe91d0d..269c758 100644 --- a/.idea/sqldialects.xml +++ b/.idea/sqldialects.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/src/Main.kt b/src/Main.kt index f1dc4f0..bd32445 100644 --- a/src/Main.kt +++ b/src/Main.kt @@ -5,6 +5,7 @@ import com.sun.jna.Platform import commandServer.TCP_Android_Command_Server import content.Language import content.VoiceType +import database.Log import database.MariaDB import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -19,7 +20,7 @@ import kotlin.concurrent.fixedRateTimer lateinit var db: MariaDB lateinit var audioPlayer: AudioPlayer val StreamerOutputs: MutableMap = HashMap() -const val version = "0.0.1 (23/09/2025)" +const val version = "0.0.2 (23/09/2025)" // dipakai untuk pilih voice type, bisa diganti via web nanti var selected_voice = VoiceType.VOICE_1.name @@ -76,14 +77,15 @@ fun main() { val androidserver = TCP_Android_Command_Server() androidserver.StartTcpServer(5003){ Logger.info { it } - db.Add_Log("ANDROID", it) + + db.logDB.Add(Log.NewLog("ANDROID", it)) } val barixserver = TCP_Barix_Command_Server() barixserver.StartTcpServer { cmd -> Logger.info { cmd } val _streamer = StreamerOutputs[cmd.ipaddress] - val _sc = db.SoundChannelList.find { it.ip == cmd.ipaddress } + val _sc = db.soundchannelDB.List.find { it.ip == cmd.ipaddress } if (_streamer == null) { // belum create BarixConnection untuk ipaddress ini Logger.info { "New Streamer Output connection from ${cmd.ipaddress}" } diff --git a/src/MainExtension01.kt b/src/MainExtension01.kt index 534c2c3..191023a 100644 --- a/src/MainExtension01.kt +++ b/src/MainExtension01.kt @@ -39,7 +39,7 @@ class MainExtension01 { val validchannels = bz // check apakah tiap zone ada di database broadcast zones .filter { z1 -> - db.BroadcastZoneList.find { z2 -> z2.SoundChannel == z1 } != null + db.broadcastDB.List.find { z2 -> z2.SoundChannel == z1 } != null } // check apakah tiap zone ada di SoundChannelList dan Online .filter { z3 -> @@ -75,7 +75,7 @@ class MainExtension01 { fun Get_MessageBank_by_id(id: Int, languages: List = urutan_bahasa): ArrayList { val mb_list = ArrayList() languages.forEach { lang -> - db.MessagebankList.find { mb -> mb.ANN_ID == id.toUInt() && mb.Language == lang && mb.Voice_Type == selected_voice } + db.messageDB.List.find { mb -> mb.ANN_ID == id.toUInt() && mb.Language == lang && mb.Voice_Type == selected_voice } ?.let { mb_list.add(it) } @@ -169,7 +169,7 @@ class MainExtension01 { return } // dapatkan soundbank array berdasarkan VoiceType dan Language - val sb = db.SoundbankList + val sb = db.soundDB.List .filter { it.VoiceType == mb.Voice_Type } .filter { it.Language == mb.Language } if (sb.isEmpty()) { @@ -479,7 +479,8 @@ class MainExtension01 { * Read and process Queue_Paging table. */ fun Read_Queue_Paging(){ - for (qp in db.Read_Queue_Paging()) { + db.queuepagingDB.Get() + for (qp in db.queuepagingDB.List) { if (qp.BroadcastZones.isNotBlank()) { val zz = qp.BroadcastZones.split(";") if (AllBroadcastZonesValid(zz)) { @@ -496,12 +497,12 @@ class MainExtension01 { "Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}" Logger.info { logmessage } db.Add_Log("AAS", logmessage) - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) return } else { // file tidak valid, delete from queue paging - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.Add_Log( "AAS", "Cancelled paging message with index ${qp.index} due to invalid audio file" @@ -552,7 +553,7 @@ class MainExtension01 { "Broadcast started SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}" Logger.info { logmsg } db.Add_Log("AAS", logmsg) - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) } else { db.Add_Log( "AAS", @@ -565,13 +566,13 @@ class MainExtension01 { }, { err -> - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.Add_Log("AAS", err) } ) } else { // tidak ada messagebank dengan ann_id ini, delete from queue paging - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.Add_Log( "AAS", "Cancelled Shalat message with index ${qp.index} due to ANN_ID $ann_id not found in Messagebank" @@ -580,7 +581,7 @@ class MainExtension01 { } } else { // invalid ann_id, delete from queue paging - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.Add_Log( "AAS", "Cancelled Shalat message with index ${qp.index} due to invalid ANN_ID" @@ -590,7 +591,7 @@ class MainExtension01 { } } else { // ada broadcast zone yang tidak valid, delete from queue paging - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.Add_Log( "AAS", "Cancelled paging message with index ${qp.index} due to invalid broadcast zone" @@ -598,7 +599,7 @@ class MainExtension01 { } } else { // invalid broadcast zone, delete from queue paging - db.Delete_Queue_Paging_by_index(qp.index) + db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.Add_Log("AAS", "Cancelled paging message with index ${qp.index} due to empty broadcast zone") } } @@ -609,7 +610,8 @@ class MainExtension01 { * Read and process Queue_Table table. */ fun Read_Queue_Table(){ - db.Read_Queue_Table().forEach { qa -> + db.queuetableDB.Get() + db.queuetableDB.List.forEach { qa -> if (qa.BroadcastZones.isNotEmpty()) { val zz = qa.BroadcastZones.split(";") if (AllBroadcastZonesValid(zz)) { @@ -645,7 +647,7 @@ class MainExtension01 { "AAS", "Cancelled SOUNDBANK message with index ${qa.index} due to missing or invalid ANN_ID in SB_TAGS" ) - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) return@forEach } // sampe sini punya ann_id valid @@ -680,7 +682,7 @@ class MainExtension01 { "Broadcast started SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}" Logger.info { logmsg } db.Add_Log("AAS", logmsg) - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) } } @@ -690,12 +692,12 @@ class MainExtension01 { { err -> db.Add_Log("AAS", err) - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) }) } } else { // tidak ada messagebank dengan ann_id ini, delete from queue table - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.Add_Log( "AAS", "Cancelled SOUNDBANK message with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank" @@ -735,7 +737,7 @@ class MainExtension01 { "Broadcast started TIMER message with generated file '$targetfile' to zones: ${qa.BroadcastZones}" Logger.info { logmsg } db.Add_Log("AAS", logmsg) - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) } } db.Add_Log("AAS", message) @@ -744,13 +746,13 @@ class MainExtension01 { { err -> db.Add_Log("AAS", err) - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) }) } } else { // tidak ada messagebank dengan ann_id ini, delete from queue table - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.Add_Log( "AAS", "Cancelled TIMER with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank" @@ -758,7 +760,7 @@ class MainExtension01 { } } else { // invalid ann_id, delete from queue table - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.Add_Log( "AAS", "Cancelled TIMER with index ${qa.index} due to invalid ANN_ID" @@ -769,7 +771,7 @@ class MainExtension01 { } } else { // ada broadcast zone yang tidak valid, delete from queue table - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.Add_Log( "AAS", "Cancelled table message with index ${qa.index} due to invalid broadcast zone" @@ -777,7 +779,7 @@ class MainExtension01 { } } else { // invalid broadcast zone, delete from queue table - db.Delete_Queue_Table_by_index(qa.index) + db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.Add_Log("AAS", "Cancelled table message with index ${qa.index} due to empty broadcast zone") } } @@ -794,7 +796,7 @@ class MainExtension01 { // detik harus 00 if (localtime.second != 0) return val timestring = timeformat2.format(localtime) - val sch = db.SchedulebankList.filter { + val sch = db.scheduleDB.List.filter { it.Time == timestring && it.Enable } // tidak ada schedule dengan time sekarang dan enable=true diff --git a/src/database/BroadcastZones.kt b/src/database/BroadcastZones.kt index a952ed6..b766d3c 100644 --- a/src/database/BroadcastZones.kt +++ b/src/database/BroadcastZones.kt @@ -1,4 +1,4 @@ package database @Suppress("unused") -data class BroadcastZones(var index: UInt, var description: String, var SoundChannel: String, var Box: String, var Relay: String) +data class BroadcastZones(var index: UInt, var description: String, var SoundChannel: String, var id: String, var bp: String) diff --git a/src/database/BroadcastZonesHtml.kt b/src/database/BroadcastZonesHtml.kt new file mode 100644 index 0000000..8bda430 --- /dev/null +++ b/src/database/BroadcastZonesHtml.kt @@ -0,0 +1,3 @@ +package database + +data class BroadcastZonesHtml(var index: UInt, var description: String, var SoundChannel: String, var Box: String, var Relay: String) diff --git a/src/database/Log.kt b/src/database/Log.kt index 6401407..932e471 100644 --- a/src/database/Log.kt +++ b/src/database/Log.kt @@ -7,4 +7,17 @@ data class Log( val timenya: String, val machine: String, val description : String -) +){ + companion object{ + + fun NewLog( + machine: String, + description: String + ) : Log { + 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 + return Log(0u, date, time, machine, description) + } + } +} diff --git a/src/database/MariaDB.kt b/src/database/MariaDB.kt index 18c8905..670d171 100644 --- a/src/database/MariaDB.kt +++ b/src/database/MariaDB.kt @@ -20,7 +20,7 @@ import java.util.function.Consumer * @property username The username for the database connection. * @property password The password for the database connection. */ -@Suppress("unused") +@Suppress("unused", "SqlSourceToSinkFlow") class MariaDB( address: String = "localhost", port: Int = 3306, @@ -28,16 +28,20 @@ class MariaDB( username: String = "admin", password: String = "admin" ) { - private var connection: Connection? = null var connected: Boolean = false - var SoundbankList: ArrayList = ArrayList() - var MessagebankList: ArrayList = ArrayList() - var LanguageLinkList: ArrayList = ArrayList() - var SchedulebankList: ArrayList = ArrayList() - var BroadcastZoneList: ArrayList = ArrayList() - var SoundChannelList: ArrayList = ArrayList() - var QueuePagingList: ArrayList = ArrayList() - var QueueTableList: ArrayList = ArrayList() + + + lateinit var connection: Connection + lateinit var soundDB: dbFunctions + lateinit var messageDB: dbFunctions + lateinit var languageDB: dbFunctions + lateinit var scheduleDB: dbFunctions + lateinit var broadcastDB: dbFunctions + lateinit var queuetableDB: dbFunctions + lateinit var queuepagingDB: dbFunctions + lateinit var soundchannelDB: dbFunctions + lateinit var logDB: dbFunctions + lateinit var userDB: dbFunctions companion object { fun ValidDate(date: String): Boolean { @@ -77,39 +81,1980 @@ class MariaDB( username, password ) as Connection - Logger.info("Connected to MariaDB" as Any) + Logger.info("Connected to MySQL" as Any) connected = true + soundDB = object : dbFunctions("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): 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() + 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", 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): 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() + 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("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): 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() + 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", 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): 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() + 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", 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): 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() + 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("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() + 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): 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("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() + 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): 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", 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 == 0) { + 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): 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 01" to "Channel 64" and empty ip + for (i in 1..64) { + val channel = String.format("Channel %02d", 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() + 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("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.datenya $data.timenya] [$data.machine] $data.description" as Any) + return true + } else { + Logger.warn("No log entry added for: [$data.datenya $data.timenya] [$data.machine] $data.description" as Any) + } + } catch (e: Exception) { + Logger.error("Error adding log entry: ${e.message}" as Any) + } + return false + } + + override fun AddAll(data: ArrayList): 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("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): 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() + 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) { - Create_Log_Table() - Create_SoundChannel_Table() - Create_Schedulebank_Table() - Create_BroadcastZones_Table() - Create_Messagebank_Table() - Create_Soundbank_Table() - Create_LanguageLink_Table() - Create_Queue_Table() - Create_Queue_Paging_Table() + logDB.Create() + soundchannelDB.Create() + scheduleDB.Create() + broadcastDB.Create() + messageDB.Create() + soundDB.Create() + languageDB.Create() + queuetableDB.Create() + queuepagingDB.Create() + userDB.Create() - Reload_Messagebank() - Reload_Soundbank() - Reload_LanguageLink() - Reload_Schedulebank() - GetBroadcastZones() - GetSoundChannel() + messageDB.Get() + soundDB.Get() + languageDB.Get() + scheduleDB.Get() + broadcastDB.Get() + soundchannelDB.Get() + userDB.Get() } } Logger.info { "Loading MariaDB completed" } - Logger.info { "Soundbank count: ${SoundbankList.size}" } - Logger.info { "Messagebank count: ${MessagebankList.size}" } - Logger.info { "LanguageLink count: ${LanguageLinkList.size}" } - Logger.info { "Schedulebank count: ${SchedulebankList.size}" } - Logger.info { "BroadcastZones count: ${BroadcastZoneList.size}" } - Logger.info { "SoundChannel count: ${SoundChannelList.size}" } + 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) { @@ -122,7 +2067,7 @@ class MariaDB( */ fun close() { try { - connection?.close() + connection.close() Logger.info("Connection to MariaDB closed" as Any) } catch (e: Exception) { @@ -131,54 +2076,119 @@ class MariaDB( connected = false } + /** - * Create Log table if not exists + * 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 Create_Log_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS logs (" + - "`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" + - ")" - ) - Logger.info("Log table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating log table: ${e.message}" as Any) - } + 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) } /** - * Add Log to database - * @param machine The machine name or identifier. - * @param description The description of the log entry. + * Get All Log from database + * @param consumer A Consumer that will receive the list of logs */ - fun Add_Log(machine: String, description: String) { - val currentDate = java.time.LocalDate.now() - val currentTime = java.time.LocalTime.now().withNano(0) // remove nanoseconds for cleaner format - val dateString = currentDate.format(java.time.format.DateTimeFormatter.ofPattern("dd/MM/yyyy")) - val timeString = currentTime.format(java.time.format.DateTimeFormatter.ofPattern("HH:mm:ss")) - + fun GetLog(consumer: Consumer>) { + val logList = ArrayList() try { - val statement = - connection?.prepareStatement("INSERT INTO logs (datenya, timenya, machine, description) VALUES (?, ?, ?, ?)") - statement?.setString(1, dateString) - statement?.setString(2, timeString) - statement?.setString(3, machine) - statement?.setString(4, description) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Log added: [$dateString $timeString] [$machine] $description" as Any) - } else { - Logger.warn("No log entry added for: [$dateString $timeString] [$machine] $description" as Any) + 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 adding log entry: ${e.message}" as Any) + 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>) { + val logList = ArrayList() + //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>) { + val logList = ArrayList() + //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) } /** @@ -189,7 +2199,7 @@ class MariaDB( */ fun Export_Log_XLSX(logDate: String, logFilter: String): XSSFWorkbook? { try { - val statement = connection?.prepareStatement( + val statement = connection.prepareStatement( if (logFilter.isBlank()) { "SELECT * FROM logs WHERE datenya = ?" } else { @@ -229,2014 +2239,7 @@ class MariaDB( return null } - /** - * Create SoundChannel table if not exists - */ - fun Create_SoundChannel_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS soundchannel (" + - "`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 - ")" - ) - Logger.info("SoundChannel table ensured to exist" as Any) - // Check if table is empty, if so, populate with 64 channels - val countResult = statement?.executeQuery("SELECT COUNT(*) AS count FROM soundchannel") - if (countResult?.next() == true) { - val count = countResult.getInt("count") - if (count == 0) { - Logger.info("SoundChannel table is empty, populating with default channels" as Any) - Clear_SoundChannel() - } - } - } catch (e: Exception) { - Logger.error("Error creating SoundChannel table: ${e.message}" as Any) - } - } - /** - * Clears all entries from the soundchannel table in the database and the local list. - */ - fun Clear_SoundChannel(): Boolean { - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE soundchannel") - Logger.info("SoundChannel table cleared" as Any) - SoundChannelList.clear() - // create new rows from 1 to 64 with description "Channel 01" to "Channel 64" and empty ip - for (i in 1..64) { - val channel = String.format("Channel %02d", i) - val insertStatement = - connection?.prepareStatement("INSERT INTO soundchannel (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 - } - fun GetSoundChannel() { - SoundChannelList.clear() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM soundchannel ORDER BY `index` ASC") - while (resultSet?.next() == true) { - val channel = SoundChannel( - resultSet.getLong("index").toUInt(), - resultSet.getString("channel"), - resultSet.getString("ip") - ) - SoundChannelList.add(channel) - } - - } catch (e: Exception) { - Logger.error("Error fetching sound channels: ${e.message}" as Any) - } - } - - /** - * Update SoundChannel IP in database - * @param channel The SoundChannel object containing the channel name and new IP address. - * @return True if the update was successful, false otherwise. - */ - fun Add_SoundChannel(channel: SoundChannel): Boolean { - try { - val statement = connection?.prepareStatement("UPDATE soundchannel SET ip = ? WHERE channel = ?") - statement?.setString(1, channel.ip) - statement?.setString(2, channel.channel) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("SoundChannel updated: ${channel.channel} -> ${channel.ip}" as Any) - return true - } else { - Logger.warn("No SoundChannel entry updated for: ${channel.channel} -> ${channel.ip}" as Any) - } - } catch (e: Exception) { - Logger.error("Error updating SoundChannel entry: ${e.message}" as Any) - } - return false - } - - /** - * Delete SoundChannel IP by index in database (set to empty string) - * @param index The index of the SoundChannel entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_SoundChannel_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("UPDATE soundchannel SET ip = '' WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("SoundChannel IP cleared for index $index" as Any) - return true - } else { - Logger.warn("No SoundChannel entry cleared for index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error clearing SoundChannel entry for index $index: ${e.message}" as Any) - } - return false - } - - - /** - * Resort the soundchannel table, in order to reorder the index after deletions. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_SoundChannel_by_index(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_soundchannel LIKE soundchannel") - statement?.executeUpdate("INSERT INTO temp_soundchannel (channel, ip) SELECT channel, ip FROM soundchannel ORDER BY `index` ASC") - statement?.executeUpdate("TRUNCATE TABLE soundchannel") - statement?.executeUpdate("INSERT INTO soundchannel (channel, ip) SELECT channel, ip FROM temp_soundchannel") - statement?.executeUpdate("DROP TABLE temp_soundchannel") - Logger.info("soundchannel table resorted by index" as Any) - // reload the local list - GetSoundChannel() - return true - } catch (e: Exception) { - Logger.error("Error resorting soundchannel table by index: ${e.message}" as Any) - } - return false - } - - /** - * Updates an existing SoundChannel entry in the database by its index. - * @param index The index of the SoundChannel entry to update. - * @param sc The SoundChannel object with updated values. - * @return True if the update was successful, false otherwise. - */ - fun Update_SoundChannel_by_index(index: UInt, sc: SoundChannel): Boolean { - try { - val statement = - connection?.prepareStatement("UPDATE soundchannel SET channel = ?, ip = ? WHERE `index` = ?") - statement?.setString(1, sc.channel) - statement?.setString(2, sc.ip) - statement?.setLong(3, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("SoundChannel updated at index $index: ${sc.channel} -> ${sc.ip}" as Any) - return true - } else { - Logger.warn("No SoundChannel entry updated at index $index for: ${sc.channel} -> ${sc.ip}" as Any) - } - } catch (e: Exception) { - Logger.error("Error updating SoundChannel entry at index $index: ${e.message}" as Any) - } - return false - } - - /** - * Exports the soundchannel table to an XLSX workbook. - * @return An XSSFWorkbook containing the soundchannel data, or null if an error occurred. - */ - fun Export_SoundChannel_XLSX(): XSSFWorkbook? { - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM soundchannel") - 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 - } - - /** - * Imports soundchannel entries from an XLSX workbook. - * @param workbook The XSSFWorkbook containing the soundchannel data. - * @return True if the import was successful, false otherwise. - */ - fun Import_SoundChannel_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_SoundChannel() - // read each row and insert into database - val _soundChannelList = ArrayList() - 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 (!Add_SoundChannel(sc)) { - success = false - } - } - return success - } catch (e: Exception) { - Logger.error { "Error importing SoundChannel, Msg: ${e.message}" } - } - return false - } - - /** - * Get All Log from database - * @param consumer A Consumer that will receive the list of logs - */ - fun GetLog(consumer: Consumer>) { - val logList = ArrayList() - 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: ${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>) { - val logList = ArrayList() - //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 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>) { - val logList = ArrayList() - //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) - } - - /** - * Create Schedulebank table if not exists - */ - fun Create_Schedulebank_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS schedulebank (" + - "`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) - ")" - ) - Logger.info("Schedulebank table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating Schedulebank table: ${e.message}" as Any) - } - } - - /** - * Reloads the ScheduleBank list from the database. - */ - fun Reload_Schedulebank() { - SchedulebankList.clear() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM schedulebank") - 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") - ) - SchedulebankList.add(schedulebank) - } - } catch (e: Exception) { - Logger.error("Error fetching schedulebanks: ${e.message}" as Any) - } - } - - /** - * Adds a new schedulebank entry to the database. - * @param schedulebank The ScheduleBank object to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_Schedulebank(schedulebank: ScheduleBank): Boolean { - if (!ValidDate(schedulebank.Day)) { - Logger.error("Error adding schedulebank entry: Invalid date format ${schedulebank.Day}" as Any) - return false - } - if (!ValidTime(schedulebank.Time)) { - Logger.error("Error adding schedulebank entry: Invalid time format ${schedulebank.Time}" as Any) - return false - } - try { - val statement = - connection?.prepareStatement("INSERT INTO schedulebank (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)") - statement?.setString(1, schedulebank.Description) - statement?.setString(2, schedulebank.Day) - statement?.setString(3, schedulebank.Time) - statement?.setString(4, schedulebank.Soundpath) - statement?.setInt(5, schedulebank.Repeat.toInt()) - statement?.setBoolean(6, schedulebank.Enable) - statement?.setString(7, schedulebank.BroadcastZones) - statement?.setString(8, schedulebank.Language) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Schedulebank added: ${schedulebank.Description}" as Any) - return true - } else { - Logger.warn("No schedulebank entry added for: ${schedulebank.Description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error adding schedulebank entry: ${e.message}" as Any) - } - return false - } - - /** - * Adds multiple schedulebank entries to the database using bulk insert. - * @param schedulebankList ArrayList of ScheduleBank objects to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_Schedulebank(schedulebankList: ArrayList): Boolean { - if (schedulebankList.isNotEmpty()) { - try { - if (connection != null) { - connection!!.autoCommit = false - val sql = - "INSERT INTO schedulebank (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" - val statement = connection!!.prepareStatement(sql) - for (sb in schedulebankList) { - 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: ${schedulebankList.size} entries" as Any) - connection!!.autoCommit = true - return true - } - } catch (e: Exception) { - Logger.error("Error adding schedulebank entries: ${e.message}" as Any) - } - } - return false - } - - /** - * Updates an existing schedulebank entry in the database by its index. - * @param index The index of the schedulebank entry to update. - * @param schedulebank The ScheduleBank object with updated values. - * @return True if the update was successful, false otherwise. - */ - fun Update_Schedulebank_by_index(index: UInt, schedulebank: ScheduleBank): Boolean { - if (!ValidDate(schedulebank.Day)) { - Logger.error("Error updating schedulebank entry: Invalid date format ${schedulebank.Day}" as Any) - return false - } - if (!ValidTime(schedulebank.Time)) { - Logger.error("Error updating schedulebank entry: Invalid time format ${schedulebank.Time}" as Any) - return false - } - try { - val statement = - connection?.prepareStatement("UPDATE schedulebank SET Description = ?, Day = ?, Time = ?, Soundpath = ?, Repeat = ?, Enable = ?, BroadcastZones = ?, Language = ? WHERE `index` = ?") - statement?.setString(1, schedulebank.Description) - statement?.setString(2, schedulebank.Day) - statement?.setString(3, schedulebank.Time) - statement?.setString(4, schedulebank.Soundpath) - statement?.setInt(5, schedulebank.Repeat.toInt()) - statement?.setBoolean(6, schedulebank.Enable) - statement?.setString(7, schedulebank.BroadcastZones) - statement?.setString(8, schedulebank.Language) - statement?.setLong(9, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Schedulebank updated at index $index: ${schedulebank.Description}" as Any) - return true - } else { - Logger.warn("No schedulebank entry updated at index $index for: ${schedulebank.Description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error updating schedulebank entry at index $index: ${e.message}" as Any) - } - return false - } - - /** - * Deletes a schedulebank entry by its index. - * @param index The index of the schedulebank entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_Schedulebank_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("DELETE FROM schedulebank WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Deleted $rowsAffected row(s) from schedulebank with index $index" as Any) - return true - } else { - Logger.warn("No rows deleted from schedulebank with index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error deleting from schedulebank with index $index: ${e.message}" as Any) - } - return false - } - - /** - * Resort the schedulebank table, in order to reorder the index after deletions, and sort ascending by Day and Time. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_Schedulebank_by_Day_Time(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_schedulebank LIKE schedulebank") - statement?.executeUpdate("INSERT INTO temp_schedulebank (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) SELECT Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language FROM schedulebank ORDER BY Day ASC, Time ASC") - statement?.executeUpdate("TRUNCATE TABLE schedulebank") - statement?.executeUpdate("INSERT INTO schedulebank (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) SELECT Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language FROM temp_schedulebank") - statement?.executeUpdate("DROP TABLE temp_schedulebank") - Logger.info("schedulebank table resorted by Day and Time" as Any) - // reload the local list - Reload_Schedulebank() - return true - } catch (e: Exception) { - Logger.error("Error resorting schedulebank table by Day and Time: ${e.message}" as Any) - } - return false - } - - /** - * Clears all entries from the schedulebank table in the database and the local list. - */ - fun Clear_Schedulebank(): Boolean { - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE schedulebank") - Logger.info("Schedulebank table cleared" as Any) - SchedulebankList.clear() - return true - } catch (e: Exception) { - Logger.error("Error clearing schedulebank table: ${e.message}" as Any) - } - return false - } - - /** - * Exports the schedulebank table to an XLSX workbook. - * @return An XSSFWorkbook containing the schedulebank data, or null if an error occurred. - */ - fun Export_Schedulebank_XLSX(): XSSFWorkbook? { - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM schedulebank") - 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 - } - - /** - * Imports schedulebank entries from an XLSX workbook. - * @param workbook The XSSFWorkbook containing the schedulebank data. - * @return True if the import was successful, false otherwise. - */ - fun Import_Schedulebank_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_Schedulebank() - // read each row and insert into database - val _schedulebankList = ArrayList() - 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 Add_Schedulebank(_schedulebankList) - } catch (e: Exception) { - Logger.error { "Error importing Schedulebank, Msg: ${e.message}" } - } - return false - } - - /** - * Create LanguageLink table if not exists - */ - fun Create_LanguageLink_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS languagelinking (" + - "`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) - ")" - ) - Logger.info("LanguageLink table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating LanguageLink table: ${e.message}" as Any) - } - } - - /** - * Reloads the language link list from the database. - */ - fun Reload_LanguageLink() { - LanguageLinkList.clear() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM languagelinking") - while (resultSet?.next() == true) { - val languageLink = LanguageLink( - resultSet.getLong("index").toUInt(), - resultSet.getString("TAG"), - resultSet.getString("Language") - ) - LanguageLinkList.add(languageLink) - } - } catch (e: Exception) { - Logger.error("Error fetching language links: ${e.message}" as Any) - } - } - - /** - * Adds a new language link entry to the database. - * @param languageLink The LanguageLink object to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_LanguageLink(languageLink: LanguageLink): Boolean { - try { - val statement = connection?.prepareStatement("INSERT INTO languagelinking (TAG, Language) VALUES (?, ?)") - statement?.setString(1, languageLink.TAG) - statement?.setString(2, languageLink.Language) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Language link added: ${languageLink.TAG} -> ${languageLink.Language}" as Any) - return true - } else { - Logger.warn("No language link entry added for: ${languageLink.TAG} -> ${languageLink.Language}" as Any) - } - } catch (e: Exception) { - Logger.error("Error adding language link entry: ${e.message}" as Any) - } - return false - } - - /** - * Adds multiple language link entries to the database using bulk insert. - * @param languageLinkList ArrayList of LanguageLink objects to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_LanguageLink(languageLinkList: ArrayList): Boolean { - if (languageLinkList.isNotEmpty()) { - try { - if (connection != null) { - connection!!.autoCommit = false - val sql = "INSERT INTO languagelinking (TAG, Language) VALUES (?, ?)" - val statement = connection!!.prepareStatement(sql) - for (ll in languageLinkList) { - statement.setString(1, ll.TAG) - statement.setString(2, ll.Language) - statement.addBatch() - } - statement.executeBatch() - connection!!.commit() - Logger.info("Bulk languagelinking insert successful: ${languageLinkList.size} entries" as Any) - connection!!.autoCommit = true - return true - } - } catch (e: Exception) { - Logger.error("Error adding languagelinking entries: ${e.message}" as Any) - } - } - return false - } - - - /** - * Updates an existing language link entry in the database by its index. - * @param index The index of the language link entry to update. - * @param languageLink The LanguageLink object with updated values. - * @return True if the update was successful, false otherwise. - */ - fun Update_LanguageLink_by_index(index: UInt, languageLink: LanguageLink): Boolean { - try { - val statement = - connection?.prepareStatement("UPDATE languagelinking SET TAG = ?, Language = ? WHERE `index` = ?") - statement?.setString(1, languageLink.TAG) - statement?.setString(2, languageLink.Language) - statement?.setLong(3, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Language link updated at index $index: ${languageLink.TAG} -> ${languageLink.Language}" as Any) - return true - } else { - Logger.warn("No language link entry updated at index $index for: ${languageLink.TAG} -> ${languageLink.Language}" as Any) - } - } catch (e: Exception) { - Logger.error("Error updating language link entry at index $index: ${e.message}" as Any) - } - return false - } - - /** - * Deletes a language link entry by its index. - * @param index The index of the language link entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_LanguageLink_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("DELETE FROM languagelinking WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Deleted $rowsAffected row(s) from languagelinking with index $index" as Any) - return true - } else { - Logger.warn("No rows deleted from languagelinking with index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error deleting from languagelinking with index $index: ${e.message}" as Any) - } - return false - } - - /** - * Resort the language link table, in order to reorder the index after deletions, and sort ascending by TAG. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_LanguageLink_by_TAG(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_languagelinking LIKE languagelinking") - statement?.executeUpdate("INSERT INTO temp_languagelinking (TAG, Language) SELECT TAG, Language FROM languagelinking ORDER BY TAG ASC") - statement?.executeUpdate("TRUNCATE TABLE languagelinking") - statement?.executeUpdate("INSERT INTO languagelinking (TAG, Language) SELECT TAG, Language FROM temp_languagelinking") - statement?.executeUpdate("DROP TABLE temp_languagelinking") - Logger.info("languagelinking table resorted by TAG" as Any) - // reload the local list - Reload_LanguageLink() - return true - } catch (e: Exception) { - Logger.error("Error resorting languagelinking table by TAG: ${e.message}" as Any) - } - return false - } - - /** - * Clears all entries from the language link table in the database and the local list. - */ - fun Clear_LanguageLink(): Boolean { - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE languagelinking") - Logger.info("languagelinking table cleared" as Any) - LanguageLinkList.clear() - return true - } catch (e: Exception) { - Logger.error("Error clearing languagelinking table: ${e.message}" as Any) - } - return false - } - - /** - * Exports the languagelink table to an XLSX workbook. - * @return An XSSFWorkbook containing the languagelink data, or null if an error occurred. - */ - fun Export_LanguageLink_XLSX(): XSSFWorkbook? { - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM languagelinking") - 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 - } - - /** - * Imports languagelink entries from an XLSX workbook. - * @param workbook The XSSFWorkbook containing the languagelink data. - * @return True if the import was successful, false otherwise. - */ - fun Import_LanguageLink_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_LanguageLink() - // read each row and insert into database - val _languageLinkList = ArrayList() - 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 Add_LanguageLink(_languageLinkList) - } catch (e: Exception) { - Logger.error { "Error importing LanguageLink, Msg: ${e.message}" } - } - return false - } - - /** - * Create Soundbank table if not exists - */ - fun Create_Soundbank_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS soundbank (" + - "`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 - ")" - ) - Logger.info("Soundbank table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating Soundbank table: ${e.message}" as Any) - } - } - - /** - * Reloads the soundbank list from the database. - */ - fun Reload_Soundbank() { - - SoundbankList.clear() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM soundbank") - 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") - ) - SoundbankList.add(soundbank) - } - } catch (e: Exception) { - Logger.error("Error fetching soundbanks: ${e.message}" as Any) - } - } - - /** - * Adds a new soundbank entry to the database. - * @param soundbank The Soundbank object to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_Soundbank(soundbank: Soundbank): Boolean { - try { - val statement = - connection?.prepareStatement("INSERT INTO soundbank (Description, TAG, Category, Language, VoiceType, Path) VALUES (?, ?, ?, ?, ?, ?)") - statement?.setString(1, soundbank.Description) - statement?.setString(2, soundbank.TAG) - statement?.setString(3, soundbank.Category) - statement?.setString(4, soundbank.Language) - statement?.setString(5, soundbank.VoiceType) - statement?.setString(6, soundbank.Path) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Soundbank added: ${soundbank.Description}" as Any) - return true - } else { - Logger.warn("No soundbank entry added for: ${soundbank.Description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error adding soundbank entry: ${e.message}" as Any) - } - return false - } - - /** - * Adds multiple soundbank entries to the database using bulk insert. - * @param soundbank Vararg of Soundbank objects to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_Soundbank(soundbank: ArrayList): Boolean { - if (soundbank.isNotEmpty()) { - // use mysql bulk insert - try { - if (connection != null) { - connection!!.autoCommit = false - val sql = - "INSERT INTO soundbank (Description, TAG, Category, Language, VoiceType, Path) VALUES (?, ?, ?, ?, ?, ?)" - val statement = connection!!.prepareStatement(sql) - for (sb in soundbank) { - 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: ${soundbank.size} entries" as Any) - connection!!.autoCommit = true - return true - } - } catch (e: Exception) { - Logger.error("Error adding soundbank entries: ${e.message}" as Any) - } - } - return false - } - - /** - * Updates an existing soundbank entry in the database by its index. - * @param index The index of the soundbank entry to update. - * @param soundbank The Soundbank object with updated values. - * @return True if the update was successful, false otherwise. - */ - fun Update_Soundbank_by_index(index: UInt, soundbank: Soundbank): Boolean { - try { - val statement = - connection?.prepareStatement("UPDATE soundbank SET Description = ?, TAG = ?, Category = ?, Language = ?, VoiceType = ?, Path = ? WHERE `index` = ?") - statement?.setString(1, soundbank.Description) - statement?.setString(2, soundbank.TAG) - statement?.setString(3, soundbank.Category) - statement?.setString(4, soundbank.Language) - statement?.setString(5, soundbank.VoiceType) - statement?.setString(6, soundbank.Path) - statement?.setLong(7, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Soundbank updated at index $index: ${soundbank.Description}" as Any) - return true - } else { - Logger.warn("No soundbank entry updated at index $index for: ${soundbank.Description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error updating soundbank entry at index $index: ${e.message}" as Any) - } - return false - } - - /** - * Retrieves a soundbank entry by its index. - * @param index The index of the soundbank entry to retrieve. - * @return The Soundbank object if found, null otherwise. - */ - fun Get_Soundbank_by_index(index: UInt): Soundbank? { - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM soundbank 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 soundbank with index $index" as Any) - } - return null - } - - /** - * Deletes a soundbank entry by its index. - * @param index The index of the soundbank entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_Soundbank_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("DELETE FROM soundbank WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Deleted $rowsAffected row(s) from soundbank with index $index" as Any) - return true - } else { - Logger.warn("No rows deleted from soundbank with index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error deleting from soundbank with index $index: ${e.message}" as Any) - } - return false - } - - /** - * Resort the soundbank table, in order to reorder the index after deletions, and sort ascending by Description. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_Soundbank_by_Description(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_soundbank LIKE soundbank") - statement?.executeUpdate("INSERT INTO temp_soundbank (Description, TAG, Category, Language, VoiceType, Path) SELECT Description, TAG, Category, Language, VoiceType, Path FROM soundbank ORDER BY Description ASC") - statement?.executeUpdate("TRUNCATE TABLE soundbank") - statement?.executeUpdate("INSERT INTO soundbank (Description, TAG, Category, Language, VoiceType, Path) SELECT Description, TAG, Category, Language, VoiceType, Path FROM temp_soundbank") - statement?.executeUpdate("DROP TABLE temp_soundbank") - Logger.info("soundbank table resorted by Description" as Any) - // reload the local list - Reload_Soundbank() - return true - } catch (e: Exception) { - Logger.error("Error resorting soundbank table by Description: ${e.message}" as Any) - } - return false - } - - /** - * Clears all entries from the soundbank table in the database and the local list. - */ - fun Clear_Soundbank(): Boolean { - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE soundbank") - Logger.info("Soundbank table cleared" as Any) - SoundbankList.clear() - return true - } catch (e: Exception) { - Logger.error("Error clearing soundbank table: ${e.message}" as Any) - } - return false - } - - /** - * Exports the soundbank table to an XLSX workbook. - * @return An XSSFWorkbook containing the soundbank data, or null if an error occurred. - */ - fun Export_Soundbank_XLSX(): XSSFWorkbook? { - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM soundbank") - 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 - } - - fun Import_Soundbank_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_Soundbank() - // read each row and insert into database - val _soundbankList = ArrayList() - 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 Add_Soundbank(_soundbankList) - } catch (e: Exception) { - Logger.error { "Error importing Soundbank, Msg: ${e.message}" } - } - return false - } - - /** - * Create Messagebank table if not exists - */ - fun Create_Messagebank_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS messagebank (" + - "`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 - ")" - ) - Logger.info("Messagebank table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating Messagebank table: ${e.message}" as Any) - } - } - - /** - * Reloads the messagebank list from the database. - */ - fun Reload_Messagebank() { - MessagebankList.clear() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM messagebank") - 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") - ) - - MessagebankList.add(messagebank) - } - } catch (e: Exception) { - Logger.error("Error fetching messagebanks: ${e.message}" as Any) - } - } - - /** - * Adds a new messagebank entry to the database. - * @param messagebank The Messagebank object to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_Messagebank(messagebank: Messagebank): Boolean { - try { - val statement = - connection?.prepareStatement("INSERT INTO messagebank (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) VALUES (?, ?, ?, ?, ?, ?)") - statement?.setString(1, messagebank.Description) - statement?.setString(2, messagebank.Language) - statement?.setInt(3, messagebank.ANN_ID.toInt()) - statement?.setString(4, messagebank.Voice_Type) - statement?.setString(5, messagebank.Message_Detail) - statement?.setString(6, messagebank.Message_TAGS) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Messagebank added: ${messagebank.Description}" as Any) - return true - } else { - Logger.warn("No messagebank entry added for: ${messagebank.Description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error adding messagebank entry: ${e.message}" as Any) - } - return false - } - - /** - * Adds multiple messagebank entries to the database using bulk insert. - * @param messagebankList ArrayList of Messagebank objects to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_Messagebank(messagebankList: ArrayList): Boolean { - if (messagebankList.isNotEmpty()) { - try { - if (connection != null) { - connection!!.autoCommit = false - val sql = - "INSERT INTO messagebank (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) VALUES (?, ?, ?, ?, ?, ?)" - val statement = connection!!.prepareStatement(sql) - for (mb in messagebankList) { - 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: ${messagebankList.size} entries" as Any) - connection!!.autoCommit = true - return true - } - } catch (e: Exception) { - Logger.error("Error adding messagebank entries: ${e.message}" as Any) - } - } - return false - } - - /** - * Updates an existing messagebank entry in the database by its index. - * @param index The index of the messagebank entry to update. - * @param messagebank The Messagebank object with updated values. - * @return True if the update was successful, false otherwise. - */ - fun Update_Messagebank_by_index(index: UInt, messagebank: Messagebank): Boolean { - try { - val statement = - connection?.prepareStatement("UPDATE messagebank SET Description = ?, Language = ?, ANN_ID = ?, Voice_Type = ?, Message_Detail = ?, Message_TAGS = ? WHERE `index` = ?") - statement?.setString(1, messagebank.Description) - statement?.setString(2, messagebank.Language) - statement?.setInt(3, messagebank.ANN_ID.toInt()) - statement?.setString(4, messagebank.Voice_Type) - statement?.setString(5, messagebank.Message_Detail) - statement?.setString(6, messagebank.Message_TAGS) - statement?.setLong(7, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Messagebank updated at index $index: ${messagebank.Description}" as Any) - return true - } else { - Logger.warn("No messagebank entry updated at index $index for: ${messagebank.Description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error updating messagebank entry at index $index: ${e.message}" as Any) - } - return false - } - - /** - * Deletes a messagebank entry by its index. - * @param index The index of the messagebank entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_Messagebank_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("DELETE FROM messagebank WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Deleted $rowsAffected row(s) from messagebank with index $index" as Any) - return true - } else { - Logger.warn("No rows deleted from messagebank with index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error deleting from messagebank with index $index: ${e.message}" as Any) - } - return false - } - - /** - * Resort the messagebank table, in order to reorder the index after deletions, and sort ascending by ANN_ID. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_Messagebank_by_ANN_ID(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_messagebank LIKE messagebank") - statement?.executeUpdate("INSERT INTO temp_messagebank (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) SELECT Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS FROM messagebank ORDER BY ANN_ID ASC") - statement?.executeUpdate("TRUNCATE TABLE messagebank") - statement?.executeUpdate("INSERT INTO messagebank (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) SELECT Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS FROM temp_messagebank") - statement?.executeUpdate("DROP TABLE temp_messagebank") - Logger.info("messagebank table resorted by Description" as Any) - // reload the local list - Reload_Messagebank() - return true - } catch (e: Exception) { - Logger.error("Error resorting messagebank table by Description: ${e.message}" as Any) - } - return false - } - - /** - * Exports the messagebank table to an XLSX workbook. - * @return An XSSFWorkbook containing the messagebank data. - */ - fun Export_Messagebank_XLSX(): XSSFWorkbook? { - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM messagebank") - 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 - } - - fun Import_Messagebank_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_Messagebank() - // read each row and insert into database - val _messagebankList = ArrayList() - 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 Add_Messagebank(_messagebankList) - } catch (e: Exception) { - Logger.error { "Error importing Messagebank, Msg: ${e.message}" } - } - return false - } - - - /** - * Clears all entries from the messagebank table in the database and the local list. - */ - fun Clear_Messagebank(): Boolean { - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE messagebank") - Logger.info("Messagebank table cleared" as Any) - MessagebankList.clear() - return true - } catch (e: Exception) { - Logger.error("Error clearing messagebank table: ${e.message}" as Any) - } - return false - } - - /** - * Create Queue table if not exists - */ - fun Create_Queue_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS queue_table (" + - "`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 - ")" - ) - Logger.info("Queue table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating Queue table: ${e.message}" as Any) - } - } - - /** - * Reads all entries from the queue_table in the database. - * @return A list of QueueTable entries. - */ - fun Read_Queue_Table(): ArrayList { - QueueTableList.clear() - val queueList = ArrayList() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM queue_table") - 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) - QueueTableList.add(queueTable) - } - } catch (e: Exception) { - Logger.error("Error fetching queue table: ${e.message}" as Any) - } - return queueList - } - - /** - * Deletes a queue_table entry by its index. - * @param index The index of the queue_table entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_Queue_Table_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("DELETE FROM queue_table WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Deleted $rowsAffected row(s) from queue_table with index $index" as Any) - Resort_Queue_Table_by_Index() - return true - } else { - Logger.warn("No rows deleted from queue_table with index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error deleting from queue_table with index $index: ${e.message}" as Any) - } - return false - } - - /** - * Resort the queue_table table, in order to reorder the index after deletions, and sort ascending by index. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_Queue_Table_by_Index(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_queue_table LIKE queue_table") - statement?.executeUpdate("INSERT INTO temp_queue_table (Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language) SELECT Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language FROM queue_table ORDER BY `index` ASC") - statement?.executeUpdate("TRUNCATE TABLE queue_table") - statement?.executeUpdate("INSERT INTO queue_table (Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language) SELECT Date_Time, Source, Type, Message, SB_TAGS, BroadcastZones, Repeat, Language FROM temp_queue_table") - statement?.executeUpdate("DROP TABLE temp_queue_table") - Logger.info("queue_table table resorted by index" as Any) - // reload the local list - Read_Queue_Table() - return true - } catch (e: Exception) { - Logger.error("Error resorting queue_table table by index: ${e.message}" as Any) - } - return false - } - - /** - * Clears all entries from the queue_table in the database. - */ - fun Clear_Queue_Table(): Boolean { - QueueTableList.clear() - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE queue_table") - Logger.info("Queue table cleared" as Any) - return true - } catch (e: Exception) { - Logger.error("Error clearing queue table: ${e.message}" as Any) - } - return false - } - - /** - * Create Queue paging table if not exists - */ - fun Create_Queue_Paging_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS queue_paging (" + - "`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 - ")" - ) - Logger.info("Queue paging table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating Queue paging table: ${e.message}" as Any) - } - } - - /** - * Reads all entries from the queue_paging in the database. - * @return A list of QueuePaging entries. - */ - fun Read_Queue_Paging(): ArrayList { - QueuePagingList.clear() - val queueList = ArrayList() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM queue_paging") - 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) - QueuePagingList.add(queuePaging) - } - } catch (e: Exception) { - Logger.error("Error fetching queue paging: ${e.message}" as Any) - } - return queueList - } - - /** - * Deletes a queue_paging entry by its index. - * @param index The index of the queue_paging entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_Queue_Paging_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("DELETE FROM queue_paging WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Deleted $rowsAffected row(s) from queue_paging with index $index" as Any) - Resort_Queue_Paging_by_Index() - return true - } else { - Logger.warn("No rows deleted from queue_paging with index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error deleting from queue_paging with index $index: ${e.message}" as Any) - } - return false - } - - /** - * Resort the queue_paging table, in order to reorder the index after deletions, and sort ascending by index. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_Queue_Paging_by_Index(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_queue_paging LIKE queue_paging") - statement?.executeUpdate("INSERT INTO temp_queue_paging (Date_Time, Source, Type, Message, SB_TAGS) SELECT Date_Time, Source, Type, Message, SB_TAGS FROM queue_paging ORDER BY `index` ASC") - statement?.executeUpdate("TRUNCATE TABLE queue_paging") - statement?.executeUpdate("INSERT INTO queue_paging (Date_Time, Source, Type, Message, SB_TAGS) SELECT Date_Time, Source, Type, Message, SB_TAGS FROM temp_queue_paging") - statement?.executeUpdate("DROP TABLE temp_queue_paging") - Logger.info("queue_paging table resorted by index" as Any) - // reload the local list - Read_Queue_Paging() - return true - } catch (e: Exception) { - Logger.error("Error resorting queue_paging table by index: ${e.message}" as Any) - } - return false - } - - /** - * Clears all entries from the queue_paging in the database. - */ - fun Clear_Queue_Paging(): Boolean { - QueuePagingList.clear() - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE queue_paging") - Logger.info("Queue paging table cleared" as Any) - return true - } catch (e: Exception) { - Logger.error("Error clearing queue paging table: ${e.message}" as Any) - } - return false - } - - /** - * Get All Broadcast Zones from database - * @return A list of BroadcastZones entries. - */ - fun GetBroadcastZones() { - BroadcastZoneList.clear() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM broadcastzones") - while (resultSet?.next() == true) { - val zone = BroadcastZones( - resultSet.getLong("index").toUInt(), - resultSet.getString("description"), - resultSet.getString("SoundChannel"), - resultSet.getString("Box"), - resultSet.getString("Relay") - ) - BroadcastZoneList.add(zone) - } - } catch (e: Exception) { - Logger.error("Error fetching broadcast zones: ${e.message}" as Any) - } - } - - /** - * Create BroadcastZones table if not exists - */ - fun Create_BroadcastZones_Table() { - try { - val statement = connection?.createStatement() - statement?.executeUpdate( - "CREATE TABLE IF NOT EXISTS broadcastzones (" + - "`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 - "Box VARCHAR(45) NOT NULL," + // Box of the broadcast zone - "Relay VARCHAR(45) NOT NULL" + // Relay of the broadcast zone - ")" - ) - Logger.info("Broadcast zones table ensured to exist" as Any) - } catch (e: Exception) { - Logger.error("Error creating broadcast zones table: ${e.message}" as Any) - } - } - - /** - * Adds a new broadcast_zones entry to the database. - * @param broadcastZones The BroadcastZones object to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_BroadcastZones(broadcastZones: BroadcastZones): Boolean { - try { - val statement = - connection?.prepareStatement("INSERT INTO broadcastzones (description, SoundChannel, Box, Relay) VALUES (?, ?, ?, ?)") - statement?.setString(1, broadcastZones.description) - statement?.setString(2, broadcastZones.SoundChannel) - statement?.setString(3, broadcastZones.Box) - statement?.setString(4, broadcastZones.Relay) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Broadcast zone added: ${broadcastZones.description}" as Any) - return true - } else { - Logger.warn("No broadcast zone entry added for: ${broadcastZones.description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error adding broadcast zone entry: ${e.message}" as Any) - } - return false - } - - /** - * Adds multiple broadcast_zones entries to the database using bulk insert. - * @param broadcastZonesList ArrayList of BroadcastZones objects to add. - * @return True if the addition was successful, false otherwise. - */ - fun Add_BroadcastZones(broadcastZonesList: ArrayList): Boolean { - if (broadcastZonesList.isNotEmpty()) { - try { - if (connection != null) { - connection!!.autoCommit = false - val sql = - "INSERT INTO broadcastzones (description, SoundChannel, Box, Relay) VALUES (?, ?, ?, ?)" - val statement = connection!!.prepareStatement(sql) - for (bz in broadcastZonesList) { - statement.setString(1, bz.description) - statement.setString(2, bz.SoundChannel) - statement.setString(3, bz.Box) - statement.setString(4, bz.Relay) - statement.addBatch() - } - statement.executeBatch() - connection!!.commit() - Logger.info("Bulk broadcast_zones insert successful: ${broadcastZonesList.size} entries" as Any) - connection!!.autoCommit = true - return true - } - } catch (e: Exception) { - Logger.error("Error adding broadcast_zones entries: ${e.message}" as Any) - } - } - return false - } - - /** - * Updates an existing broadcast_zones entry in the database by its index. - * @param index The index of the broadcast_zones entry to update. - * @param broadcastZones The BroadcastZones object with updated values. - * @return True if the update was successful, false otherwise. - */ - fun Update_BroadcastZones_by_index(index: UInt, broadcastZones: BroadcastZones): Boolean { - try { - val statement = - connection?.prepareStatement("UPDATE broadcastzones SET description = ?, SoundChannel = ?, Box = ?, Relay = ? WHERE `index` = ?") - statement?.setString(1, broadcastZones.description) - statement?.setString(2, broadcastZones.SoundChannel) - statement?.setString(3, broadcastZones.Box) - statement?.setString(4, broadcastZones.Relay) - statement?.setLong(5, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Broadcast zone updated at index $index: ${broadcastZones.description}" as Any) - return true - } else { - Logger.warn("No broadcast zone entry updated at index $index for: ${broadcastZones.description}" as Any) - } - } catch (e: Exception) { - Logger.error("Error updating broadcast zone entry at index $index: ${e.message}" as Any) - } - return false - } - - /** - * Deletes a broadcast_zones entry by its index. - * @param index The index of the broadcast_zones entry to delete. - * @return True if the deletion was successful, false otherwise. - */ - fun Delete_BroadcastZones_by_index(index: UInt): Boolean { - try { - val statement = connection?.prepareStatement("DELETE FROM broadcastzones WHERE `index` = ?") - statement?.setLong(1, index.toLong()) - val rowsAffected = statement?.executeUpdate() - if (rowsAffected != null && rowsAffected > 0) { - Logger.info("Deleted $rowsAffected row(s) from broadcast_zones with index $index" as Any) - return true - } else { - Logger.warn("No rows deleted from broadcast_zones with index $index" as Any) - } - } catch (e: Exception) { - Logger.error("Error deleting from broadcast_zones with index $index: ${e.message}" as Any) - } - return false - } - - /** - * Resort the broadcast_zones table, in order to reorder the index after deletions, and sort ascending by description. - * @return True if the resorting was successful, false otherwise. - */ - fun Resort_BroadcastZones_by_description(): Boolean { - try { - val statement = connection?.createStatement() - // use a temporary table to reorder the index - statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_broadcastzones LIKE broadcastzones") - statement?.executeUpdate("INSERT INTO temp_broadcastzones (description, SoundChannel, Box, Relay) SELECT description, SoundChannel, Box, Relay FROM broadcastzones ORDER BY description ASC") - statement?.executeUpdate("TRUNCATE TABLE broadcastzones") - statement?.executeUpdate("INSERT INTO broadcastzones (description, SoundChannel, Box, Relay) SELECT description, SoundChannel, Box, Relay FROM temp_broadcastzones") - statement?.executeUpdate("DROP TABLE temp_broadcastzones") - Logger.info("broadcast_zones table resorted by description" as Any) - // reload the local list - GetBroadcastZones() - return true - } catch (e: Exception) { - Logger.error("Error resorting broadcast_zones table by description: ${e.message}" as Any) - } - return false - } - - /** - * Clears all entries from the broadcast_zones in the database. - */ - fun Clear_BroadcastZones(): Boolean { - try { - val statement = connection?.createStatement() - // use TRUNCATE to reset auto increment index - statement?.executeUpdate("TRUNCATE TABLE broadcastzones") - Logger.info("Broadcast zones table cleared" as Any) - return true - } catch (e: Exception) { - Logger.error("Error clearing broadcast zones table: ${e.message}" as Any) - } - return false - } - - /** - * Exports the broadcast_zones table to an XLSX workbook. - * @return An XSSFWorkbook containing the broadcast_zones data, or null if an error occurred. - */ - fun Export_BroadcastZones_XLSX(): XSSFWorkbook? { - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM broadcastzones") - 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 - } - - /** - * Imports broadcast_zones entries from an XLSX workbook. - * @param workbook The XSSFWorkbook containing the broadcast_zones data. - * @return True if the import was successful, false otherwise. - */ - fun Import_BroadcastZones_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_BroadcastZones() - // read each row and insert into database - val _broadcastZonesList = ArrayList() - 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 Add_BroadcastZones(_broadcastZonesList) - } catch (e: Exception) { - Logger.error { "Error importing BroadcastZones, Msg: ${e.message}" } - } - return false - } - - - fun Get_User_List(): ArrayList { - val userList = ArrayList() - try { - val statement = connection?.createStatement() - val resultSet = statement?.executeQuery("SELECT * FROM user") - while (resultSet?.next() == true) { - val user = UserDB( - resultSet.getLong("index").toUInt(), - resultSet.getString("username"), - resultSet.getString("password"), - resultSet.getString("location") - ) - userList.add(user) - } - } catch (e: Exception) { - Logger.error("Error fetching user list: ${e.message}" as Any) - } - return userList - } } \ No newline at end of file diff --git a/src/database/UserDB.kt b/src/database/UserDB.kt index 45c8e21..58e9a5d 100644 --- a/src/database/UserDB.kt +++ b/src/database/UserDB.kt @@ -1,4 +1,4 @@ package database @Suppress("unused") -data class UserDB(var index: UInt, var username: String, var password: String, var location: String) +data class UserDB(var index: UInt, var username: String, var password: String, var location: String, var soundbank_tags: String, var messagebank_ann_id: String, var broadcastzones: String) diff --git a/src/database/dbFunctions.kt b/src/database/dbFunctions.kt index 622abeb..d0b0da4 100644 --- a/src/database/dbFunctions.kt +++ b/src/database/dbFunctions.kt @@ -1,20 +1,106 @@ package database +import org.apache.poi.xssf.usermodel.XSSFWorkbook +import org.tinylog.Logger import java.sql.Connection +@Suppress("unused", "SqlDialectInspection", "SqlSourceToSinkFlow") abstract class dbFunctions(val dbName: String, val connection: Connection) { var List : ArrayList = ArrayList() - fun Clear(){ + /** + * Clear all entries in the table + * @return true if successful, false otherwise + */ + open fun Clear() : Boolean{ + try { + val statement = connection.createStatement() + // use TRUNCATE to reset auto increment index + statement?.executeUpdate("TRUNCATE TABLE $dbName") + Logger.info("$dbName table cleared" as Any) + List.clear() + return true + } catch (e: Exception) { + Logger.error("Error clearing $dbName table: ${e.message}" as Any) + } + return false } - fun DeleteByIndex(index: Int) { - + /** + * Delete entry by index + * @param index The index of the entry to delete + * @return true if successful, false otherwise + */ + open fun DeleteByIndex(index: Int) : Boolean{ + try { + val statement = connection.prepareStatement("DELETE FROM $dbName WHERE `index` = ?") + statement?.setLong(1, index.toLong()) + val rowsAffected = statement?.executeUpdate() + if (rowsAffected != null && rowsAffected > 0) { + Logger.info("Deleted $rowsAffected row(s) from $dbName with index $index" as Any) + return true + } else { + Logger.warn("No rows deleted from $dbName with index $index" as Any) + } + } catch (e: Exception) { + Logger.error("Error deleting from $dbName with index $index: ${e.message}" as Any) + } + return false } + /** + * Create the table if it does not exist + */ abstract fun Create() - abstract fun Get(): ArrayList + + protected fun Create(tableDefinition: String) { + try { + val statement = connection.createStatement() + statement?.executeUpdate(tableDefinition) + Logger.info("$dbName table ensured to exists" as Any) + } catch (e: Exception) { + Logger.error("Error creating $dbName table: ${e.message}" as Any) + } + } + + /** + * Get all entries from the table and populate the List + */ + abstract fun Get() + + /** + * Add a new entry to the table + * @param data The data to add + * @return true if successful, false otherwise + */ abstract fun Add(data: T): Boolean + + /** + * Add multiple entries to the table + * @param data The list of data to add + * @return true if successful, false otherwise + */ + abstract fun AddAll(data: ArrayList): Boolean + + /** + * Update an existing entry by index + * @param index The index of the entry to update + * @param data The new data + * @return true if successful, false otherwise + */ abstract fun UpdateByIndex(index: Int, data: T): Boolean abstract fun Resort(): Boolean + + /** + * Import the table from XLSX format + * @param workbook The XSSFWorkbook object to import from + * @return true if successful, false otherwise + */ + abstract fun Import_XLSX(workbook: XSSFWorkbook) : Boolean + + /** + * Export the table to XLSX format + * @return XSSFWorkbook object if successful, null otherwise + */ + abstract fun Export_XLSX() : XSSFWorkbook? } \ No newline at end of file diff --git a/src/web/WebApp.kt b/src/web/WebApp.kt index 9f6009f..83c1266 100644 --- a/src/web/WebApp.kt +++ b/src/web/WebApp.kt @@ -16,6 +16,7 @@ import content.Language import content.ScheduleDay import content.VoiceType import database.BroadcastZones +import database.BroadcastZonesHtml import database.LanguageLink import database.MariaDB import database.Messagebank @@ -129,11 +130,11 @@ class WebApp(val listenPort: Int, val userlist: List>) { } "getPagingQueue" ->{ - SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(db.Read_Queue_Paging())) + SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(db.queuepagingDB.List)) } "getAASQueue" ->{ - SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(db.Read_Queue_Table())) + SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(db.queuetableDB.List)) } "getStreamerOutputs" -> { @@ -197,7 +198,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } path("SoundBank") { get("List") { - it.result(MariaDB.ArrayListtoString(db.SoundbankList)) + it.result(MariaDB.ArrayListtoString(db.soundDB.List)) } get("ListFiles"){ it.result(objectmapper.writeValueAsString(ListAudioFiles("C:\\soundbank"))) @@ -211,13 +212,13 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (ValidString(addvalue.Language)) { if (ValidString(addvalue.Path)) { // check apakah TAG sudah ada untuk language dan category yang sama - val exists = db.SoundbankList.any { sb -> + val exists = db.soundDB.List.any { sb -> sb.TAG == addvalue.TAG && sb.Language == addvalue.Language && sb.Category == addvalue.Category } if (!exists) { if (ValidFile(addvalue.Path)) { - if (db.Add_Soundbank(addvalue)) { - db.Resort_Soundbank_by_Description() + if (db.soundDB.Add(addvalue)) { + db.soundDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) .result(objectmapper.writeValueAsString(resultMessage("Failed to add soundbank to database"))) @@ -236,8 +237,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } delete("List") { // truncate soundbank table - if (db.Clear_Soundbank()) { - db.Reload_Soundbank() + if (db.soundDB.Clear()) { + db.soundDB.Get() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate soundbank table"))) @@ -249,8 +250,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - if (db.Delete_Soundbank_by_index(index)) { - db.Resort_Soundbank_by_Description() + if (db.soundDB.DeleteByIndex(index.toInt())) { + db.soundDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete soundbank with index $index"))) @@ -264,7 +265,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { // tidak ada path param index it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - val sb = db.SoundbankList.find { xx -> xx.index == index } + val sb = db.soundDB.List.find { xx -> xx.index == index } if (sb == null) { // soundbank dengan index tersebut tidak ditemukan it.status(404).result(objectmapper.writeValueAsString(resultMessage("Soundbank with index $index not found"))) @@ -313,8 +314,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } } if (changed) { - if (db.Update_Soundbank_by_index(index, sb)) { - db.Resort_Soundbank_by_Description() + if (db.soundDB.UpdateByIndex(index.toInt(), sb)) { + db.soundDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to update soundbank with index $index"))) } else it.status(400) @@ -324,7 +325,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } } get("ExportXLSX") { - val xlsxdata = db.Export_Soundbank_XLSX() + val xlsxdata = db.soundDB.Export_XLSX() if (xlsxdata != null) { it.header( "Content-Type", @@ -346,8 +347,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } try { val xlsx = XSSFWorkbook(uploaded.content()) - if (db.Import_Soundbank_XLSX(xlsx)) { - db.Resort_Soundbank_by_Description() + if (db.soundDB.Import_XLSX(xlsx)) { + db.soundDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import soundbank from XLSX"))) @@ -360,7 +361,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { path("MessageBank") { get("List") { // get messagebank list - it.result(MariaDB.ArrayListtoString(db.MessagebankList)) + it.result(MariaDB.ArrayListtoString(db.messageDB.List)) } post("Add"){ val json : JsonNode = objectmapper.readTree(it.body()) @@ -377,8 +378,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (message_detail.isNotEmpty()){ if (message_tags.isNotEmpty()){ val mb = Messagebank(0u, description, language, ann_id, voice_type, message_detail, message_tags) - if (db.Add_Messagebank(mb)){ - db.Resort_Messagebank_by_ANN_ID() + if (db.messageDB.Add(mb)){ + db.messageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add messagebank to database"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Message_TAGS"))) @@ -390,8 +391,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } delete("List") { // truncate messagebank table - if (db.Clear_Messagebank()) { - db.Reload_Messagebank() + if (db.messageDB.Clear()) { + db.messageDB.Get() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate messagebank table"))) @@ -403,8 +404,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - if (db.Delete_Messagebank_by_index(index)) { - db.Resort_Messagebank_by_ANN_ID() + if (db.messageDB.DeleteByIndex(index.toInt())) { + db.messageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete messagebank with index $index"))) @@ -417,7 +418,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - val mb = db.MessagebankList.find { xx -> xx.index == index } + val mb = db.messageDB.List.find { xx -> xx.index == index } if (mb == null) { it.status(404).result(objectmapper.writeValueAsString(resultMessage("Messagebank with index $index not found"))) } else { @@ -463,8 +464,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { changed = true } if (changed) { - if (db.Update_Messagebank_by_index(index, mb)) { - db.Resort_Messagebank_by_ANN_ID() + if (db.messageDB.UpdateByIndex(index.toInt(), mb)) { + db.messageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) .result(objectmapper.writeValueAsString(resultMessage("Failed to update messagebank with index $index"))) @@ -475,7 +476,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } } get("ExportXLSX") { - val xlsxdata = db.Export_Messagebank_XLSX() + val xlsxdata = db.messageDB.Export_XLSX() if (xlsxdata != null) { it.header( "Content-Type", @@ -497,8 +498,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } try { val xlsx = XSSFWorkbook(uploaded.content()) - if (db.Import_Messagebank_XLSX(xlsx)) { - db.Resort_Messagebank_by_ANN_ID() + if (db.messageDB.Import_XLSX(xlsx)) { + db.messageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import messagebank from XLSX"))) @@ -511,7 +512,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { path("LanguageLink") { get("List") { // get language link list - it.result(MariaDB.ArrayListtoString(db.LanguageLinkList)) + it.result(MariaDB.ArrayListtoString(db.languageDB.List)) } post("Add"){ // Parse JSON from request body @@ -521,10 +522,10 @@ class WebApp(val listenPort: Int, val userlist: List>) { println("Add Language Link, tag=$tag, languages=$languages") if (ValidString(tag)){ if (languages.all { xx -> Language.entries.any { yy -> yy.name.equals(xx,true)} }){ - if (!db.LanguageLinkList.any { ll -> ll.TAG.equals(tag,true) }) { + if (!db.languageDB.List.any { ll -> ll.TAG.equals(tag,true) }) { val newvalue = LanguageLink(0u, tag, languages.joinToString(";")) - if (db.Add_LanguageLink(newvalue)){ - db.Resort_LanguageLink_by_TAG() + if (db.languageDB.Add(newvalue)){ + db.languageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add language link to database"))) @@ -545,8 +546,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } delete("List") { // truncate language link table - if (db.Clear_LanguageLink()) { - db.Reload_LanguageLink() + if (db.languageDB.Clear()) { + db.languageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate language link table"))) @@ -558,8 +559,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - if (db.Delete_LanguageLink_by_index(index)) { - db.Resort_LanguageLink_by_TAG() + if (db.languageDB.DeleteByIndex(index.toInt())) { + db.languageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete language link with index $index"))) @@ -572,7 +573,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - val ll = db.LanguageLinkList.find { xx -> xx.index == index } + val ll = db.languageDB.List.find { xx -> xx.index == index } if (ll == null) { it.status(404).result(objectmapper.writeValueAsString(resultMessage("Language link with index $index not found"))) } else { @@ -592,8 +593,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { changed = true } if (changed) { - if (db.Update_LanguageLink_by_index(index, ll)) { - db.Resort_LanguageLink_by_TAG() + if (db.languageDB.UpdateByIndex(index.toInt(), ll)) { + db.languageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) .result(objectmapper.writeValueAsString(resultMessage("Failed to update language link with index $index"))) @@ -604,7 +605,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } } get("ExportXLSX") { - val xlsxdata = db.Export_LanguageLink_XLSX() + val xlsxdata = db.languageDB.Export_XLSX() if (xlsxdata != null) { it.header( "Content-Type", @@ -626,8 +627,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } try { val xlsx = XSSFWorkbook(uploaded.content()) - if (db.Import_LanguageLink_XLSX(xlsx)) { - db.Resort_LanguageLink_by_TAG() + if (db.languageDB.Import_XLSX(xlsx)) { + db.languageDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import language link from XLSX"))) @@ -640,12 +641,12 @@ class WebApp(val listenPort: Int, val userlist: List>) { path("ScheduleBank") { get("List") { // get timer list - it.result(MariaDB.ArrayListtoString(db.SchedulebankList)) + it.result(MariaDB.ArrayListtoString(db.scheduleDB.List)) } delete("List") { // truncate timer table - if (db.Clear_Schedulebank()) { - db.Reload_Schedulebank() + if (db.scheduleDB.Clear()) { + db.scheduleDB.Get() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate schedulebank table"))) @@ -657,8 +658,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - if (db.Delete_Schedulebank_by_index(index)) { - db.Resort_Schedulebank_by_Day_Time() + if (db.scheduleDB.DeleteByIndex(index.toInt())) { + db.scheduleDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete schedule with index $index"))) @@ -671,7 +672,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - val sb = db.SchedulebankList.find { xx -> xx.index == index } + val sb = db.scheduleDB.List.find { xx -> xx.index == index } if (sb == null) { it.status(404).result(objectmapper.writeValueAsString(resultMessage("Schedule with index $index not found"))) } else { @@ -736,8 +737,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } } if (changed) { - if (db.Update_Schedulebank_by_index(index, sb)) { - db.Resort_Schedulebank_by_Day_Time() + if (db.scheduleDB.UpdateByIndex(index.toInt(), sb)) { + db.scheduleDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) .result(objectmapper.writeValueAsString(resultMessage("Failed to update schedule with index $index"))) @@ -748,7 +749,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } } get("ExportXLSX") { - val xlsxdata = db.Export_Schedulebank_XLSX() + val xlsxdata = db.scheduleDB.Export_XLSX() if (xlsxdata != null) { it.header( "Content-Type", @@ -770,8 +771,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } try { val xlsx = XSSFWorkbook(uploaded.content()) - if (db.Import_Schedulebank_XLSX(xlsx)) { - db.Resort_Schedulebank_by_Day_Time() + if (db.scheduleDB.Import_XLSX(xlsx)) { + db.scheduleDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import schedulebank from XLSX"))) @@ -788,6 +789,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (ValiDateForLogHtml(logdate)) { if (ValidString(logfilter)) { // ada log filter + db.GetLogForHtml(logdate, logfilter) { get1.result(MariaDB.ArrayListtoString(it)) } @@ -828,13 +830,23 @@ class WebApp(val listenPort: Int, val userlist: List>) { } path("BroadcastZones"){ get("List") { - // get broadcast zones list - it.result(MariaDB.ArrayListtoString(db.BroadcastZoneList)) + // TODO : temporary, convert BroadcastZones to BroadcastZonesHtml, karena harus revisi javascript di Bootstrap Studio + val newlist: ArrayList = db.broadcastDB.List.map { xx -> + BroadcastZonesHtml( + xx.index, + xx.description, + xx.SoundChannel, + xx.id, + xx.bp + ) + } as ArrayList + + it.result(MariaDB.ArrayListtoString(newlist)) } delete("List"){ // truncate broadcast zones table - if (db.Clear_BroadcastZones()) { - db.GetBroadcastZones() + if (db.broadcastDB.Clear()) { + db.broadcastDB.Get() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate broadcast zones table"))) @@ -851,8 +863,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (ValidString(_box)){ if (ValidString(_relay)){ val newbp = BroadcastZones(0u,_description,_soundchannel,_box,_relay) - if (db.Add_BroadcastZones(newbp)){ - db.Resort_BroadcastZones_by_description() + if (db.broadcastDB.Add(newbp)){ + db.broadcastDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add broadcast zone to database"))) } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Relay"))) @@ -866,8 +878,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - if (db.Delete_BroadcastZones_by_index(index)) { - db.Resort_BroadcastZones_by_description() + if (db.broadcastDB.DeleteByIndex(index.toInt())) { + db.broadcastDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete broadcast zone with index $index"))) @@ -880,7 +892,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - val bz = db.BroadcastZoneList.find { xx -> xx.index == index } + val bz = db.broadcastDB.List.find { xx -> xx.index == index } if (bz == null) { it.status(404).result(objectmapper.writeValueAsString(resultMessage("Broadcast zone with index $index not found"))) } else { @@ -901,17 +913,17 @@ class WebApp(val listenPort: Int, val userlist: List>) { bz.SoundChannel = _soundchannel changed = true } - if (ValidString(_box) && _box != bz.Box) { - bz.Box = _box + if (ValidString(_box) && _box != bz.id) { + bz.id = _box changed = true } - if (ValidString(_relay) && _relay != bz.Relay) { - bz.Relay = _relay + if (ValidString(_relay) && _relay != bz.bp) { + bz.bp = _relay changed = true } if (changed) { - if (db.Update_BroadcastZones_by_index(index, bz)) { - db.Resort_BroadcastZones_by_description() + if (db.broadcastDB.UpdateByIndex(index.toInt(), bz)) { + db.broadcastDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) .result(objectmapper.writeValueAsString(resultMessage("Failed to update broadcast zone with index $index"))) @@ -923,7 +935,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } get("ExportXLSX") { - val xlsxdata = db.Export_BroadcastZones_XLSX() + val xlsxdata = db.broadcastDB.Export_XLSX() if (xlsxdata != null) { it.header( "Content-Type", @@ -945,8 +957,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } try { val xlsx = XSSFWorkbook(uploaded.content()) - if (db.Import_BroadcastZones_XLSX(xlsx)) { - db.Resort_BroadcastZones_by_description() + if (db.broadcastDB.Import_XLSX(xlsx)) { + db.broadcastDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import broadcast zones from XLSX"))) @@ -959,12 +971,12 @@ class WebApp(val listenPort: Int, val userlist: List>) { } path("SoundChannel"){ get("List"){ - it.result(MariaDB.ArrayListtoString(db.SoundChannelList)) + it.result(MariaDB.ArrayListtoString(db.soundchannelDB.List)) } delete("List"){ // truncate sound channel table - if (db.Clear_SoundChannel()) { - db.GetSoundChannel() + if (db.soundchannelDB.Clear()) { + db.soundchannelDB.Get() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate sound channel table"))) @@ -976,7 +988,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { if (index == null) { it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { - val sc = db.SoundChannelList.find { xx -> xx.index == index } + val sc = db.soundchannelDB.List.find { xx -> xx.index == index } if (sc == null) { println("Sound channel with index $index not found") it.status(404).result(objectmapper.writeValueAsString(resultMessage("Sound channel with index $index not found"))) @@ -999,7 +1011,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } else { // cek apakah ada soundchannel lain yang pakai ip dan channel yang sama - if (db.SoundChannelList.any { xx -> xx.index != index && _ip.equals(xx.ip) && _channel.equals(xx.channel, true) }) { + if (db.soundchannelDB.List.any { xx -> xx.index != index && _ip.equals(xx.ip) && _channel.equals(xx.channel, true) }) { println("Another sound channel already uses IP $_ip and channel $_channel") it.status(400).result(objectmapper.writeValueAsString(resultMessage("Another sound channel already uses IP $_ip and channel $_channel"))) return@patch @@ -1007,9 +1019,9 @@ class WebApp(val listenPort: Int, val userlist: List>) { // ada sesuatu yang ganti val newsc = SoundChannel(0u, _channel, _ip) - if (db.Update_SoundChannel_by_index(index,newsc)){ + if (db.soundchannelDB.UpdateByIndex(index.toInt(),newsc)){ println("Updated sound channel with index $index") - db.Resort_SoundChannel_by_index() + db.soundchannelDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { println("Failed to update sound channel with index $index") @@ -1035,7 +1047,7 @@ class WebApp(val listenPort: Int, val userlist: List>) { } get("ExportXLSX"){ - val xlsxdata = db.Export_SoundChannel_XLSX() + val xlsxdata = db.soundchannelDB.Export_XLSX() if (xlsxdata != null) { it.header( "Content-Type", @@ -1057,8 +1069,8 @@ class WebApp(val listenPort: Int, val userlist: List>) { } try { val xlsx = XSSFWorkbook(uploaded.content()) - if (db.Import_SoundChannel_XLSX(xlsx)) { - db.Resort_SoundChannel_by_index() + if (db.soundchannelDB.Import_XLSX(xlsx)) { + db.soundchannelDB.Resort() it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import sound channel from XLSX")))