/*
 * Copyright 2022 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.
 */

// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS

#undef LOG_TAG
#define LOG_TAG "SurfaceFlinger"

#include "LayerLifecycleManager.h"
#include "Client.h" // temporarily needed for LayerCreationArgs
#include "LayerLog.h"
#include "SwapErase.h"

namespace android::surfaceflinger::frontend {

using namespace ftl::flag_operators;

namespace {
// Returns true if the layer is root of a display and can be mirrored by mirroringLayer
bool canMirrorRootLayer(RequestedLayerState& mirroringLayer, RequestedLayerState& rootLayer) {
    return rootLayer.isRoot() && rootLayer.layerStack == mirroringLayer.layerStackToMirror &&
            rootLayer.id != mirroringLayer.id;
}
} // namespace

void LayerLifecycleManager::addLayers(std::vector<std::unique_ptr<RequestedLayerState>> newLayers) {
    if (newLayers.empty()) {
        return;
    }

    mGlobalChanges |= RequestedLayerState::Changes::Hierarchy;
    for (auto& newLayer : newLayers) {
        RequestedLayerState& layer = *newLayer.get();
        auto [it, inserted] = mIdToLayer.try_emplace(layer.id, References{.owner = layer});
        LLOG_ALWAYS_FATAL_WITH_TRACE_IF(!inserted,
                                        "Duplicate layer id found. New layer: %s Existing layer: "
                                        "%s",
                                        layer.getDebugString().c_str(),
                                        it->second.owner.getDebugString().c_str());
        mAddedLayers.push_back(newLayer.get());
        mChangedLayers.push_back(newLayer.get());
        layer.parentId = linkLayer(layer.parentId, layer.id);
        layer.relativeParentId = linkLayer(layer.relativeParentId, layer.id);
        if (layer.layerStackToMirror != ui::INVALID_LAYER_STACK) {
            // Set mirror layer's default layer stack to -1 so it doesn't end up rendered on a
            // display accidentally.
            layer.layerStack = ui::INVALID_LAYER_STACK;

            // if this layer is mirroring a display, then walk though all the existing root layers
            // for the layer stack and add them as children to be mirrored.
            mDisplayMirroringLayers.emplace_back(layer.id);
            for (auto& rootLayer : mLayers) {
                if (canMirrorRootLayer(layer, *rootLayer)) {
                    layer.mirrorIds.emplace_back(rootLayer->id);
                    linkLayer(rootLayer->id, layer.id);
                }
            }
        } else {
            // Check if we are mirroring a single layer, and if so add it to the list of children
            // to be mirrored.
            layer.layerIdToMirror = linkLayer(layer.layerIdToMirror, layer.id);
            if (layer.layerIdToMirror != UNASSIGNED_LAYER_ID) {
                layer.mirrorIds.emplace_back(layer.layerIdToMirror);
            }
        }
        layer.touchCropId = linkLayer(layer.touchCropId, layer.id);
        if (layer.isRoot()) {
            updateDisplayMirrorLayers(layer);
        }
        LLOGV(layer.id, "%s", layer.getDebugString().c_str());
        mLayers.emplace_back(std::move(newLayer));
    }
}

void LayerLifecycleManager::onHandlesDestroyed(
        const std::vector<std::pair<uint32_t, std::string /* debugName */>>& destroyedHandles,
        bool ignoreUnknownHandles) {
    std::vector<uint32_t> layersToBeDestroyed;
    for (const auto& [layerId, name] : destroyedHandles) {
        auto it = mIdToLayer.find(layerId);
        if (it == mIdToLayer.end()) {
            LLOG_ALWAYS_FATAL_WITH_TRACE_IF(!ignoreUnknownHandles, "%s Layerid not found %s[%d]",
                                            __func__, name.c_str(), layerId);
            continue;
        }
        RequestedLayerState& layer = it->second.owner;
        LLOGV(layer.id, "%s", layer.getDebugString().c_str());
        layer.handleAlive = false;
        if (!layer.canBeDestroyed()) {
            continue;
        }
        layer.changes |= RequestedLayerState::Changes::Destroyed;
        layersToBeDestroyed.emplace_back(layerId);
    }

    if (layersToBeDestroyed.empty()) {
        return;
    }

    mGlobalChanges |= RequestedLayerState::Changes::Hierarchy;
    for (size_t i = 0; i < layersToBeDestroyed.size(); i++) {
        uint32_t layerId = layersToBeDestroyed[i];
        auto it = mIdToLayer.find(layerId);
        LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mIdToLayer.end(), "%s Layer with id %d not found",
                                        __func__, layerId);

        RequestedLayerState& layer = it->second.owner;

        layer.parentId = unlinkLayer(layer.parentId, layer.id);
        layer.relativeParentId = unlinkLayer(layer.relativeParentId, layer.id);
        if (layer.layerStackToMirror != ui::INVALID_LAYER_STACK) {
            layer.mirrorIds = unlinkLayers(layer.mirrorIds, layer.id);
            swapErase(mDisplayMirroringLayers, layer.id);
        } else {
            layer.layerIdToMirror = unlinkLayer(layer.layerIdToMirror, layer.id);
            layer.mirrorIds.clear();
        }

        layer.touchCropId = unlinkLayer(layer.touchCropId, layer.id);

        auto& references = it->second.references;
        for (uint32_t linkedLayerId : references) {
            RequestedLayerState* linkedLayer = getLayerFromId(linkedLayerId);
            LLOG_ALWAYS_FATAL_WITH_TRACE_IF(!linkedLayer,
                                            "%s Layerid reference %d not found for %d", __func__,
                                            linkedLayerId, layer.id);
            if (linkedLayer->parentId == layer.id) {
                linkedLayer->parentId = UNASSIGNED_LAYER_ID;
                if (linkedLayer->canBeDestroyed()) {
                    linkedLayer->changes |= RequestedLayerState::Changes::Destroyed;
                    layersToBeDestroyed.emplace_back(linkedLayer->id);
                }
            }
            if (linkedLayer->relativeParentId == layer.id) {
                linkedLayer->relativeParentId = UNASSIGNED_LAYER_ID;
            }
            if (swapErase(linkedLayer->mirrorIds, layer.id)) {
                linkedLayer->changes |= RequestedLayerState::Changes::Mirror;
            }
            if (linkedLayer->touchCropId == layer.id) {
                linkedLayer->touchCropId = UNASSIGNED_LAYER_ID;
            }
        }
        mIdToLayer.erase(it);
    }

