# -*- coding: utf-8 -*-

#########################################################################
# pyeole.service._apache - manage apache services
# Copyright © 2013 Pôle de Compétence EOLE <eole@ac-dijon.fr>
#
# License CeCILL:
#  * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
#  * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
#########################################################################

"""EOLE Apache service management

This internal module is only for use by :mod:`pyeole.service`.

"""

from os.path import dirname
from os.path import join
from os.path import isfile
from os.path import islink
from os.path import realpath
from os.path import relpath
from os.path import samefile

from os import symlink
from os import unlink

import re

import logging


# Base exception
from pyeole.service.error import ServiceError
# Configuration
from pyeole.service.error import ConfigureError
from pyeole.service.error import DisabledError
from pyeole.service.error import UnknownServiceError
# Action
from pyeole.service.error import StartError
from pyeole.service.error import StopError

from pyeole.service.launcher import Command

from pyeole.i18n import i18n
_ = i18n('service')

log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())

_APACHE_CTL = u'/usr/sbin/apachectl'
_APACHE_AVAILABLE = u'/etc/apache2/sites-available'
_APACHE_ENABLED = u'/etc/apache2/sites-enabled'
_SERVICE_CMD = u'/usr/sbin/service'


#####
##### Per action workers
#####

class Service(Command):

    module_name = u'Apache'

    def cmd_check_service(self, service, ctx):
        available, enabled = self._build_apache_filenames(service, ctx)

        if not isfile(available):
            msg = _(u'Missing Apache available file for service {0} in {1}: "{2}"')
            raise UnknownServiceError(msg.format(service[u'name'], ctx[u'name'],
                                                 available))

    def cmd_enable_service(self, service, ctx):
        self.cmd_check_service(service, ctx)
        available, enabled = self._build_apache_filenames(service, ctx)
        create_link = True
        if islink(enabled):
            if realpath(enabled) != available:
                msg = u'Wrong link for {0} in {1}, disable the link before recreate it'
                log.debug(msg.format(service[u'name'], ctx[u'name']))
                self.cmd_disable_service(service, ctx)
            else:
                msg = u'Already enabled Apache service {0} in {1}'
                log.debug(msg.format(service[u'name'], ctx[u'name']))
                create_link = False
        if create_link:
            relative_available = relpath(available, dirname(enabled))
            msg = u'Creating enabled link {0} => {1}'
            log.debug(msg.format(enabled, relative_available))
            try:
                symlink(relative_available, enabled)
            except (IOError, OSError) as err:
                msg = u'Can not enable Apache service {0} in {1}: {2}'
                raise ConfigureError(msg.format(service[u'name'], ctx[u'name'], err))


    def cmd_disable_service(self, service, ctx):
        available, enabled = self._build_apache_filenames(service, ctx)
        try:
            if not isfile(enabled):
                msg = u'Already disabled Apache service {0} in {1}'
                log.debug(msg.format(service[u'name'], ctx[u'name']))
            else:
                msg = u'Removing enabled link {0}'
                log.debug(msg.format(enabled))
                unlink(enabled)
        except (IOError, OSError) as err:
            msg = u'Can not disable Apache service {0} in {1}: {2}'
            raise ConfigureError(msg.format(service[u'name'], ctx[u'name'], err))

    #####
    ##### Utilities for Apache
    #####


    def _build_apache_filenames(self, service, ctx):
        """Return the available and enabled filenames of an Apache service.

        :param service: service informations
        :type service: `dict`
        :param ctx: container context
        :type ctx: `dict`
        :return: available and enabled configuration filenames
        :rtype: `tuple`

        """
        name = service[u'name']

        available = join(u'/',
                         ctx[u'path'],
                         _APACHE_AVAILABLE.lstrip(u'/'),
                         name)
        if isfile('{0}.conf'.format(available)):
            available = '{0}.conf'.format(available)
        else:
            msg = u"No '.conf' file for available site {0}"
            log.debug(msg.format(name))

        #similare to a2ensite hack #6160
        if name == 'default':
            name = '000-default'
        enabled = join(u'/',
                       ctx[u'path'],
                       _APACHE_ENABLED.lstrip(u'/'),
                       '{0}.conf'.format(name))

        return available, enabled
