# JournalScansViewModel.kt

    /*
     * The MIT License
     *
     * Original work sponsored and donated by The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     * Copyright (C) 2020 The Danish Health Data Authority (http://www.sundhedsdatastyrelsen.dk)
     *
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy of
     * this software and associated documentation files (the "Software"), to deal in
     * the Software without restriction, including without limitation the rights to
     * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     * of the Software, and to permit persons to whom the Software is furnished to do
     * so, subject to the following conditions:
     *
     *
     * The above copyright notice and this permission notice shall be included in all
     * copies or substantial portions of the Software.
     *
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */

    package dk.nsp.mingraviditet.ui.main.journal.sections.scans

    import androidx.lifecycle.LiveData
    import androidx.lifecycle.MutableLiveData
    import androidx.lifecycle.Observer
    import androidx.lifecycle.viewModelScope
    import dagger.hilt.android.lifecycle.HiltViewModel
    import dk.nsp.domain.dictionary.DictionaryEntry
    import dk.nsp.domain.repository.DataCardRepository
    import dk.nsp.domain.repository.DictionaryRepository
    import dk.nsp.domain.repository.ObservationsRepository
    import dk.nsp.mingraviditet.R
    import dk.nsp.mingraviditet.extensions.numberOfFetuses
    import dk.nsp.mingraviditet.ui.adapterviews.KeyValueData
    import dk.nsp.mingraviditet.ui.adapterviews.KeyValueRow
    import dk.nsp.mingraviditet.ui.adapterviews.KeyValueSectionHeader
    import dk.nsp.mingraviditet.ui.main.journal.extensions.toTextModel
    import dk.nsp.mingraviditet.ui.main.journal.sections.JournalCommonDialogNavigatorViewModel
    import dk.nsp.mingraviditet.ui.main.journal.sections.measurements.table.models.common.TableColumnSet
    import dk.nsp.mingraviditet.ui.main.journal.sections.measurements.table.models.scan.ObservationScanTableData
    import dk.nsp.mingraviditet.util.android.recycler.RecyclerAdapterView
    import dk.nsp.mingraviditet.util.extensions.getValue
    import dk.nsp.mingraviditet.util.extensions.toMediumFormat
    import dk.nsp.mingraviditet.util.extensions.toSingleEvent
    import dk.nsp.mingraviditet.util.extensions.toTextModelOrDefault
    import dk.nsp.mingraviditet.util.extensions.transform
    import dk.nsp.mingraviditet.util.livedata.SingleEvent
    import dk.nsp.models.DataCard
    import dk.nsp.shared.Failed
    import dk.nsp.shared.Success
    import dk.nsp.shared.util.launchDefault
    import dk.nsp.util.TextModel
    import kotlinx.coroutines.CoroutineScope
    import timber.log.Timber
    import javax.inject.Inject

    @HiltViewModel
    class JournalScansViewModel @Inject constructor(
        private val dataCardRepository: DataCardRepository,
        private val dictionaryRepository: DictionaryRepository,
        private val observationsRepository: ObservationsRepository
    ) : JournalCommonDialogNavigatorViewModel() {

        private val _tableData = MutableLiveData<TableColumnSet?>()
        val tableData by _tableData

        val rowsToShow: LiveData<List<RecyclerAdapterView<*>>> =
            dataCardRepository.currentDataCard.transform { currentDataCard: DataCard? ->
                createKeyValueRows(currentDataCard)
            }

        private val _onDictionary: MutableLiveData<SingleEvent<DictionaryEntry>> = MutableLiveData()
        val onDictionary: LiveData<SingleEvent<DictionaryEntry>> = _onDictionary

        private val episodeOfCareObserver =
            Observer<DataCard?> { currentDataCard: DataCard? ->
                currentDataCard?.let {
                    updateTableRows(it.episodeOfCareIdentifier)
                }
            }

        init {
            dataCardRepository.currentDataCard.observeForever(episodeOfCareObserver)
        }

        override fun onCleared() {
            super.onCleared()
            dataCardRepository.currentDataCard.removeObserver(episodeOfCareObserver)
        }

        private fun updateTableRows(episodeOfCareIdentifier: String) = viewModelScope.launchDefault {
            val scansResult = observationsRepository.getScanObservationsTable(
                this,
                episodeOfCareIdentifier
            ).await()

            when (scansResult) {
                is Success -> {
                    val scanData = scansResult.value
                    val tableData = ObservationScanTableData(scanData)
                    _tableData.postValue(
                        tableData.toTableColumnSet(
                            ::dictionaryCallback,
                            ::triggerNavigateToActivity,
                            ::triggerNavigateToInfo
                        )
                    )
                }
                is Failed -> {
                    _tableData.postValue(null)
                    Timber.e(scansResult.error)
                }
            }
        }

        private fun createKeyValueRows(dataCard: DataCard?): List<RecyclerAdapterView<*>> {

            val expectedDateOfDeliveryFromUltrasoundScanKey =
                TextModel.from(R.string.journal_section_scans_expected_date_of_delivery_from_prenatal_ultrasound_scan)
            val oddsOfDownsKey = TextModel.from(R.string.journal_section_scans_downs_probability)
            val doubleTestPerformed = TextModel.from(R.string.journal_section_scans_double_test)
            val multipleRiskFactorsKey =
                TextModel.from(R.string.journal_section_scans_multiple_risk_factors)
            val multipleRiskFactorsCommentKey =
                TextModel.from(R.string.journal_section_scans_multiple_risk_factors_remarks)
            val amountOfFetusesKey = TextModel.from(R.string.journal_section_scans_amount_of_fetuses)
            val placentalBiopsyObservationKey =
                TextModel.from(R.string.journal_section_scans_placental_biopsy_observation)
            val prenatalAmniocentisisObservationKey =
                TextModel.from(R.string.journal_section_scans_prenatal_amniocentesis_observation)

            return listOf(
                KeyValueSectionHeader(TextModel.from(R.string.journal_section_scans_other_results_title)),
                KeyValueRow(
                    KeyValueData(
                        expectedDateOfDeliveryFromUltrasoundScanKey,
                        dataCard?.ultrasoundSection?.expectedDateOfDeliveryFromPrenatalUltrasoundScan.toMediumFormat()
                            .toTextModelOrDefault(),
                        null,
                        dictionaryCallback(expectedDateOfDeliveryFromUltrasoundScanKey)
                    )
                ),
                KeyValueRow(
                    KeyValueData(
                        oddsOfDownsKey,
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment3?.downsScreeningProbabilityAssessment.toTextModel(),
                        null,
                        dictionaryCallback(oddsOfDownsKey)
                    )
                ),
                KeyValueRow(
                    KeyValueData(
                        doubleTestPerformed,
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment3?.doubleTestCompletedDate.toMediumFormat()
                            .toTextModelOrDefault(),
                        null,
                        dictionaryCallback(doubleTestPerformed)
                    )
                ),
                KeyValueRow(
                    KeyValueData(
                        multipleRiskFactorsKey,
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment2?.multiplicityRiskAssessment?.risk.toTextModel(),
                        null,
                        dictionaryCallback(multipleRiskFactorsKey)
                    )
                ),
                KeyValueRow(
                    KeyValueData(
                        multipleRiskFactorsCommentKey,
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment2?.multiplicityRiskAssessment?.comment.toTextModelOrDefault(),
                        null,
                        dictionaryCallback(multipleRiskFactorsCommentKey)
                    )
                ),
                KeyValueRow(
                    KeyValueData(
                        amountOfFetusesKey,
                        dataCard?.numberOfFetuses?.toString()
                            .toTextModelOrDefault(),
                        null,
                        dictionaryCallback(amountOfFetusesKey)
                    )
                ),
                KeyValueRow(
                    KeyValueData(
                        placentalBiopsyObservationKey,
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment5?.placentalBiopsiObservation?.result.toTextModelOrDefault(),
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment5?.placentalBiopsiObservation?.date,
                        dictionaryCallback(placentalBiopsyObservationKey)
                    )
                ),
                KeyValueRow(
                    KeyValueData(
                        prenatalAmniocentisisObservationKey,
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment6?.prenatalAmniocentesisiObservation?.result.toTextModelOrDefault(),
                        dataCard?.prenatalRiskAssessmentSection?.riskAssessment6?.prenatalAmniocentesisiObservation?.date,
                        dictionaryCallback(prenatalAmniocentisisObservationKey)
                    )
                )
            )
        }

        private fun dictionaryCallback(key: TextModel): (() -> Unit)? {
            return getDictionaryEntryFor(
                viewModelScope, key
            )?.let {
                {
                    _onDictionary.postValue(it.toSingleEvent())
                }
            }
        }

        private fun getDictionaryEntryFor(scope: CoroutineScope, key: TextModel): DictionaryEntry? {
            return dictionaryRepository.getDictionaryEntryFor(scope, key)
        }
    }