/*
 * Copyright (c) 2020-2026 Valve Corporation
 * Copyright (c) 2020-2026 LunarG, Inc.
 *
 * 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.
 *
 * Authors:
 * - Richard S. Wright Jr. <richard@lunarg.com>
 * - Christophe Riccio <christophe@lunarg.com>
 */

#pragma once

#include "setting.h"
#include "layer_preset.h"
#include "version.h"
#include "path.h"
#include "type_layer_type.h"
#include "type_layer_control.h"
#include "type_configurator_mode.h"

#include <QObject>
#include <QJsonDocument>
#include <QJsonObject>

#include <vector>
#include <string>

enum LayerLoadStatus {
    LAYER_LOAD_ADDED = 0,
    LAYER_LOAD_RELOADED,
    LAYER_LOAD_UNMODIFIED,
    LAYER_LOAD_INVALID,
    LAYER_LOAD_IGNORED,

    LAYER_LOAD_FIRST = LAYER_LOAD_ADDED,
    LAYER_LOAD_LAST = LAYER_LOAD_IGNORED,
};

enum { LAYER_LOAD_COUNT = LAYER_LOAD_LAST - LAYER_LOAD_FIRST + 1 };

enum LayerValidated {
    LAYER_VALIDATE_NONE = 0,
    LAYER_VALIDATE_PASS,
    LAYER_VALIDATE_FAIL,

    LAYER_VALIDATE_FIRST = LAYER_VALIDATE_NONE,
    LAYER_VALIDATE_LAST = LAYER_VALIDATE_FAIL,
};

enum { LAYER_VALIDATE_COUNT = LAYER_VALIDATE_LAST - LAYER_VALIDATE_FIRST + 1 };

const char* GetToken(LayerValidated status);

LayerValidated GetLayerValidated(const char* token);

struct LayerId {
    Path manifest_path;
    std::string key;
    Version api_version;
};

struct LayerDescriptor {
    std::string last_modified;
    LayerValidated validated = LAYER_VALIDATE_NONE;
    bool enabled = true;
    bool removed = false;
    bool recent = false;
};

class Layer {
   public:
    enum { NO_PRESET = -1, DEFAULT_PRESET = 0 };

    Layer();
    Layer(const std::string& key);

    LayerId GetId() const;

    bool IsValid() const;

    LayerControl GetActualControl() const;

    int FindPresetIndex(const SettingDataSet& settings) const;

    SettingMeta* Instantiate(SettingMetaSet& meta_set, const std::string& key, const SettingType type);

    void AddSettingData(SettingDataSet& data_set, const QJsonValue& json_setting_value);

    void AddSettingsSet(SettingMetaSet& meta_set, const SettingMeta* parent, const QJsonValue& json_settings_value);
    void AddSettingsDependences(const QJsonValue& json_settings_value);
    void AddSettingsMessages(const QJsonValue& json_settings_value);

    void AddMessages(const QJsonValue& json_messages_value);

    void FillPresetSettings(SettingDataSet& setting_data, const std::vector<SettingMeta*>& settings) const;

   public:
    std::string key;
    std::string prefix;
    Version file_format_version;
    Path binary_path;
    Version api_version;
    std::string implementation_version;
    // std::string last_modified;
    StatusType status;
    std::string description;
    std::string introduction;
    Path url;
    int platforms = PLATFORM_DESKTOP_BIT;
    Path manifest_path;
    LayerType type = LAYER_TYPE_EXPLICIT;
    QJsonDocument profile;
    std::string disable_env;
    std::string enable_env;
    std::string enable_value;
    bool is_32bits = false;

    std::vector<SettingMeta*> settings;
    std::vector<LayerPreset> presets;
    std::vector<Message> messages;

    LayerLoadStatus Load(const QJsonObject& json_layer_object);

    LayerDescriptor descriptor;

   private:
    Layer& operator=(const Layer&) = delete;

    std::vector<std::shared_ptr<SettingMeta> > memory;  // Settings are deleted when all layers instances are deleted.
};

bool operator<(const Layer& layer_a, const Layer& layer_b);

void CollectDefaultSettingData(const SettingMetaSet& meta_set, SettingDataSet& data_set);
void CheckMessage(IgnoredMessages& ignored_messages, const std::vector<Message>& messages, SettingDataSet& data_set);