    auto it = mLayers.begin();
    while (it != mLayers.end()) {
        RequestedLayerState* layer = it->get();
        if (layer->changes.test(RequestedLayerState::Changes::Destroyed)) {
            LLOGV(layer->id, "destroyed %s", layer->getDebugStringShort().c_str());
            std::iter_swap(it, mLayers.end() - 1);
            mDestroyedLayers.emplace_back(std::move(mLayers.back()));
            if (it == mLayers.end() - 1) {
                it = mLayers.erase(mLayers.end() - 1);
            } else {
                mLayers.erase(mLayers.end() - 1);
            }
        } else {
            it++;
        }
    }
}

void LayerLifecycleManager::applyTransactions(const std::vector<TransactionState>& transactions,
                                              bool ignoreUnknownLayers) {
    for (const auto& transaction : transactions) {
        for (const auto& resolvedComposerState : transaction.states) {
            const auto& clientState = resolvedComposerState.state;
            uint32_t layerId = resolvedComposerState.layerId;
            if (layerId == UNASSIGNED_LAYER_ID) {
                ALOGW("%s Handle %p is not valid", __func__, clientState.surface.get());
                continue;
            }

            RequestedLayerState* layer = getLayerFromId(layerId);
            if (layer == nullptr) {
                LLOG_ALWAYS_FATAL_WITH_TRACE_IF(!ignoreUnknownLayers,
                                                "%s Layer with layerid=%d not found", __func__,
                                                layerId);
                continue;
            }

            LLOG_ALWAYS_FATAL_WITH_TRACE_IF(!layer->handleAlive,
                                            "%s Layer's with layerid=%d) is not alive. Possible "
                                            "out of "
                                            "order LayerLifecycleManager updates",
                                            __func__, layerId);

            if (layer->changes.get() == 0) {
                mChangedLayers.push_back(layer);
            }

            if (transaction.flags & ISurfaceComposer::eAnimation) {
                layer->changes |= RequestedLayerState::Changes::Animation;
            }

            uint32_t oldParentId = layer->parentId;
            uint32_t oldRelativeParentId = layer->relativeParentId;
            uint32_t oldTouchCropId = layer->touchCropId;
            layer->merge(resolvedComposerState);

            if (layer->what & layer_state_t::eBackgroundColorChanged) {
                if (layer->bgColorLayerId == UNASSIGNED_LAYER_ID && layer->bgColor.a != 0) {
                    LayerCreationArgs
                            backgroundLayerArgs(LayerCreationArgs::getInternalLayerId(
                                                        LayerCreationArgs::sInternalSequence++),
                                                /*internalLayer=*/true);
                    backgroundLayerArgs.parentId = layer->id;
                    backgroundLayerArgs.name = layer->name + "BackgroundColorLayer";
                    backgroundLayerArgs.flags = ISurfaceComposerClient::eFXSurfaceEffect;
                    std::vector<std::unique_ptr<RequestedLayerState>> newLayers;
                    newLayers.emplace_back(
                            std::make_unique<RequestedLayerState>(backgroundLayerArgs));
                    RequestedLayerState* backgroundLayer = newLayers.back().get();
                    backgroundLayer->bgColorLayer = true;
                    backgroundLayer->handleAlive = false;
                    backgroundLayer->parentId = layer->id;
                    backgroundLayer->z = std::numeric_limits<int32_t>::min();
                    backgroundLayer->color = layer->bgColor;
                    backgroundLayer->dataspace = layer->bgColorDataspace;
                    layer->bgColorLayerId = backgroundLayer->id;
                    addLayers({std::move(newLayers)});
                } else if (layer->bgColorLayerId != UNASSIGNED_LAYER_ID && layer->bgColor.a == 0) {
                    RequestedLayerState* bgColorLayer = getLayerFromId(layer->bgColorLayerId);
                    layer->bgColorLayerId = UNASSIGNED_LAYER_ID;
                    bgColorLayer->parentId = unlinkLayer(bgColorLayer->parentId, bgColorLayer->id);
                    onHandlesDestroyed({{bgColorLayer->id, bgColorLayer->debugName}});
                } else if (layer->bgColorLayerId != UNASSIGNED_LAYER_ID) {
                    RequestedLayerState* bgColorLayer = getLayerFromId(layer->bgColorLayerId);
                    bgColorLayer->color = layer->bgColor;
                    bgColorLayer->dataspace = layer->bgColorDataspace;
                    bgColorLayer->what |= layer_state_t::eColorChanged |
                            layer_state_t::eDataspaceChanged | layer_state_t::eAlphaChanged;
                    bgColorLayer->changes |= RequestedLayerState::Changes::Content;
                    mChangedLayers.push_back(bgColorLayer);
                    mGlobalChanges |= RequestedLayerState::Changes::Content;
                }
            }

            if (oldParentId != layer->parentId) {
                unlinkLayer(oldParentId, layer->id);
                layer->parentId = linkLayer(layer->parentId, layer->id);
                if (oldParentId == UNASSIGNED_LAYER_ID) {
                    updateDisplayMirrorLayers(*layer);
                }
            }
            if (layer->what & layer_state_t::eLayerStackChanged && layer->isRoot()) {
                updateDisplayMirrorLayers(*layer);
            }
            if (oldRelativeParentId != layer->relativeParentId) {
                unlinkLayer(oldRelativeParentId, layer->id);
                layer->relativeParentId = linkLayer(layer->relativeParentId, layer->id);
            }
            if (oldTouchCropId != layer->touchCropId) {
                unlinkLayer(oldTouchCropId, layer->id);
                layer->touchCropId = linkLayer(layer->touchCropId, layer->id);
            }

            mGlobalChanges |= layer->changes;
        }
    }
}

