class DataManager(object):
    def __init__(self):
    def is_ready(self):
    def update_database(self, item_type, items_list):
    def get_item(self, item_type, key, value=None):
    def remove_item(self, item_type, key, value=None):
    def update_item_data(self, item_type, item_id, data):
    def get_realm_name(self, realm):
    def get_period_name(self, period):
    def get_synthesis_count(self):
    def get_all_hostnames(self):
    def get_host_services(self, host_id):
    def get_host_with_services(self, host_field):
    def get_events(self):
    def get_items_and_problems(self):
    def update_problems(self):
    def get_problems(self):
    def is_problem(item_type, item_data): class WSClient(object):
    """
        Class who manage Web Service requests
    """

    def __init__(self):
        self.ws_backend = ''
        self.token = ''
        self.auth = None

    def login(self, token):
        """
        Login to Web Service. Used only to ensure that the user token is identical

        :param token: user's token of App
        :type token: str
        """

        self.ws_backend = settings.get_config('Alignak', 'webservice')

        try:
            # WS login
            logger.info("Requesting Web Service authentication with token: %s", token)
            headers = {'Content-Type': 'application/json'}
            params = {'username': token, 'password': ''}
            response = requests.post(
                '/'.join([self.ws_backend, 'login']), json=params, headers=headers
            )

            resp = response.json()

            if '_result' in resp:
                assert token == resp['_result'][0]
                self.token = token
                self.auth = requests.auth.HTTPBasicAuth(self.token, '')
        except (RequestsConnectionError, AssertionError) as exp:
            msg = 'Connection to Web Service on [%s] has failed' % \
                  '/'.join([self.ws_backend, 'login'])
            logger.warning(msg)
            logger.debug(exp)

    def get(self, endpoint, params):  # pragma: no cover
        """
        GET on alignak Backend Web Service

        :param endpoint: WS endpoint
        :type endpoint: str
        :param params: dict of parameters for the WS
        :type params: dict|None
        :return: request result
        :rtype: dict
        """

        request = None

        try:
            request = requests.get(
                '/'.join([self.ws_backend, endpoint]), params=params, auth=self.auth
            )
            logger.info('GET on [%s] web service > %s', endpoint, str(request))

            request.raise_for_status()
            logger.debug('\tparams: [%s]', str(params))

        except RequestsConnectionError as exp:
            logger.error("Backend connection error, error: %s", exp)

        return request.json()

    def post(self, endpoint, params=None):  # pragma: no cover
        """
        Post on alignak Backend Web Service

        :param endpoint: WS endpoint
        :type endpoint: str
        :param params: dict of parameters for the WS
        :type params: dict
        :return: list of properties when query item | list of items when get many items
        :rtype: list
        """

        request = None

        try:
            headers = {'Content-Type': 'application/json'}
            params = json.dumps(params)

            request = requests.post(
                '/'.join([self.ws_backend, endpoint]), data=params, headers=headers, auth=self.auth
            )

            request.raise_for_status()
            logger.info('POST on [%s] backend > %s', endpoint, str(request))
            logger.debug('\tdata: [%s]', str(params))
            logger.debug('\theaders: [%s]', str(headers))
        except (RequestsConnectionError, HTTPError) as exp:
            logger.warning("WS connection error, error: %s", str(exp))

        except Exception as exp:
            logger.exception("WS exception, error: %s", exp)

        return request.json() class Daemon(Item):
    """
        Class who create a daemon item
    """

    def __init__(self):
        super(Daemon, self).__init__()
        self.item_type = 'alignakdaemon'

    @staticmethod
    def get_request_model():
        """
        Return the request model for alignakdaemon requests

        :return: request model for alignakdaemon endpoint
        :rtype: dict
        """

        daemons_projection = [
            'alive', 'type', 'name', 'reachable', 'spare', 'address', 'port', 'passive',
            'last_check'
        ]

        request_model = {
            'endpoint': 'alignakdaemon',
            'params': None,
            'projection': daemons_projection
        }

        return request_model

    @staticmethod
    def get_daemons_names():
        """
        Returns all the names of daemons

        :return: all the names of daemons
        :rtype: list
        """

        return [
            'poller',
            'receiver',
            'reactionner',
            'arbiter',
            'scheduler',
            'broker'
        ]

    @staticmethod
    def get_states(status):
        """
        Return states of daemons or backend

        :param status: status of item
        :type status: str
        :return: the status string
        :rtype: str
        """

        states = {
            'ok': 'connected',
            'flapping': 'flapping',
            'ko': 'disconnected',
            'not_connect': 'not_connect',
        }

        return states[status]

    @staticmethod
    def get_daemons_status_icon():
        """
        Return daemons status icon name

        :return: daemons status icon name
        :rtype: str
        """

        alignak_daemons = data_manager.database['alignakdaemon']

        daemons_down = 0
        daemons_nb = len(alignak_daemons)
        for daemon in alignak_daemons:
            daemons_nb += 1
            if not daemon.data['alive']:
                daemons_down += 1

        if daemons_down == daemons_nb:
            status = 'ko'
        elif daemons_down > 0:
            status = 'flapping'
        else:
            status = 'ok'

        if daemons_nb == 0:
            status = 'not_connect'

        return Daemon.get_states(status) class Event(Item):
    """
        Class who create an event item
    """

    def __init__(self):
        super(Event, self).__init__()
        self.item_type = 'notification'

    @staticmethod
    def get_request_model():
        """
        Return the request model for notification requests

        :return: request model for history endpoint (only for notifications)
        :rtype: dict
        """

        notification_projection = {
            'message', '_updated', 'host'
        }

        # Backend use time format in "en_US", so switch if needed
        if "en_US" not in locale.getlocale(locale.LC_TIME) and 'win32' not in sys.platform:
            locale.setlocale(locale.LC_TIME, "en_US.utf-8")
            logger.debug(
                "App set locale to %s for converting date", locale.getlocale(locale.LC_TIME)
            )

        # Define time for the last X minutes define in config file for events
        notif_elapsed = int(settings.get_config('Alignak-app', 'notification_elapsed'))
        time_interval = (datetime.datetime.utcnow() - datetime.timedelta(minutes=notif_elapsed)) \
            .strftime("%a, %d %b %Y %H:%M:%S GMT")

        request_model = {
            'endpoint': 'history',
            'params': {
                'where': json.dumps({
                    'type': 'monitoring.notification',
                    '_updated': {"$gte": time_interval},
                }),
                'sort': '-_updated'
            },
            'projection': notification_projection
        }

        return request_model class History(Item):
    """
        Class who create a history item
    """

    def __init__(self):
        super(History, self).__init__()
        self.item_type = 'history'

    @staticmethod
    def get_request_model():
        """
        Return the request model for history requests

        :return: request model for history endpoint
        :rtype: dict
        """

        request_model = {
            'endpoint': 'history',
            'params': {
                'sort': '-_id',
            },
            'projection': ['service_name', 'message', 'type']
        }

        return request_model

    @staticmethod
    def get_history_icon_name(message, event_type):
        """
        Return icon name related to message or event type

        :param message: message of an history event
        :type message: str
        :param event_type: type of history event
        :type event_type: str
        :return: icon name
        :rtype: str
        """

        if 'ack' in event_type:
            icon_name = 'acknowledge'
        elif 'downtime' in event_type:
            icon_name = 'downtime'
        elif 'comment' in event_type:
            icon_name = 'event_info'
        elif 'request' in event_type:
            icon_name = 'request'
        else:
            if 'UP' in message:
                icon_name = 'hosts_up'
            elif 'DOWN' in message:
                icon_name = 'hosts_down'
            elif 'UNREACHABLE' in message:
                icon_name = 'services_unreachable'
            elif 'OK' in message:
                icon_name = 'services_ok'
            elif 'WARNING' in message:
                icon_name = 'services_warning'
            elif 'CRITICAL' in message:
                icon_name = 'services_critical'
            elif 'UNKNOWN' in message:
                icon_name = 'services_unknown'
            else:
                icon_name = 'error'

        return icon_name class Host(Item):
    """
        Class who create a host item
    """

    def __init__(self):
        super(Host, self).__init__()
        self.item_type = 'host'

    @staticmethod
    def get_request_model():
        """
        Return the request model for host requests

        :return: request model for host endpoint
        :rtype: dict
        """

        hosts_projection = [
            'name', 'alias', 'ls_state', '_id', 'ls_acknowledged', 'ls_downtimed', 'ls_last_check',
            'ls_output', 'address', 'business_impact', 'notes', '_realm', 'passive_checks_enabled',
            'active_checks_enabled', '_overall_state_id', 'customs'
        ]

        request = {
            'endpoint': 'host',
            'params': {'where': json.dumps({'_is_template': False})},
            'projection': hosts_projection
        }

        return request

    @staticmethod
    def get_available_icons():
        """
        Return list of available icons for a Host item

        :return: list of available icons for Host
        :rtype: list
        """

        return ['hosts_up', 'hosts_unreachable', 'hosts_down', 'acknowledge',
                'downtime', 'hosts_not_monitored']

    def get_display_name(self):
        """
        Return alias or name if available

        :return: name or alias
        :rtype: str
        """

        if 'alias' in self.data:
            return self.data['alias'].title()

        return self.name.title()

    def get_overall_tooltip(self, services):
        """
        Return corresponding overall state tooltip depends of ``_overall_state_id`` of Host and its
        Services

        :param services: list of Service items
        :type services: list
        :return: overall tooltip message
        :rtype: str
        """

        host_msg = self.get_tooltip()

        event_messages = [
            _('%s. You have nothing to do.') % host_msg,
            _('%s and his services are ok or acknowledged.') % host_msg,
            _('%s and his services are ok or downtimed.') % host_msg,
            _('%s, some services may be unknown.') % host_msg,
            _('%s, some services may be in critical condition or unreachable !') % host_msg,
            _('%s, some services are not monitored.') % host_msg,
        ]

        state_lvl = []

        for service in services:
            state_lvl.append(service.data['_overall_state_id'])

        state_lvl.append(self.data['_overall_state_id'])

        try:
            max_state_lvl = max(state_lvl)
            overall_tooltip = event_messages[max_state_lvl]

            if not services:
                overall_tooltip = '%s, no services...' % host_msg
        except IndexError as e:
            logger.error('Can\'t get overall tooltip, %s', e)
            return host_msg

        return overall_tooltip class LiveSynthesis(Item):
    """
        Class who create livesynthesis item
    """

    def __init__(self):
        super(LiveSynthesis, self).__init__()
        self.item_type = 'livesynthesis'

    @staticmethod
    def get_request_model():
        """
        Return the request model for livesynthesis requests

        :return: request model for livesynthesis endpoint
        :rtype: dict
        """

        request = {
            'endpoint': 'livesynthesis',
            'params': None,
            'projection': None
        }

        return request

    @staticmethod
    def get_synthesis_count_model():
        """
        Return the synthesis count model

        :return: synthesis count model
        :rtype: dict
        """

        synthesis_count_model = {
            'hosts': {
                'up': 0,
                'down': 0,
                'unreachable': 0,
                'acknowledge': 0,
                'downtime': 0,
                'not_monitored': 0
            },
            'services': {
                'ok': 0,
                'critical': 0,
                'unknown': 0,
                'warning': 0,
                'unreachable': 0,
                'acknowledge': 0,
                'downtime': 0,
                'not_monitored': 0
            }
        }

        return synthesis_count_model class Service(Item):
    """
        Class who create a service item
    """

    def __init__(self):
        super(Service, self).__init__()
        self.item_type = 'service'

    @staticmethod
    def get_request_model(host_id=None):
        """
        Return the request model for service requests

        :param host_id: "_id" of host, needed to get only host services
        :type host_id: str
        :return: request model for service endpoint
        :rtype: dict
        """

        services_projection = [
            'name', 'alias', 'ls_state', 'ls_acknowledged', 'ls_downtimed', 'ls_last_check',
            'ls_output', '_overall_state_id', 'aggregation', 'host', 'passive_checks_enabled',
            'active_checks_enabled'
        ]

        request_model = {
            'endpoint': 'service',
            'projection': services_projection
        }

        if host_id:
            request_model['params'] = {
                'where': json.dumps({'_is_template': False, 'host': host_id})
            }
        else:
            request_model['params'] = {'where': json.dumps({'_is_template': False})}

        return request_model

    @staticmethod
    def get_service_states_nb():
        """
        Return all service state in a dict with int() as zero

        :return: all service state with int() as zero
        :rtype: dict
        """

        return {
            'OK': 0,
            'UNKNOWN': 0,
            'WARNING': 0,
            'UNREACHABLE': 0,
            'CRITICAL': 0,
            'NOT_MONITORED': 0,
            'ACKNOWLEDGE': 0,
            'DOWNTIME': 0
        }

    @staticmethod
    def get_available_icons():
        """
        Return list of available icons for a Service item

        :return: list of available icons for Service
        :rtype: list
        """

        return [
            'services_ok', 'services_warning', 'services_critical', 'services_unknown',
            'services_unreachable', 'services_not_monitored', 'acknowledge', 'downtime'
        ]

    def get_display_name(self):
        """
        Return alias or name if available

        :return: name or alias
        :rtype: str
        """

        if 'alias' in self.data:
            return self.data['alias'].title()

        return self.name.title() class User(Item):
    """
        Class who create user item for backend ``user`` endpoint
    """

    def __init__(self):
        super(User, self).__init__()
        self.item_type = 'user'

    @staticmethod
    def get_request_model(token):
        """
        Return the request model for user requests

        :param token: token of user
        :type token: str
        :return: request model for user endpoint
        :rtype: dict
        """

        user_projection = {
            '_realm', 'is_admin', 'back_role_super_admin', 'alias', 'name', 'notes', 'email',
            'can_submit_commands', 'token', 'host_notifications_enabled',
            'service_notifications_enabled', 'host_notification_period',
            'service_notification_period', 'host_notification_options',
            'service_notification_options',
        }

        request = {
            'endpoint': 'user',
            'params': {'where': json.dumps({'token': token})},
            'projection': user_projection
        }

        return request

    def get_role(self):
        """
        Get user role

        :return: role of user
        :rtype: str
        """

        role = _('user')

        if self.data['is_admin'] or \
                self.data['back_role_super_admin']:
            role = _('administrator')
        if self.data['can_submit_commands'] and not \
                self.data['is_admin'] and not \
                self.data['back_role_super_admin']:
            role = _('power')

        return role class Realm(Item):
    """
        Class who create a realm item
    """

    def __init__(self):
        super(Realm, self).__init__()
        self.item_type = 'realm'

    @staticmethod
    def get_request_model():
        """
        Return the request model for realm requests

        :return: request model for realm endpoint
        :rtype: dict
        """

        realms_projection = [
            'name', 'alias'
        ]

        request_model = {
            'endpoint': 'realm',
            'params': None,
            'projection': realms_projection
        }

        return request_model

    def get_display_name(self):
        """
        Return alias or name if available

        :return: name or alias
        :rtype: str
        """

        if 'alias' in self.data:
            return self.data['alias'].title()

        return self.data['name'].title() class Period(Item):
    """
        Class who create a period item
    """

    def __init__(self):
        super(Period, self).__init__()
        self.item_type = 'timeperiod'

    @staticmethod
    def get_request_model():
        """
        Return the request model for timeperiod requests

        :return: request model for timeperiod endpoint
        :rtype: dict
        """

        realms_projection = [
            'name', 'alias'
        ]

        request_model = {
            'endpoint': 'timeperiod',
            'params': None,
            'projection': realms_projection
        }

        return request_model

    def get_display_name(self):
        """
        Return alias or name if available

        :return: name or alias
        :rtype: str
        """

        if 'alias' in self.data:
            return self.data['alias'].title()

        return self.data['name'].title() class Settings(object):
    def __init__(self):
    def init_config(self):
    def get_config(self, section, option, boolean=False):
    def set_config(self, section, option, new_value):
    def get_image(self, name):
    def init_css(self):
