#!/usr/bin/python3 -i
#
# Copyright (c) 2015-2026 The Khronos Group Inc.
# Copyright (c) 2015-2026 Valve Corporation
# Copyright (c) 2015-2026 LunarG, Inc.
# Copyright (c) 2015-2026 Google 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.


import os
from base_generator import BaseGenerator
from generators.generator_utils import PlatformGuardHelper

class FeatureNotPresentGenerator(BaseGenerator):
    def __init__(self):
        BaseGenerator.__init__(self)

    def generate(self):
        out = []
        out.append(f'''// *** THIS FILE IS GENERATED - DO NOT EDIT ***
            // See {os.path.basename(__file__)} for modifications

            /***************************************************************************
            *
            * Copyright (c) 2025-2026 Valve Corporation
            * Copyright (c) 2025-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.
            ****************************************************************************/\n\n''')
        out.append(self.generateSource())
        self.write("".join(out))

    def generateSource(self):
        out = []
        guard_helper = PlatformGuardHelper()
        out.append('''
            #include "chassis/dispatch_object.h"
            #include "generated/dispatch_functions.h"
            #include "error_message/error_location.h"

            namespace vvl {

            void DispatchInstance::ReportErrorFeatureNotPresent(VkPhysicalDevice gpu, const VkDeviceCreateInfo &create_info) {
                std::ostringstream ss;
                ss << "returned VK_ERROR_FEATURE_NOT_PRESENT because the following features were not supported on this physical device:\\n";

                // First do 1.0 VkPhysicalDeviceFeatures
                const auto* features2_in = vku::FindStructInPNextChain<VkPhysicalDeviceFeatures2>(create_info.pNext);
                if (create_info.pEnabledFeatures || features2_in) {
                    const VkPhysicalDeviceFeatures& enabling =
                        create_info.pEnabledFeatures ? *create_info.pEnabledFeatures : features2_in->features;

                    VkPhysicalDeviceFeatures supported = {};
                    DispatchGetPhysicalDeviceFeatures(gpu, &supported);
        ''')

        for member in self.vk.structs['VkPhysicalDeviceFeatures'].members:
            out.append(f'''if (enabling.{member.name} && !supported.{member.name}) {{
                               ss << "VkPhysicalDeviceFeatures::{member.name} is not supported\\n";
                           }}
                        ''')
        out.append('}')
        out.append('''
                    VkPhysicalDeviceFeatures2 features_2 = vku::InitStructHelper();
                    for (const VkBaseInStructure* current = static_cast<const VkBaseInStructure*>(create_info.pNext); current != nullptr; current = current->pNext) {
                        switch(current->sType) {
                    ''')

        feature_structs = self.vk.structs['VkPhysicalDeviceFeatures2'].extendedBy
        for extending_struct_name in feature_structs:
            # TODO - When script is ran by itself this works fine, but when ran together, "VkPhysicalDeviceFeatures" is somehow added to extendedBy
            # Seems to be an issue with the caching, likely the VulkanObject is being overwritten somewhere
            if extending_struct_name == 'VkPhysicalDeviceFeatures':
                continue

            extending_struct = self.vk.structs[extending_struct_name]
            out.extend(guard_helper.add_guard(extending_struct.protect))
            out.append(f'''case {extending_struct.sType}: {{
                            {extending_struct_name} supported = vku::InitStructHelper();
                            features_2.pNext = &supported;
                            DispatchGetPhysicalDeviceFeatures2(gpu, &features_2);
                            const {extending_struct_name} *enabling = reinterpret_cast<const {extending_struct_name} *>(current);
                       ''')

            for member in [x for x in extending_struct.members if x.type == 'VkBool32']:
                out.append(f'''if (enabling->{member.name} && !supported.{member.name}) {{
                                ss << "{extending_struct_name}::{member.name} is not supported\\n";
                            }}
                            ''')
            out.append('break;\n}\n')
            out.extend(guard_helper.add_guard(None))
        out.append('''
                        default:
                            break;
                        }
                    }

                    Location loc(vvl::Func::vkCreateDevice);
                    LogWarning("WARNING-vkCreateDevice-FeatureNotPresent", instance, loc, "%s", ss.str().c_str());
                }  // ReportErrorFeatureNotPresent
                }  // namespace vvl
                ''')
        return "".join(out)
