package org.hso.texturesyncclient.controller import javafx.application.Platform import javafx.collections.ObservableList import javafx.event.EventHandler import javafx.stage.DirectoryChooser import org.hso.texturesyncclient.alerts.JFXInfoAlert import org.hso.texturesyncclient.alerts.JFXOkayCancelAlert import org.hso.texturesyncclient.controller.net.AutoConnect import org.hso.texturesyncclient.controller.net.Connection import org.hso.texturesyncclient.model.GUIModel import org.hso.texturesyncclient.model.Sha256 import org.hso.texturesyncclient.model.Texture import org.hso.texturesyncclient.model.TextureFormat import org.hso.texturesyncclient.view.importView.ImportView import org.hso.texturesyncclient.view.mainView.MainView import org.hso.texturesyncclient.view.mainView.MainViewController import org.hso.texturesyncclient.view.startupView.StartupView import org.hso.texturesyncclient.view.startupView.StartupViewController import tornadofx.Controller import tornadofx.find import tornadofx.observable import java.net.InetAddress import java.util.Calendar import java.io.File import javax.imageio.ImageIO import java.util.UUID import java.nio.file.Files import java.io.FileOutputStream import java.io.IOException import java.text.SimpleDateFormat class RootController : Controller() { private val mvc: MainViewController by inject() private val svc: StartupViewController by inject() private lateinit var con: Connection private lateinit var selectedTexture: Texture private var lastExportDir: String = System.getProperty("user.home") /** * calculate the resolution, get today's date -> upload to server * @param path the absolute path of the file on the client's system * @param name the file name * @param tags all tags for the file */ fun importTexture(path: String, name: String, tags: ObservableList) { var data = Files.readAllBytes(File(path).toPath()) // this is the image as byte array val uuid = UUID.randomUUID() val format = if (File(path).extension.toLowerCase() == "png") TextureFormat.PNG else TextureFormat.JPEG val bimg = ImageIO.read(File(path)) //image for obtaining resolution val resolution = Pair(bimg.height, bimg.width) val cal = Calendar.getInstance() //calendar obj with current time val hash = Sha256(data) val alertImportHash = JFXInfoAlert( "Upload fehlgeschlagen", "Die Textur wurde nicht fehlerfrei übertragen", "-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;" ) val alertImport = JFXInfoAlert( "Upload fehlgeschlagen", "Mögliche Ursachen:" + "\n- Textur existiert bereits" + "\n- Server nicht bereit", "-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;" ) data = null //Free image val newTexture = Texture(uuid, name, tags.toTypedArray(), format, resolution, cal, hash) try { con.uploadTexture(newTexture, data) println("Texture upload successful") } catch (e: IllegalArgumentException) { println(e) alertImportHash.showAndWait() } catch (e: Exception) { alertImport.showAndWait() } } /** * Initialize connection to server and switch to MainView if connected * @param name server name as IP or domain */ fun initConnection(name: String) { if (name == " ") { //no user input, try automatic connect or restore address from settings file println("try auto connect") try { val foundServer = AutoConnect.searchServer() if (foundServer != null) { println("[auto] server found") con = foundServer con.ping() println("auto Connection to Server successful") switchStartupToMain() showAll() } else { println("[auto] no server found") } } catch (e: Exception) { println(e) println("auto Connection to Server NOT successful") } if (SettingsController.serverAddressIsSet()) { println("[file] try connect with settings file") try { svc.setServerAddress(SettingsController.getServerAddress()) // FIXME this crashes the client when there is either not text or no label! con = Connection(InetAddress.getByName(SettingsController.getServerAddress())) con.ping() println("[file] Connection to Server successful") switchStartupToMain() showAll() } catch (e: Exception) { println(e) println("[file] Connection to Server NOT successful") } } else { println("[file] no address in settings file") } } else { //try to connect with user input try { println("try connect with user input") con = Connection(InetAddress.getByName(name)) con.ping() println("Connection to Server successful") SettingsController.setServerAddress(name) //store address in settings file switchStartupToMain() showAll() println("swithing to MainView @ initCon") } catch (e: Exception) { println(e) println("Connection to Server NOT successful") } } } fun queryElements(tags: ObservableList): ArrayList { mvc.setVisibleMetaTags(false) val previewList = arrayListOf() try { con.query(tags.toTypedArray()).forEach { runAsync { Platform.runLater { mvc.addElement(GUIModel(it, con.getTexturePreview(it.textureHash))) } } } } catch (e: Exception) { println(e) } println(previewList.size) return previewList } /** * save the texture file to a local directory * @param data the texture as meta element */ fun exportTexture(data: Texture) { val directoryChooser = DirectoryChooser() directoryChooser.title = "Export Verzeichnis wählen" directoryChooser.initialDirectory = File(lastExportDir) val alertExport = JFXInfoAlert( "Exporterien fehlgeschlagen", "Mögliche Ursachen:" + "\n- Datei existiert bereits" + "\n- Ordner nicht beschreibbar", "-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;" ) val dir = directoryChooser.showDialog(primaryStage) if (dir != null) { val extension = if (data.format == TextureFormat.PNG) ".png" else ".jpeg" //get file format val filePath = "$dir/${data.name}$extension" //build absolute exported texture path val exportedFile = File(filePath) //create file if (exportedFile.exists()) { alertExport.showAndWait() } else { try { val fileout = FileOutputStream(exportedFile) fileout.write(con.getTextureFile(data.textureHash)) //write bytes in file fileout.close() fileout.close() } catch (e: IOException) { alertExport.showAndWait() } } lastExportDir = dir.absolutePath //store last user chosen dir } } /** * show the detailed meta information in the DetailView * @param data the texture as meta element */ fun showDetail(data: Texture) { mvc.setPreview3DTexture(con.getTexturePreview(data.textureHash)) val sdf = SimpleDateFormat("dd.MM.yyyy") mvc.setMeta( data.name, "${data.resolution.first}px x ${data.resolution.second}px", data.format.toString(), sdf.format(data.addedOn.time) ) mvc.setTags(data.tags.toList().observable()) selectedTexture = data mvc.setVisibleMetaTags(true) } /** * remove a texture from the FolderView and the server * @param data the texture as meta element */ fun deleteTexture(data: Texture) { val dialogDelete = JFXOkayCancelAlert( "Löschen", "Textur ${data.name} wirklich löschen?", "-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;" ) dialogDelete.okayAction = EventHandler { con.deleteTexture(data) mvc.removeTextureFromView(data) } dialogDelete.cancelAction = EventHandler { // Do nothing } dialogDelete.showAndWait() } /** * send a changed texture to the server * @param chips the new tag list */ fun updateTexture(chips: ObservableList) { val uuid = UUID.randomUUID() val newTexture = Texture( uuid, selectedTexture.name, chips.toTypedArray(), selectedTexture.format, selectedTexture.resolution, selectedTexture.addedOn, selectedTexture.textureHash ) con.updateTexture(selectedTexture, newTexture, con.getTextureFile(selectedTexture.textureHash)) } /** * show all available textures at start */ private fun showAll() { queryElements(mvc.getTags()) } companion object { fun switchStartupToMain() { Platform.runLater { find(StartupView::class).replaceWith(MainView::class, sizeToScene = true, centerOnScreen = true) } } // These runLater calls should be unnecessary fun switchMainToImport() { Platform.runLater { find(MainView::class).replaceWith(ImportView::class, sizeToScene = true, centerOnScreen = true) } } fun switchImportToMain() { Platform.runLater { find(ImportView::class).replaceWith(MainView::class, sizeToScene = true, centerOnScreen = true) } } } }