package moonpi.gui

import moonpi.*
import net.miginfocom.swing.MigLayout
import java.awt.Color
import java.awt.Dimension
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.nio.file.Path
import java.util.concurrent.ExecutorService
import javax.imageio.ImageIO
import javax.swing.*

class PictureGui(
        parent: JFrame,
        private val pictureService: PictureService,
        eventBus: EventBus,
        worker: ExecutorService
) {

    val commandPanel = CommandPanel()
    val picturePanel = PicturePanel()
    val historyNavigationPanel = HistoryNavigationPanel()

    init {
        assignActivePicture()

        commandPanel.processButton.addActionListener {
            commandPanel.processButton.isEnabled = false
            worker.submit { pictureService.takePicture(commandPanel.getOptions()) }
        }

        eventBus.onGui(PictureProcessingSucceded::class) {
            commandPanel.processButton.isEnabled = true
        }

        eventBus.onGui(PictureProcessingFailed::class) {
            commandPanel.processButton.isEnabled = true
            GuiUtils.showErrorDialog(
                    parent,
                    "Failed to process picture with options [${it.options}]\nCause: ${it.cause}"
            )
        }

        historyNavigationPanel.previousButton.addActionListener { pictureService.selectPreviousPicture() }

        historyNavigationPanel.nextButton.addActionListener { pictureService.selectNextPicture() }

        historyNavigationPanel.removeButton.addActionListener { pictureService.removeActivePicture() }

        eventBus.onGui(PictureSelected::class) { assignActivePicture() }
    }

    private fun assignActivePicture() {
        pictureService.activePicture?.let {
            picturePanel.setPicture(it.filePath)
            historyNavigationPanel.populateWithPicture(
                    it,
                    pictureService.history.getPictures().indexOf(it),
                    pictureService.history.getPictures().size
            )
        }
    }
}

class CommandPanel : JPanel(MigLayout("fill", "[][grow][]")) {

    private val optionsInput = JTextField()
    internal val processButton = JButton(GuiUtils.loadIcon("run"))

    init {
        add(JLabel("Command"))
        add(optionsInput, "grow")
        add(processButton)
    }

    fun getOptions(): String {
        return optionsInput.text
    }
}

class PicturePanel : JPanel() {

    private var picture: BufferedImage? = null

    init {
        preferredSize = Dimension(640, 480)
    }

    fun setPicture(filepath: Path) {
        picture = ImageIO.read(filepath.toFile())
        repaint()
    }

    override fun paintComponent(g: Graphics?) {
        val g2 = g as Graphics2D
        picture?.let {
            g2.color = Color.BLACK
            g2.fillRect(0, 0, width, height)
            val heightRatio = it.height.toDouble() / height.toDouble()
            val widthRatio = it.width.toDouble() / width.toDouble()
            val ratio = arrayOf(heightRatio, widthRatio).max()!!
            val drawW = it.width / ratio
            val drawH = it.height / ratio
            val drawX = (width - drawW) / 2
            val drawY = (height - drawH) / 2
            g2.drawImage(it, drawX.toInt(), drawY.toInt(), drawW.toInt(), drawH.toInt(), this)
        }
    }
}

class HistoryNavigationPanel : JPanel(MigLayout("fillx", "[min][center,grow][min]")) {

    private val optionsLabel = JLabel()
    private val dateLabel = JLabel()
    private val counterLabel = JLabel("", JLabel.CENTER)
    internal val previousButton = JButton("<")
    internal val nextButton = JButton(">")
    internal val removeButton = JButton("Remove")

    init {
        previousButton.isEnabled = false
        nextButton.isEnabled = false
        removeButton.isEnabled = false

        val navigationPanel = JPanel()
        navigationPanel.add(previousButton)
        navigationPanel.add(counterLabel)
        navigationPanel.add(nextButton)

        add(optionsLabel, "span")
        add(dateLabel)
        add(navigationPanel)
        add(removeButton, "wrap")
    }

    fun populateWithPicture(picture: Picture, picturePosition: Int, picturesCount: Int) {
        removeButton.isEnabled = true

        if (picturesCount > 1) {
            previousButton.isEnabled = true
            nextButton.isEnabled = true
        } else {
            nextButton.isEnabled = false
            removeButton.isEnabled = false
        }

        optionsLabel.text = "Options: ${picture.options}"
        dateLabel.text = picture.date.format(localDateTimeFormatter)
        counterLabel.text = "${picturePosition + 1}/$picturesCount"
    }
}
