/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.controls.management

import android.text.TextUtils
import android.util.ArrayMap
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.controller.ControlInfo

/**
 * This model is used to show controls separated by zones.
 *
 * The model will sort the controls and zones in the following manner:
 *  * The zones will be sorted in a first seen basis
 *  * The controls in each zone will be sorted in a first seen basis.
 *
 *  The controls passed should belong to the same structure, as an instance of this model will be
 *  created for each structure.
 *
 *  The list of favorite ids can contain ids for controls not passed to this model. Those will be
 *  filtered out.
 *
 * @property controls List of controls as returned by loading
 * @property initialFavoriteIds sorted ids of favorite controls.
 * @property noZoneString text to use as header for all controls that have blank or `null` zone.
 */
class AllModel(
    private val controls: List<ControlStatus>,
    initialFavoriteIds: List<String>,
    private val emptyZoneString: CharSequence
) : ControlsModel {

    override val favorites: List<ControlInfo.Builder>
        get() = favoriteIds.mapNotNull { id ->
            val control = controls.firstOrNull { it.control.controlId == id }?.control
            control?.let {
                ControlInfo.Builder().apply {
                    controlId = it.controlId
                    controlTitle = it.title
                    controlSubtitle = it.subtitle
                    deviceType = it.deviceType
                }
            }
        }

    private val favoriteIds = run {
        val ids = controls.mapTo(HashSet()) { it.control.controlId }
        initialFavoriteIds.filter { it in ids }.toMutableList()
    }

    override val elements: List<ElementWrapper> = createWrappers(controls)

    override fun changeFavoriteStatus(controlId: String, favorite: Boolean) {
        val toChange = elements.firstOrNull {
            it is ControlWrapper && it.controlStatus.control.controlId == controlId
        } as ControlWrapper?
        if (favorite == toChange?.controlStatus?.favorite) return
        if (favorite) {
            favoriteIds.add(controlId)
        } else {
            favoriteIds.remove(controlId)
        }
        toChange?.let {
            it.controlStatus.favorite = favorite
        }
    }

    private fun createWrappers(list: List<ControlStatus>): List<ElementWrapper> {
        val map = list.groupByTo(OrderedMap(ArrayMap<CharSequence, MutableList<ControlStatus>>())) {
            it.control.zone ?: ""
        }
        val output = mutableListOf<ElementWrapper>()
        var emptyZoneValues: Sequence<ControlWrapper>? = null
        for (zoneName in map.orderedKeys) {
            val values = map.getValue(zoneName).asSequence().map { ControlWrapper(it) }
            if (TextUtils.isEmpty(zoneName)) {
                emptyZoneValues = values
            } else {
                output.add(ZoneNameWrapper(zoneName))
                output.addAll(values)
            }
        }
        // Add controls with empty zone at the end
        if (emptyZoneValues != null) {
            if (map.size != 1) {
                output.add(ZoneNameWrapper(emptyZoneString))
            }
            output.addAll(emptyZoneValues)
        }
        return output
    }

    private class OrderedMap<K, V>(private val map: MutableMap<K, V>) : MutableMap<K, V> by map {

        val orderedKeys = mutableListOf<K>()

        override fun put(key: K, value: V): V? {
            if (key !in map) {
                orderedKeys.add(key)
            }
            return map.put(key, value)
        }

        override fun clear() {
            orderedKeys.clear()
            map.clear()
        }

        override fun remove(key: K): V? {
            val removed = map.remove(key)
            if (removed != null) {
                orderedKeys.remove(key)
            }
            return removed
        }
    }
}
