DataPanelController.kt 12.8 KB
package application.controller

import application.model.*
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.fxml.FXML
import javafx.fxml.Initializable
import javafx.scene.control.ListCell
import javafx.scene.control.ListView
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.charts.dataviewer.api.config.DataViewerConfiguration
import org.charts.dataviewer.api.data.PlotData
import org.charts.dataviewer.api.trace.ScatterTrace
import org.charts.dataviewer.javafx.JavaFxDataViewer
import org.charts.dataviewer.utils.TraceColour
import org.charts.dataviewer.utils.TraceVisibility
import java.net.URL
import java.util.*


class DataPanelController : Initializable, SelectedVesselListener {
    private var dataList: ObservableList<Pair<String, ArrayList<MessageData?>>> = FXCollections.observableArrayList()
    private lateinit var timeData: ArrayList<MessageData?>

    private val latitude: ArrayList<MessageData?> = arrayListOf()
    private val longitude: ArrayList<MessageData?> = arrayListOf()
    private val speedOverGround: ArrayList<MessageData?> = arrayListOf()
    private val courseOverGround: ArrayList<MessageData?> = arrayListOf()
    private val heading: ArrayList<MessageData?> = arrayListOf()
    private val vesselName: ArrayList<MessageData?> = arrayListOf()
    private val imo: ArrayList<MessageData?> = arrayListOf()
    private val callSign: ArrayList<MessageData?> = arrayListOf()
    private val vesselType: ArrayList<MessageData?> = arrayListOf()
    private val status: ArrayList<MessageData?> = arrayListOf()
    private val length: ArrayList<MessageData?> = arrayListOf()
    private val width: ArrayList<MessageData?> = arrayListOf()
    private val draft: ArrayList<MessageData?> = arrayListOf()
    private val cargo: ArrayList<MessageData?> = arrayListOf()

    private var selectedItem: Pair<String, ArrayList<MessageData?>>? = null

    @FXML
    var dataListView = ListView<Pair<String, ArrayList<MessageData?>>>()

    @FXML
    var dataViewer = JavaFxDataViewer()

    private val plotData = PlotData()
    private val config = DataViewerConfiguration()

    override fun initialize(location: URL?, resources: ResourceBundle?) {
        setObservableSelectedVesselListener()
        dataListView.items = dataList



        config.showLegend(false)
        config.setLegendInsidePlot(false)

        setObservableCurrentTimeListener()

        dataListView.setCellFactory {
            object : ListCell<Pair<String, ArrayList<MessageData?>>?>() {
                override fun updateItem(item: Pair<String, ArrayList<MessageData?>>?, empty: Boolean) {
                    super.updateItem(item, empty)
                    text = if (empty) {
                        null
                    } else {
                        item?.first
                    }
                }
            }
        }

        dataListView.selectionModel.selectedItemProperty().addListener { _, _, newValue ->
            selectedItem = newValue
            updateDataList(observableSelectedVessel.value)
            plot(newValue)
        }

        plotData.allTraces.clear()
        config.setxAxisTitle("")
        config.setyAxisTitle("")
        config.plotTitle = ""
        dataViewer.updateConfiguration(config)
        dataViewer.updatePlot(plotData)
        initDataList()


    }

    private fun plot() {
        if (selectedItem != null || observableSelectedVessel.value == Vessel(null)) {
            GlobalScope.launch {
                plot(selectedItem)
            }
        }
    }

    private fun plot(data: Pair<String, ArrayList<MessageData?>>?) {
        if (data == null) {
            plotData.allTraces.clear()
            config.setxAxisTitle("")
            config.setyAxisTitle("")
            dataViewer.updateConfiguration(config)

            dataViewer.resetPlot()

            return
        }else if (data.second.size < timeData.size) return

        val getValueVisitorX = GetValueVisitor()
        val getValueVisitorY = GetValueVisitor()

        val arrayListStringX = arrayListOf<String>()
//        val arrayListDoubleX = arrayListOf<Double>()
        val arrayListStringY = arrayListOf<String>()
        val arrayListDoubleY = arrayListOf<Double>()

        for (x in 0 until timeData.size) {
            timeData[x]?.accept(getValueVisitorX)
            data.second[x]?.accept(getValueVisitorY)

            if (getValueVisitorY.value.toDoubleOrNull() == null) {
                arrayListStringX.add(getValueVisitorX.value)
                arrayListStringY.add(getValueVisitorY.value)
            } else {
                arrayListStringX.add(getValueVisitorX.value)
                arrayListDoubleY.add(getValueVisitorY.value.toDouble())
            }
        }

        val scatterTrace = ScatterTrace<Any>()
        scatterTrace.traceColour = TraceColour.RED
        scatterTrace.traceVisibility = TraceVisibility.TRUE

        val serieStringX: Array<String> = arrayListStringX.toTypedArray()
//            val serieDoubleX: Array<Double> = arrayListDoubleX.toTypedArray()
        val serieStringY: Array<String> = arrayListStringY.toTypedArray()
        val serieDoubleY: Array<Double> = arrayListDoubleY.toTypedArray()

        if (getValueVisitorY.value.toDoubleOrNull() == null) {
            scatterTrace.setxArray(serieStringX)
            scatterTrace.setyArray(serieStringY)
        } else {
            scatterTrace.setxArray(serieStringX)
            scatterTrace.setyArray(serieDoubleY)
        }

        config.plotTitle = ""
        config.setxAxisTitle("Time (s)")
        config.setyAxisTitle(data.first)
        dataViewer.resetPlot()
        plotData.allTraces.clear()
        plotData.addTrace(scatterTrace)
        dataViewer.updateConfiguration(config)
        dataViewer.updatePlot(plotData)

    }


