# Copyright 2016 - Nokia
#
# 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 copy
import logging

from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_validation.status_messages import status_msgs
from vitrage.evaluator.template_validation import template_syntax_validator
from vitrage.evaluator.template_validation.template_syntax_validator import \
    EXCEPTION
from vitrage.tests import base
from vitrage.tests.mocks import utils
from vitrage.utils import file as file_utils


BAD_YAML_PATH = 'bad_yaml.yaml'


# noinspection PyAttributeOutsideInit
class TemplateSyntaxValidatorTest(base.BaseTest):

    # noinspection PyPep8Naming
    @classmethod
    def setUpClass(cls):
        super(TemplateSyntaxValidatorTest, cls).setUpClass()

        cls.def_template_dir_path = utils.get_resources_dir() + \
            '/templates/def_template_tests'
        template_dir_path = '%s/templates/general' % utils.get_resources_dir()
        cls.version_dir_path = '%s/templates/version/' \
                               % utils.get_resources_dir()
        cls.template_yamls = file_utils.load_yaml_files(template_dir_path)
        cls.bad_template = \
            cls._load_template_file(template_dir_path + '/' + BAD_YAML_PATH)
        cls.first_template = cls.template_yamls[0]

        cls._hide_useless_logging_messages()

    @property
    def clone_template(self):
        return copy.deepcopy(self.first_template)

    def test_template_validator(self):
        for template in self.template_yamls:
            self._test_execution_with_correct_result(template)

    def test_bad_yaml_validation(self):
        self._test_execution_with_fault_result(self.bad_template, 5)

    def test_validate_template_without_metadata_section(self):

        template = self.clone_template
        template.pop(TemplateFields.METADATA)
        self._test_execution_with_fault_result(template, 62)

    def test_validate_template_without_id_in_metadata_section(self):

        template = self.clone_template
        template[TemplateFields.METADATA].pop(TemplateFields.NAME)
        self._test_execution_with_fault_result(template, 60)

    def test_validate_template_without_definitions_section(self):

        template = self.clone_template
        template.pop(TemplateFields.DEFINITIONS)
        self._test_execution_with_fault_result(template, 21)

    def test_validate_template_without_entities(self):

        template = self.clone_template
        template[TemplateFields.DEFINITIONS].pop(TemplateFields.ENTITIES)
        self._test_execution_with_fault_result(template, 20)

    def test_validate_template_with_empty_entities(self):

        template = self.clone_template
        template[TemplateFields.DEFINITIONS][TemplateFields.ENTITIES] = []
        self._test_execution_with_fault_result(template, 43)

    def test_validate_entity_without_required_fields(self):

        self._validate_entity_without_required_field(
            TemplateFields.CATEGORY, 42)

        self._validate_entity_without_required_field(
            TemplateFields.TEMPLATE_ID, 41)

    def _validate_entity_without_required_field(self,
                                                field_name,
                                                expected_comment):
        template = self.clone_template
        definitions = template[TemplateFields.DEFINITIONS]
        entity = definitions[TemplateFields.ENTITIES][0]
        entity[TemplateFields.ENTITY].pop(field_name)

        self._test_execution_with_fault_result(template, expected_comment)

    def test_validate_entity_with_invalid_template_id(self):
        template = self.clone_template
        definitions = template[TemplateFields.DEFINITIONS]
        entity = definitions[TemplateFields.ENTITIES][0]

        # template_id as integer
        entity[TemplateFields.ENTITY][TemplateFields.TEMPLATE_ID] = 1
        self._test_execution_with_fault_result(template, 1)

        # template_id as string with numbers
        entity[TemplateFields.ENTITY][TemplateFields.TEMPLATE_ID] = '123'
        self._test_execution_with_fault_result(template, 1)

        # template_id as string with numbers
        entity[TemplateFields.ENTITY][TemplateFields.TEMPLATE_ID] = '_'
        self._test_execution_with_fault_result(template, 1)

    def test_validate_correct_template_id_value(self):

        template = self.clone_template
        definitions = template[TemplateFields.DEFINITIONS]
        entity = definitions[TemplateFields.ENTITIES][0]

        entity[TemplateFields.ENTITY][TemplateFields.TEMPLATE_ID] = 'a_a'
        self._test_execution_with_correct_result(template)

        entity[TemplateFields.ENTITY][TemplateFields.TEMPLATE_ID] = 'a'
        self._test_execution_with_correct_result(template)

        entity[TemplateFields.ENTITY][TemplateFields.TEMPLATE_ID] = '_aaa'
        self._test_execution_with_correct_result(template)

        entity[TemplateFields.ENTITY][TemplateFields.TEMPLATE_ID] = '_a123'
        self._test_execution_with_correct_result(template)

    def test_validate_entity_with_invalid_vitrage_category_value(self):

        template = self.clone_template
        definitions = template[TemplateFields.DEFINITIONS]
        entity = definitions[TemplateFields.ENTITIES][0]
        entity[TemplateFields.ENTITY][TemplateFields.CATEGORY] = 'unknown'

        self._test_execution_with_fault_result(template, 45)

    def test_validate_relationships_without_required_fields(self):

        self._validate_relationships_with_missing_required_field(
            TemplateFields.SOURCE, 102)

        self._validate_relationships_with_missing_required_field(
            TemplateFields.TARGET, 103)

        self._validate_relationships_with_missing_required_field(
            TemplateFields.TEMPLATE_ID, 104)

    def _validate_relationships_with_missing_required_field(self,
                                                            field_name,
                                                            expected_comment):
        template = self.clone_template