def open_url(endpoint='login'):  # pragma: no cover
def get_url_endpoint_from_icon_name(icon_name):
import json
from logging import getLogger
from alignak_backend_client.client import Backend, BackendException
from alignak_app.backend.datamanager import data_manager
from alignak_app.backend.ws_client import WSClient
from alignak_app.items.daemon import Daemon
from alignak_app.items.event import Event
from alignak_app.items.history import History
from alignak_app.items.host import Host
from alignak_app.items.livesynthesis import LiveSynthesis
from alignak_app.items.service import Service
from alignak_app.items.user import User
from alignak_app.items.realm import Realm
from alignak_app.items.period import Period
from alignak_app.utils.config import settings
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2015-2018:
#   Matthieu Estrada, ttamalfor@gmail.com
#
# This file is part of (AlignakApp).
#
# (AlignakApp) is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# (AlignakApp) is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with (AlignakApp).  If not, see <http://www.gnu.org/licenses/>.

"""
    Backend
    +++++++
    Backend manage connection and access to Alignak backend. It also fill
    :class:`DataManager <alignak_app.backend.datamanager.DataManager>`.
"""







logger = getLogger(__name__)


class BackendClient(object):
    """
        Class who collect informations with Backend-Client and returns data for Alignak-App.
    """

    connection_status = {
        True: 'Success',
        False: 'Failure'
    }

    def __init__(self):
        self.backend = None
        self.connected = False
        self.user = {}
        self.ws_client = WSClient()

    def login(self, username=None, password=None, proxies=None, check=False):
        """
        Connect to alignak backend

        :param username: name or token of user
        :type username: str
        :param password: password of user. If token given, this parameter is useless
        :type password: str
        :param proxies: dictionnary for proxy
        :type proxies: dict
        :param check: define if login is a check or a first login
        :type check: bool
        :return: True if connected or False if not
        :rtype: bool
        """

        # Credentials
        if not username and not password:
            if 'token' in self.user:
                username = self.user['token']

        # Create Backend object

        backend_url = settings.get_config('Alignak', 'backend')