void LayerLifecycleManager::commitChanges() {
    for (auto layer : mAddedLayers) {
        for (auto& listener : mListeners) {
            listener->onLayerAdded(*layer);
        }
    }
    mAddedLayers.clear();

    for (auto& layer : mLayers) {
        layer->clearChanges();
    }

    for (auto& destroyedLayer : mDestroyedLayers) {
        for (auto& listener : mListeners) {
            listener->onLayerDestroyed(*destroyedLayer);
        }
    }
    mDestroyedLayers.clear();
    mChangedLayers.clear();
    mGlobalChanges.clear();
}

void LayerLifecycleManager::addLifecycleListener(std::shared_ptr<ILifecycleListener> listener) {
    mListeners.emplace_back(std::move(listener));
}

void LayerLifecycleManager::removeLifecycleListener(std::shared_ptr<ILifecycleListener> listener) {
    swapErase(mListeners, listener);
}

const std::vector<std::unique_ptr<RequestedLayerState>>& LayerLifecycleManager::getLayers() const {
    return mLayers;
}

const std::vector<std::unique_ptr<RequestedLayerState>>& LayerLifecycleManager::getDestroyedLayers()
        const {
    return mDestroyedLayers;
}

const std::vector<RequestedLayerState*>& LayerLifecycleManager::getChangedLayers() const {
    return mChangedLayers;
}

const ftl::Flags<RequestedLayerState::Changes> LayerLifecycleManager::getGlobalChanges() const {
    return mGlobalChanges;
}

const RequestedLayerState* LayerLifecycleManager::getLayerFromId(uint32_t id) const {
    if (id == UNASSIGNED_LAYER_ID) {
        return nullptr;
    }
    auto it = mIdToLayer.find(id);
    if (it == mIdToLayer.end()) {
        return nullptr;
    }
    return &it->second.owner;
}

