# -*- coding: utf-8 -*-
"""
Helper functions used in views.
"""

import csv
from lxml import etree
from json import dumps
from functools import wraps
from datetime import datetime

from flask import Response

from presence_analyzer.main import app

import logging
log = logging.getLogger(__name__)  # pylint: disable=C0103


def jsonify(function):
    """
    Creates a response with the JSON representation of wrapped function result.
    """
    @wraps(function)
    def inner(*args, **kwargs):
        """
        Inner function of jsonify.
        """
        return Response(dumps(function(*args, **kwargs)),
                        mimetype='application/json')
    return inner


def get_menu_data():
    """
    Extracts menu data from CSV file

    It creates structure like this:
    data = [{
        'link': 'mainpage',
        'title': 'This is mainpage'
    }]
    """
    data = []
    with open(app.config['MENU_CSV'], 'r') as csvfile:
        menu_reader = csv.reader(csvfile, delimiter=',')
        for row in menu_reader:
            data.append({
                'link': row[0],
                'title': row[1]
            })

    return data


@app.template_global()
def get_menu(page_url):
    """
    Gets links and their titles.
    Adds 'selected' attribute to current page.
    """
    pages = get_menu_data()

    for page in pages:
        if page.get('link') == page_url:
            page['selected'] = True

    return pages


@app.template_global()
def get_users():
    """
    Gets dictionary with users data imported from xml file
    """
    data = etree.parse(app.config['DATA_USERS']).getroot()
    server = data.find('server')
    host = '{0}://{1}:{2}'.format(
        server.find('protocol').text,
        server.find('host').text,
        server.find('port').text,
    )
    data_users = data.find('users')
    users = {
        user.get('id'): {
            'name': unicode(user.find('name').text),
            'avatar': host + user.find('avatar').text
            } for user in data_users
        }

    return users


def get_data():
    """
    Extracts presence data from CSV file and groups it by user_id.

    It creates structure like this:
    data = {
        'user_id': {
            datetime.date(2013, 10, 1): {
                'start': datetime.time(9, 0, 0),
                'end': datetime.time(17, 30, 0),
            },
            datetime.date(2013, 10, 2): {
                'start': datetime.time(8, 30, 0),
                'end': datetime.time(16, 45, 0),
            },
        }
    }
    """
    data = {}

    with open(app.config['DATA_CSV'], 'r') as csvfile:
        presence_reader = csv.reader(csvfile, delimiter=',')
        for i, row in enumerate(presence_reader):
            if len(row) != 4:
                # ignore header and footer lines
                continue

            try:
                user_id = int(row[0])
                date = datetime.strptime(row[1], '%Y-%m-%d').date()
                start = datetime.strptime(row[2], '%H:%M:%S').time()
                end = datetime.strptime(row[3], '%H:%M:%S').time()
                data.setdefault(user_id, {})[date] = {
                    'start': start,
                    'end': end
                }
            except (ValueError, TypeError):
                log.debug('Problem with line %d: ', i, exc_info=True)

    return data


def group_by_weekday(items):
    """
    Groups presence entries by weekday.
    """
    result = {i: [] for i in range(7)}
    for date in items:
        start = items[date]['start']
        end = items[date]['end']
        result[date.weekday()].append(interval(start, end))
    return result


def seconds_since_midnight(time):
    """
    Calculates amount of seconds since midnight.
    """
    return time.hour * 3600 + time.minute * 60 + time.second


def interval(start, end):
    """
    Calculates inverval in seconds between two datetime.time objects.
    """
    return seconds_since_midnight(end) - seconds_since_midnight(start)


def mean(items):
    """
    Calculates arithmetic mean. Returns zero for empty lists.
    """
    return float(sum(items)) / len(items) if len(items) > 0 else 0


def group_by_weekday_start_end(items):
    """
    Groups start and end presences by weekday.
    """
    weekdays = {
        i: {
            'start': [],
            'end': []
        }
        for i in range(7)
    }
    for date in items:
        start = seconds_since_midnight(items[date]['start'])
        end = seconds_since_midnight(items[date]['end'])
        weekdays[date.weekday()]['start'].append(start)
        weekdays[date.weekday()]['end'].append(end)

    return weekdays


def presence_start_end(items):
    """
    Groups mean start and mean end presences by weekday.
    """

    weekdays = group_by_weekday_start_end(items)
    result = {
        weekday: {
            'start': int(mean(time['start'])),
            'end': int(mean(time['end'])),
        }
        for weekday, time in weekdays.items()
    }

    return result
