import com.google.gson.Gson
import org.openrndr.application
import org.openrndr.dialogs.openFileDialog
import org.openrndr.dialogs.saveFileDialog
import org.openrndr.extensions.SingleScreenshot
import org.openrndr.panel.controlManager
import org.openrndr.panel.elements.*
import org.openrndr.panel.style.*
import java.io.File

// -- these have to be top-level classes or Gson will silently fail.
private class ConfigItem {
    var value: Double = 0.0
}

private class ProgramState {
    var rows = 1
    var columns = 1
    val matrix = mutableListOf(mutableListOf(ConfigItem()))

    fun copyTo(programState: ProgramState) {
        programState.rows = rows
        programState.columns = columns
        programState.matrix.clear()
        programState.matrix.addAll(matrix)
    }

    fun save(file: File) {
        file.writeText(Gson().toJson(this))
    }

    fun load(file: File) {
        Gson().fromJson(file.readText(), ProgramState::class.java).copyTo(this)
    }
}

fun main() = application {
    configure {
        width = 900
        height = 720
    }

    program {
        // -- this block is for automation purposes only
        if (System.getProperty("takeScreenshot") == "true") {
            extend(SingleScreenshot()) {
                this.outputFile = System.getProperty("screenshotPath")
            }
        }
        val programState = ProgramState()
        val cm = controlManager {
            layout {
                styleSheet(has class_ "matrix") {
                    this.width = 100.percent
                }

                styleSheet(has class_ "row") {
                    this.display = Display.FLEX
                    this.flexDirection = FlexDirection.Row
                    this.width = 100.percent

                    child(has type "slider") {
                        this.width = 80.px
                    }
                }

                button {
                    label = "save"
                    clicked {
                        saveFileDialog(supportedExtensions = listOf("JSON" to listOf("json"))) {
                            programState.save(it)
                        }
                    }
                }

                button {
                    label = "load"
                    clicked {
                        openFileDialog(supportedExtensions =  listOf("JSON" to listOf("json"))) {
                            programState.load(it)
                        }
                    }
                }

                slider {
                    label = "rows"
                    precision = 0
                    bind(programState::rows)

                    events.valueChanged.listen {
                        while (programState.matrix.size > programState.rows) {
                            programState.matrix.removeAt(programState.matrix.size - 1)
                        }
                        while (programState.matrix.size < programState.rows) {
                            programState.matrix.add(MutableList(programState.columns) { ConfigItem() })
                        }
                    }
                }

                slider {
                    label = "columns"
                    precision = 0
                    bind(programState::columns)
                    events.valueChanged.listen {
                        for (row in programState.matrix) {
                            while (row.size > programState.columns) {
                                row.removeAt(row.size - 1)
                            }
                            while (row.size < programState.columns) {
                                row.add(ConfigItem())
                            }
                        }
                    }
                }

                watchListDiv("matrix", watchList = programState.matrix) { row ->
                    watchListDiv("row", watchList = row) { item ->
                        this.id = "some-row"
                        slider {
                            label = "value"
                            bind(item::value)
                        }
                    }
                }
            }
        }
        extend(cm)
    }
}