RequestedLayerState* LayerLifecycleManager::getLayerFromId(uint32_t id) {
    if (id == UNASSIGNED_LAYER_ID) {
        return nullptr;
    }
    auto it = mIdToLayer.find(id);
    if (it == mIdToLayer.end()) {
        return nullptr;
    }
    return &it->second.owner;
}

std::vector<uint32_t>* LayerLifecycleManager::getLinkedLayersFromId(uint32_t id) {
    if (id == UNASSIGNED_LAYER_ID) {
        return nullptr;
    }
    auto it = mIdToLayer.find(id);
    if (it == mIdToLayer.end()) {
        return nullptr;
    }
    return &it->second.references;
}

uint32_t LayerLifecycleManager::linkLayer(uint32_t layerId, uint32_t layerToLink) {
    if (layerId == UNASSIGNED_LAYER_ID) {
        return UNASSIGNED_LAYER_ID;
    }

    std::vector<uint32_t>* linkedLayers = getLinkedLayersFromId(layerId);
    if (!linkedLayers) {
        ALOGV("Could not find layer id %d to link %d. Parent is probably destroyed", layerId,
              layerToLink);
        return UNASSIGNED_LAYER_ID;
    }
    linkedLayers->emplace_back(layerToLink);
    return layerId;
}

uint32_t LayerLifecycleManager::unlinkLayer(uint32_t layerId, uint32_t linkedLayer) {
    std::vector<uint32_t>* linkedLayers = getLinkedLayersFromId(layerId);
    if (!linkedLayers) {
        return UNASSIGNED_LAYER_ID;
    }
    swapErase(*linkedLayers, linkedLayer);
    return UNASSIGNED_LAYER_ID;
}

std::vector<uint32_t> LayerLifecycleManager::unlinkLayers(const std::vector<uint32_t>& layerIds,
                                                          uint32_t linkedLayer) {
    for (uint32_t layerId : layerIds) {
        unlinkLayer(layerId, linkedLayer);
    }
    return {};
}

std::string LayerLifecycleManager::References::getDebugString() const {
    std::string debugInfo = owner.name + "[" + std::to_string(owner.id) + "] refs:";
    std::for_each(references.begin(), references.end(),
                  [&debugInfo = debugInfo](const uint32_t& reference) mutable {
                      debugInfo += std::to_string(reference) + ",";
                  });
    return debugInfo;
}

void LayerLifecycleManager::fixRelativeZLoop(uint32_t relativeRootId) {
    auto it = mIdToLayer.find(relativeRootId);
    if (it == mIdToLayer.end()) {
        return;
    }
    RequestedLayerState& layer = it->second.owner;
    layer.relativeParentId = unlinkLayer(layer.relativeParentId, layer.id);
    layer.changes |=
            RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::RelativeParent;
    mGlobalChanges |= RequestedLayerState::Changes::Hierarchy;
}

// Some layers mirror the entire display stack. Since we don't have a single root layer per display
// we have to track all these layers and update what they mirror when the list of root layers
// on a display changes. This function walks through the list of display mirroring layers
// and updates its list of layers that its mirroring. This function should be called when a new
// root layer is added, removed or moved to another display.
void LayerLifecycleManager::updateDisplayMirrorLayers(RequestedLayerState& rootLayer) {
    for (uint32_t mirroringLayerId : mDisplayMirroringLayers) {
        RequestedLayerState* mirrorLayer = getLayerFromId(mirroringLayerId);
        bool canBeMirrored = canMirrorRootLayer(*mirrorLayer, rootLayer);
        bool currentlyMirrored =
                std::find(mirrorLayer->mirrorIds.begin(), mirrorLayer->mirrorIds.end(),
                          rootLayer.id) != mirrorLayer->mirrorIds.end();

        if (canBeMirrored && !currentlyMirrored) {
            mirrorLayer->mirrorIds.emplace_back(rootLayer.id);
            linkLayer(rootLayer.id, mirrorLayer->id);
            mirrorLayer->changes |= RequestedLayerState::Changes::Mirror;
        } else if (!canBeMirrored && currentlyMirrored) {
            swapErase(mirrorLayer->mirrorIds, rootLayer.id);
            unlinkLayer(rootLayer.id, mirrorLayer->id);
            mirrorLayer->changes |= RequestedLayerState::Changes::Mirror;
        }
    }
}

bool LayerLifecycleManager::isLayerSecure(uint32_t layerId) const {
    if (layerId == UNASSIGNED_LAYER_ID) {
        return false;
    }

    if (getLayerFromId(layerId)->flags & layer_state_t::eLayerSecure) {
        return true;
    }
    return isLayerSecure(getLayerFromId(layerId)->parentId);
}

} // namespace android::surfaceflinger::frontend
