package application.controller

import application.model.*
import application.model.MapState.*
import javafx.application.Platform
import javafx.fxml.FXML
import javafx.fxml.Initializable
import javafx.scene.layout.StackPane
import map.*
import java.net.URL
import java.util.*

class MapPanelController : Initializable {

    @FXML
    private lateinit var map: StackPane

    private val mapView = LeafletMapView()

    override fun initialize(location: URL?, resources: ResourceBundle?) {
        mapView.displayMap(MapConfig())
        setObservableVesselListener()
        setObservableSelectedVesselListener()
        setStateListener()
        setObservableIsReplayState()
        observableCurrentTime()

        map.children.add(mapView)
        map.children
    }

    private fun setStateListener() {
        observableMapState.listeners.add(object : StateListener {
            override fun onValueChanged(newValue: MapState) {
                if (observableSelectedVessel.value.mmsi != null) {
                    updateMap(observableSelectedVessel.value.mmsi!!)
                } else {
                    updateMap()
                }
            }
        })
    }

    private fun observableCurrentTime() {
        observableCurrentTime.listeners.add(object : CurrentTime {
            override fun onValueChanged(newValue: Int) {
                if (observableSelectedVessel.value.mmsi != null) {
                    updateMap(observableSelectedVessel.value.mmsi!!)
                } else {
                    updateMap()
                }
            }
        })
    }

    private fun updateMap() {
        Platform.runLater {
            if (observableIsReplayState.value) {
                when (observableMapState.state) {
                    ALL_MESSAGES -> displayTimedAllMessageOnMap(mapView)
                    CLUSTERED_MESSAGES -> displayTimedClusterMessageOnMap(mapView)
                    HEAT_MAP -> displayTimedHeatMapOnMap(mapView)
                }
            } else {
                when (observableMapState.state) {
                    ALL_MESSAGES -> displayAllMessageOnMap(mapView)
                    CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView)
                    HEAT_MAP -> displayHeatMapOnMap(mapView)
                }
            }
        }
    }

    private fun updateMap(selectedMMSI: String) {
        Platform.runLater {
            if (observableIsReplayState.value) {
                when (observableMapState.state) {
                    ALL_MESSAGES -> displayTimedAllMessageOnMap(mapView, selectedMMSI)
                    CLUSTERED_MESSAGES -> displayTimedClusterMessageOnMap(mapView, selectedMMSI)
                    HEAT_MAP -> displayTimedHeatMapOnMap(mapView, selectedMMSI)
                }
            } else {
                when (observableMapState.state) {
                    ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI)
                    CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI)
                    HEAT_MAP -> displayHeatMapOnMap(mapView, selectedMMSI)
                }
            }
        }
    }

    private fun setObservableVesselListener() {
        observableVessel.listeners.add(object : MessageListener {
            override fun onValueChanged(newValue: MutableMap<String?, Vessel>) {
                updateMap()
            }
        })
    }

    private fun setObservableIsReplayState() {
        observableIsReplayState.listeners.add(object : ReplayState {
            override fun onValueChanged(newValue: Boolean) {
                if (observableSelectedVessel.value.mmsi != null) {
                    updateMap(observableSelectedVessel.value.mmsi!!)
                } else {
                    updateMap()
                }
            }
        })
    }

    private fun setObservableSelectedVesselListener() {
        observableSelectedVessel.listeners.add(object : SelectedVesselListener {
            override fun onValueChanged(newValue: Vessel) {
                if (newValue.mmsi != null) {
                    updateMap(newValue.mmsi)
                } else {
                    updateMap()
                }
            }
        })
    }
}