#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2024 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

import os
import re
import fnmatch
from . import schema_utils as su
from .syntax_checker import SyntaxChecker
from .constraint_checker import ConstraintChecker
from .associated_checker import AssociatedChecker


class SchemaChecker:
    MAPPER_PATH = 'interface_config/redfish/mapping_config'
    SCHEMA_PATH = 'interface_config/redfish/static_resource/redfish/v1/schemastore/en'
    SCHEMAFILE_SCHEMA_PATH = 'schema_check/data_schemafile_schema.json'
    JSON_SCHEMAS_PATH = 'interface_config/redfish/static_resource/redfish/v1/jsonschemas'

    def __init__(self):
        self.mapper_dir = su.get_abspath_under_rackmount(self.MAPPER_PATH)
        self.schema_dir = su.get_abspath_under_rackmount(self.SCHEMA_PATH)
        self.schemafile_schema_path = su.get_abspath_under_rackmount(self.SCHEMAFILE_SCHEMA_PATH)
        self.json_schemas_dir = su.get_abspath_under_rackmount(self.JSON_SCHEMAS_PATH)

    @staticmethod
    def check_dir_syntax(target_dir, schema_path):
        filenames = os.listdir(target_dir)
        schema_json = su.load_json(schema_path)
        syntax_success = True
        for filename in filenames:
            if not filename.endswith('.json'):
                continue
            schemafile_path = os.path.join(target_dir, filename)
            schemafile_json = su.load_json(schemafile_path)
            sc = SyntaxChecker(schema_json, schemafile_json, filename, schemafile_path)
            if not sc.check():
                syntax_success = False
                continue
        return syntax_success
    
    @staticmethod
    def check_dir_constraint(target_dir, schema_dir):
        cons_success = True
        for root, _, files in os.walk(target_dir):
            for filename in files:
                if fnmatch.fnmatch(filename, '*.json'):
                    target_path = os.path.join(root, filename)
                    cc = ConstraintChecker(su.load_json(target_path), target_path, schema_dir)
                    cons_success = cc.check() and cons_success
        return cons_success

    @staticmethod
    def check_dir_associated(json_schemas_dir, schema_dir):
        filenames = os.listdir(schema_dir)
        filenames = [os.path.splitext(f)[0] for f in filenames if f.endswith('.json')]
        asso_success = True
        ac = AssociatedChecker(json_schemas_dir, schema_dir)
        for filename in filenames:
            if ac.check(filename) is False:
                asso_success = False
        return asso_success

    
    def check(self):
        syntax_success = True
        # 检查标准定义文件语法正确性
        syntax_success = self.check_dir_syntax(self.schema_dir, self.schemafile_schema_path)
        # 检查自定义文件语法正确性
        syntax_success = self.check_dir_syntax(os.path.join(self.schema_dir, 'oem'), self.schemafile_schema_path) and syntax_success
        # 语法校验失败，直接退出
        if not syntax_success:
            print('映射器配置检查失败, 构建终止')
            raise Exception("build failed, because errors are found in Data mapping files")
        # 语法校验成功，进行约束性校验
        cons_success = self.check_dir_constraint(self.mapper_dir, self.schema_dir)
        # 关联配置完整性校验
        asso_success = self.check_dir_associated(self.json_schemas_dir, self.schema_dir)
        # 此处syntax_success是为了表达功能完整：通过语法和约束性校验，则检查成功
        if syntax_success is True and cons_success is True and asso_success is True:
            print('=============Schema检查成功=============')
        else:
            print('映射器配置检查失败, 构建终止')
            raise Exception("build failed, because errors are found in Data mapping files")