    private fun setObservableSelectedVesselListener() {
        observableSelectedVessel.listeners.add(this)
    }

    private fun populateTime(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllTimeBeforeSelectedTime()
        } else {
            vessel.getAllTime()
        }
    }


    private fun populateLatitude(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllLatitudeBeforeSelectedTime()
        } else {
            vessel.getAllLatitude()
        }
    }

    private fun populateLongitude(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllLongitudeBeforeSelectedTime()
        } else {
            vessel.getAllLongitude()
        }
    }

    private fun populateSpeedOverGround(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllSpeedOverGroundBeforeSelectedTime()
        } else {
            vessel.getAllSpeedOverGround()
        }
    }

    private fun populateCourseOverGround(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllCourseOverGroundBeforeSelectedTime()
        } else {
            vessel.getAllCourseOverGround()
        }
    }

    private fun populateHeading(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllHeadingBeforeSelectedTime()
        } else {
            vessel.getAllHeading()
        }
    }

    private fun populateVesselName(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllVesselNameBeforeSelectedTime()
        } else {
            vessel.getAllVesselName()
        }
    }

    private fun populateIMO(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllIMOBeforeSelectedTime()
        } else {
            vessel.getAllIMO()
        }
    }

    private fun populateCallSign(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllCallSignBeforeSelectedTime()
        } else {
            vessel.getAllCallSign()
        }
    }

    private fun populateVesselType(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllVesselTypeBeforeSelectedTime()
        } else {
            vessel.getAllVesselType()
        }
    }

    private fun populateStatus(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllStatusBeforeSelectedTime()
        } else {
            vessel.getAllStatus()
        }
    }

    private fun populateLength(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllLengthBeforeSelectedTime()
        } else {
            vessel.getAllLength()
        }
    }

    private fun populateWidth(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllWidthBeforeSelectedTime()
        } else {
            vessel.getAllWidth()
        }
    }

    private fun populateDraft(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllDraftBeforeSelectedTime()
        } else {
            vessel.getAllDraft()
        }
    }

    private fun populateCargo(vessel: Vessel): ArrayList<MessageData?> {
        return if (observableIsReplayState.value) {
            vessel.getAllCargoBeforeSelectedTime()
        } else {
            vessel.getAllCargo()
        }
    }

    private fun initDataList() {
        val data = arrayListOf<Pair<String, ArrayList<MessageData?>>>()

        data.add(Pair("Latitude", latitude))
        data.add(Pair("Longitude", longitude))
        data.add(Pair("Speed Over Ground", speedOverGround))
        data.add(Pair("Course Over Ground", courseOverGround))
        data.add(Pair("Heading", heading))
        data.add(Pair("Vessel Name", vesselName))
        data.add(Pair("IMO", imo))
        data.add(Pair("Call Sign", callSign))
        data.add(Pair("Vessel Type", vesselType))
        data.add(Pair("Status", status))
        data.add(Pair("Length", length))
        data.add(Pair("Width", width))
        data.add(Pair("Draft", draft))
        data.add(Pair("Cargo", cargo))

        dataList.addAll(data)
    }

    private fun updateDataList(vessel: Vessel) {
        timeData = populateTime(vessel)

        if(dataListView.selectionModel.selectedItem == null) return

        when (dataListView.selectionModel.selectedItem.first) {
            "Latitude" -> {
                latitude.clear()
                latitude.addAll(populateLatitude(vessel))
            }
            "Longitude" -> {
                longitude.clear()
                longitude.addAll(populateLongitude(vessel))
            }
            "Speed Over Ground" -> {
                speedOverGround.clear()
                speedOverGround.addAll(populateSpeedOverGround(vessel))
            }
            "Course Over Ground" -> {
                courseOverGround.clear()
                courseOverGround.addAll(populateCourseOverGround(vessel))
            }
            "Heading" -> {
                heading.clear()
                heading.addAll(populateHeading(vessel))
            }
            "Vessel Name" -> {
                vesselName.clear()
                vesselName.addAll(populateVesselName(vessel))
            }
            "IMO" -> {
                imo.clear()
                imo.addAll(populateIMO(vessel))
            }
            "Call Sign" -> {
                callSign.clear()
                callSign.addAll(populateCallSign(vessel))
            }
            "Vessel Type" -> {
                vesselType.clear()
                vesselType.addAll(populateVesselType(vessel))
            }
            "Status" -> {
                status.clear()
                status.addAll(populateStatus(vessel))
            }
            "Length" -> {
                length.clear()
                length.addAll(populateLength(vessel))
            }
            "Width" -> {
                width.clear()
                width.addAll(populateWidth(vessel))
            }
            "Draft" -> {
                draft.clear()
                draft.addAll(populateDraft(vessel))
            }
            "Cargo" -> {
                cargo.clear()
                cargo.addAll(populateCargo(vessel))
            }
        }
    }

    private fun setObservableCurrentTimeListener() {
        observableCurrentTime.listeners.add(object : CurrentTime {
            override fun onValueChanged(newValue: Int) {
                updateDataList(observableSelectedVessel.value)
                plot()
            }
        })
    }

    override fun onValueChanged(newValue: Vessel) {
        updateDataList(newValue)
        plot()
    }

}