Files
AAS_NewGeneration/src/database/table/Table_Soundbank.kt
2026-02-09 17:03:50 +07:00

349 lines
14 KiB
Kotlin

package database.table
import content.Category
import database.data.Soundbank
import database.dbFunctions
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.tinylog.Logger
import java.io.File
import java.sql.Connection
import java.util.function.Consumer
class Table_Soundbank(connection: Connection) : dbFunctions<Soundbank>("soundbank", connection, listOf("index", "Description", "TAG", "Category", "Language", "VoiceType", "Path")) {
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(cbOK: Consumer<Unit>?, cbFail: Consumer<String>?) {
List.clear()
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName} ORDER BY Category, Language, VoiceType, TAG")
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)
}
cbOK?.accept(Unit)
} catch (e: Exception) {
Logger.error("Error fetching soundbanks: ${e.message}" as Any)
cbFail?.accept("Error fetching ${super.dbName} : ${e.message}")
}
}
override fun Add(data: Soundbank): Boolean {
try {
val statement =
connection.prepareStatement("INSERT INTO ${super.dbName} (Description, TAG, Category, Language, VoiceType, Path) VALUES (?, ?, ?, ?, ?, ?)")
statement?.setString(1, data.Description)
statement?.setString(2, data.TAG)
statement?.setString(3, data.Category)
statement?.setString(4, data.Language)
statement?.setString(5, data.VoiceType)
statement?.setString(6, data.Path)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Soundbank added: ${data.Description}" as Any)
return true
} else {
Logger.warn("No soundbank entry added for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error adding soundbank entry: ${e.message}" as Any)
}
return false
}
override fun AddAll(data: ArrayList<Soundbank>): Boolean {
// use mysql bulk insert
try {
connection.autoCommit = false
val sql =
"INSERT INTO ${super.dbName} (Description, TAG, Category, Language, VoiceType, Path) VALUES (?, ?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (sb in data) {
statement.setString(1, sb.Description)
statement.setString(2, sb.TAG)
statement.setString(3, sb.Category)
statement.setString(4, sb.Language)
statement.setString(5, sb.VoiceType)
statement.setString(6, sb.Path)
statement.addBatch()
}
statement.executeBatch()
connection.commit()
Logger.info("Bulk soundbank insert successful: ${data.size} entries" as Any)
connection.autoCommit = true
return true
} catch (e: Exception) {
Logger.error("Error adding soundbank entries: ${e.message}" as Any)
}
return false
}
override fun UpdateByIndex(index: Int, data: Soundbank): Boolean {
try {
val statement =
connection.prepareStatement("UPDATE ${super.dbName} SET Description = ?, TAG = ?, Category = ?, Language = ?, VoiceType = ?, Path = ? WHERE `index` = ?")
statement?.setString(1, data.Description)
statement?.setString(2, data.TAG)
statement?.setString(3, data.Category)
statement?.setString(4, data.Language)
statement?.setString(5, data.VoiceType)
statement?.setString(6, data.Path)
statement?.setLong(7, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Soundbank updated at index $index: ${data.Description}" as Any)
return true
} else {
Logger.warn("No soundbank entry updated at index $index for: ${data.Description}" as Any)
}
} catch (e: Exception) {
Logger.error("Error updating soundbank entry at index $index: ${e.message}" as Any)
}
return false
}
override fun Resort(): Boolean {
try {
val statement = connection.createStatement()
val tempdb_name = "temp_${super.dbName}"
// use a temporary table to reorder the index
statement?.executeUpdate("CREATE TABLE IF NOT EXISTS $tempdb_name LIKE ${super.dbName}")
statement?.executeUpdate("TRUNCATE TABLE $tempdb_name")
statement?.executeUpdate("INSERT INTO $tempdb_name (Description, TAG, Category, Language, VoiceType, Path) SELECT Description, TAG, Category, Language, VoiceType, Path FROM ${super.dbName} ORDER BY Category, Language, VoiceType, TAG ")
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 $tempdb_name")
statement?.executeUpdate("DROP TABLE $tempdb_name")
Logger.info("${super.dbName} table resorted by Description" as Any)
// reload the local list
Get()
return true
} catch (e: Exception) {
Logger.error("Error resorting ${super.dbName} table by Description: ${e.message}" as Any)
}
return false
}
override fun Import_XLSX(workbook: XSSFWorkbook): Boolean {
try {
// check if there is sheet named "Soundbank"
val sheet =
workbook.getSheet("Soundbank") ?: throw Exception("No sheet named 'Soundbank' found")
// check if the sheet contains header named "index", "Description", "TAG", "Category", "Language", "VoiceType", "Path"
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers =
arrayOf("Index", "Description", "TAG", "Category", "Language", "VoiceType", "Path")
for ((colIndex, header) in headers.withIndex()) {
val cell = headerRow.getCell(colIndex) ?: throw Exception("Header '$header' not found")
if (cell.stringCellValue != header) throw Exception("Header '$header' not found")
}
// clear existing soundbank
Clear()
// read each row and insert into database
val _soundbankList = ArrayList<Soundbank>()
for (rowIndex in 1..sheet.lastRowNum) {
val row = sheet.getRow(rowIndex) ?: continue
val description = row.getCell(1)?.stringCellValue ?: continue
val tag = row.getCell(2)?.stringCellValue ?: continue
val category = row.getCell(3)?.stringCellValue ?: continue
val language = row.getCell(4)?.stringCellValue ?: continue
val voiceType = row.getCell(5)?.stringCellValue ?: continue
val path = row.getCell(6)?.stringCellValue ?: continue
val soundbank = Soundbank(0u, description, tag, category, language, voiceType, path)
_soundbankList.add(soundbank)
}
return AddAll(_soundbankList)
} catch (e: Exception) {
Logger.error { "Error importing Soundbank, Msg: ${e.message}" }
}
return false
}
override fun Export_XLSX(): XSSFWorkbook? {
try {
val statement = connection.createStatement()
val resultSet = statement?.executeQuery("SELECT * FROM ${super.dbName}")
val workbook = XSSFWorkbook()
val sheet = workbook.createSheet("Soundbank")
val headerRow = sheet.createRow(0)
val headers =
arrayOf("Index", "Description", "TAG", "Category", "Language", "VoiceType", "Path")
for ((colIndex, header) in headers.withIndex()) {
val cell = headerRow.createCell(colIndex)
cell.setCellValue(header)
}
var rowIndex = 1
while (resultSet?.next() == true) {
val row = sheet.createRow(rowIndex++)
row.createCell(0).setCellValue(resultSet.getString("index"))
row.createCell(1).setCellValue(resultSet.getString("Description"))
row.createCell(2).setCellValue(resultSet.getString("TAG"))
row.createCell(3).setCellValue(resultSet.getString("Category"))
row.createCell(4).setCellValue(resultSet.getString("Language"))
row.createCell(5).setCellValue(resultSet.getString("VoiceType"))
row.createCell(6).setCellValue(resultSet.getString("Path"))
}
for (i in 0 until headers.size) {
sheet.autoSizeColumn(i)
}
return workbook
} catch (e: Exception) {
Logger.error { "Error exporting Soundbank, Msg: ${e.message}" }
}
return null
}
/**
* Get all distinct airline code tags from soundbank
* @return a list of distinct airline code tags sorted alphabetically
*/
fun Get_AirlineCode_Tags(): List<String> {
return List
.filter { it.Category.equals(Category.Airline_Code.name,true) }
.distinctBy { it.TAG }
.map { it.TAG }
.sorted()
}
/**
* Get all distinct city tags from soundbank
* @return a list of distinct city tags sorted alphabetically
*/
fun Get_City_Tags(): List<String> {
return List
.filter { it.Category.equals(Category.City.name,true) }
.distinctBy { it.TAG }
.map { it.TAG }
.sorted()
}
/**
* Find City by TAG
* @param tag the city tag to search for
* @return a list of Soundbank entries matching the city tag
*/
fun Find_City_By_TAG(tag: String) : List<Soundbank> {
return List
.filter {it.Category.equals(Category.City.name,true) }
.filter { it.TAG.equals(tag, true) }
.distinctBy { it.TAG }
}
/**
* Find Airline Name by TAG
* @param tag the airline code tag to search for
* @return a list of Soundbank entries matching the airline code tag
*/
fun Find_AirlineName_By_TAG(tag: String) : List<Soundbank> {
return List
.filter {it.Category.equals(Category.Airplane_Name.name,true) }
.filter { it.TAG.equals(tag, true) }
.distinctBy { it.TAG }
}
fun Get_Places(): List<Soundbank> {
return List
.filter { it.Category.equals(Category.Places.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
fun Get_Shalat() : List<Soundbank> {
return List
.filter { it.Category.equals(Category.Shalat.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
fun Get_Sequences() : List<Soundbank> {
return List
.filter { it.Category.equals(Category.Sequence.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
fun Get_Reasons() : List<Soundbank> {
return List
.filter { it.Category.equals(Category.Reason.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
fun Get_Gates(): List<Soundbank> {
return List
.filter { it.Category.equals(Category.Gate.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
fun Get_Compensation(): List<Soundbank> {
return List
.filter { it.Category.equals(Category.Compensation.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
fun Get_Greeting() : List<Soundbank> {
return List
.filter { it.Category.equals(Category.Greeting.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
fun Get_Procedures(): List<Soundbank> {
return List
.filter { it.Category.equals(Category.Procedure.name,true) }
.distinctBy { it.TAG }
.sortedBy { it.TAG }
}
class FileCheckResult{
var validfile = arrayListOf<Soundbank>()
var invalidfile = arrayListOf<Soundbank>()
}
/**
* Check Soundbank path files existence
* @param cb callback with FileCheckResult containing valid and invalid files
*/
fun FileCheck(cb: Consumer<FileCheckResult>){
val result = FileCheckResult()
// file wav must at least 10 kb
val validfilesize = 10 * 1024; // 10 KB
for (sb in List){
if (sb.Path.isBlank()) {
result.invalidfile.add(sb)
continue
}
val file = File(sb.Path)
if (file.isFile && file.length() >= validfilesize) {
// file size should at leat 10 kb
result.validfile.add(sb)
} else {
result.invalidfile.add(sb)
}
}
cb.accept(result)
}
}