# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.

from . import exceptions
from .parser import consumption
from .parser.loading.location import UriLocation


class Core(object):

    def __init__(self,
                 model_storage,
                 resource_storage,
                 plugin_manager):
        self._model_storage = model_storage
        self._resource_storage = resource_storage
        self._plugin_manager = plugin_manager

    @property
    def model_storage(self):
        return self._model_storage

    @property
    def resource_storage(self):
        return self._resource_storage

    @property
    def plugin_manager(self):
        return self._plugin_manager

    def validate_service_template(self, service_template_path):
        self._parse_service_template(service_template_path)

    def create_service_template(self, service_template_path, service_template_dir,
                                service_template_name):
        context = self._parse_service_template(service_template_path)
        service_template = context.modeling.template
        service_template.name = service_template_name
        self.model_storage.service_template.put(service_template)
        self.resource_storage.service_template.upload(
            entry_id=str(service_template.id), source=service_template_dir)

    def delete_service_template(self, service_template_id):
        service_template = self.model_storage.service_template.get(service_template_id)
        if service_template.services:
            raise exceptions.DependentServicesError(
                "Can't delete service template {0} - Service template has existing services")

        self.model_storage.service_template.delete(service_template)
        self.resource_storage.service_template.delete(entry_id=str(service_template.id))

    def create_service(self, service_template_id, inputs, service_name=None):

        service_template = self.model_storage.service_template.get(service_template_id)

        # creating an empty ConsumptionContext, initiating a threadlocal context
        context = consumption.ConsumptionContext()

        storage_session = self.model_storage._all_api_kwargs['session']
        # setting no autoflush for the duration of instantiation - this helps avoid dependency
        # constraints as they're being set up
        with storage_session.no_autoflush:
            service = service_template.instantiate(None, self.model_storage, inputs=inputs)

            consumption.ConsumerChain(
                context,
                (
                    consumption.CoerceServiceInstanceValues,
                    consumption.ValidateServiceInstance,
                    consumption.SatisfyRequirements,
                    consumption.CoerceServiceInstanceValues,
                    consumption.ValidateCapabilities,
                    consumption.FindHosts,
                    consumption.ConfigureOperations,
                    consumption.CoerceServiceInstanceValues
                )).consume()
            if context.validation.dump_issues():
                raise exceptions.InstantiationError('Failed to instantiate service template')

        storage_session.flush()  # flushing so service.id would auto-populate
        service.name = service_name or '{0}_{1}'.format(service_template.name, service.id)
        self.model_storage.service.put(service)
        return service

    def delete_service(self, service_id, force=False):
        service = self.model_storage.service.get(service_id)

        active_executions = [e for e in service.executions if e.is_active()]
        if active_executions:
            raise exceptions.DependentActiveExecutionsError(
                "Can't delete service {0} - there is an active execution for this service. "
                "Active execution id: {1}".format(service.name, active_executions[0].id))

        if not force:
            available_nodes = [str(n.id) for n in service.nodes.values() if n.is_available()]
            if available_nodes:
                raise exceptions.DependentAvailableNodesError(
                    "Can't delete service {0} - there are available nodes for this service. "
                    "Available node ids: {1}".format(service.name, ', '.join(available_nodes)))

        self.model_storage.service.delete(service)

    @staticmethod
    def _parse_service_template(service_template_path):
        context = consumption.ConsumptionContext()
        context.presentation.location = UriLocation(service_template_path)
        consumption.ConsumerChain(
            context,
            (
                consumption.Read,
                consumption.Validate,
                consumption.ServiceTemplate
            )).consume()
        if context.validation.dump_issues():
            raise exceptions.ParsingError('Failed to parse service template')
        return context
