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

import sys
from os import listdir, symlink, unlink
from os.path import join, isfile, islink
from creole.loader import creole_loader, config_save_values
from creole.client import CreoleClient, CreoleClientError
from pyeole.ansiprint import print_orange

## configuration
SCHEDULE_DIR = '/usr/share/eole/schedule'
SCHEDULE_SCRIPT_DIR = join(SCHEDULE_DIR, 'scripts')

DAY_TO_STRING = {1: 'lundi', 2: 'mardi', 3: 'mercredi', 4: 'jeudi', 5: 'vendredi', 6: 'samedi', 7: 'dimanche'}

client = CreoleClient()

def _list_schedules(schedules):
    # {u'majauto.mode': u'pre', u'majauto.description': u'Mise \xe0 jour du serveur', u'majauto.day': u'weekly'}
    # =>
    # {'pre: ['majauto']}
    sched_dict = {}
    sched = {}
    sched_keys = list(schedules.keys())
    sched_keys.sort()
    # {'majauto': {'mode': 'pre', 'description': u'Mise \xe0 jour du serveur', 'day': u'weekly'}}
    for sched_key in sched_keys:
        value = schedules[sched_key]
        sched_key = sched_key.split('.')
        script = sched_key[0]
        key = sched_key[1]
        sched_dict.setdefault(script, {})[key] = value
    # {'pre: set(['majauto'])}
    for sched_key, schedule in sched_dict.items():
        sched.setdefault(schedule['mode'], set()).add(sched_key)

    return sched

def add_schedule(day, mode, script):
    orig = join(SCHEDULE_SCRIPT_DIR, script)
    if not isfile(orig):
        raise Exception('unable to find schedule script {0}'.format(orig))
    if mode is None:
        mode = client.get('schedule.{}.mode'.format(script))
    dest = join(SCHEDULE_DIR, day, mode, script)
    if isfile(dest):
        raise Exception('{0} already exists'.format(dest))
    symlink(orig, dest)

def del_schedule(day, mode, script):
    orig = join(SCHEDULE_SCRIPT_DIR, script)
    if mode is None:
        mode = client.get('schedule.{}.mode'.format(script))
    dest = join(SCHEDULE_DIR, day, mode)
    old_filename = join(dest, script)
    if not islink(old_filename):
        print_orange(f"Le fichier {old_filename} n'est pas un lien symbolique")
        return
    if not isfile(orig):
        raise Exception('unable to find schedule script {0}'.format(orig))
    if not islink(old_filename):
        raise Exception('file {0} is not a symlink!'.format(old_filename))
    unlink(old_filename)

def apply_schedules():
    for day in ['daily', 'weekly', 'monthly']:
        for mode in ['pre', 'post']:
            dest = join(SCHEDULE_DIR, day, mode)
            for old_filename in listdir(dest):
                del_schedule(day, mode, old_filename)
        try:
            schedules = client.get('/schedule', withoption='day', withvalue=day)
            scheds = _list_schedules(schedules)
            for mode, sched_list in scheds.items():
                for script in sched_list:
                    add_schedule(day, mode, script)
        except CreoleClientError:
            pass

def list_once(mode):
    """
    Liste les scripts lancés qu'une seule fois
    Les scripts "once" ne sont pas dans tiramisu. Un lien symbolique est créé
    a son activation.
    return: ('script1', 'script2')
    """
    return listdir(join(SCHEDULE_DIR, 'once', mode))

def display_schedules():
    """
    Programmation automatique d'une mise à jour hebdomadaire

    """
    def hour_display(number):
        if number < 10:
            return '0{0}'.format(number)
        return str(number)

    minute = hour_display(client.get('schedule.schedule.minute'))
    hour = hour_display(client.get('schedule.schedule.hour'))
    weekday = DAY_TO_STRING[client.get('schedule.schedule.weekday')]
    monthday = DAY_TO_STRING[client.get('schedule.schedule.monthday')]
    print_orange("Tâches planifiées EOLE :")
    messages = {'daily': "les tâches journalières se feront tous les jours",
        'weekly': "les tâches hebdomadaires se feront le {1}",
        'monthly': "les tâches mensuelles se feront le premier {0} du mois",
        'none': "les tâches désactivées",
        'once': "les tâches exécutées qu'une fois (la nuit qui vient)"}
    messages_mode = {'pre': 'avant sauvegarde', 'post': 'après sauvegarde'}
    display_once = False
    for mode in ['pre', 'post']:
        scripts = list_once(mode)
        if scripts != []:
            if not display_once:
                print_orange(' * {0}'.format(messages['once']))
                display_once = True
            print_orange('  - {0}'.format(messages_mode[mode]))
            scripts.sort()
            for script in scripts:
                if sys.version_info[0] >= 3:
                    print(' '.join(["   +", client.get('/schedule/{0}/description'.format(script)), \
                        '({0})'.format(script)]))
                else:
                    print(' '.join(["   +", client.get('/schedule/{0}/description'.format(script)), \
                        '({0})'.format(script)]))

    for day in ['daily', 'weekly', 'monthly', 'none']:
        try:
            #raise NotFoundError if no schedule
            schedules = client.get('/schedule', withoption='day', withvalue=day)
            message = messages[day].format(monthday, weekday)
            if day != 'none':
                message = "{0} à {1}:{2} (hors sauvegarde)".format(message,
                                                                     hour,
                                                                     minute)
                print_orange(" * {0}".format(message))
            else:
                print_orange("Tâches désactivées EOLE :")
            scheds = _list_schedules(schedules)
            mode_list = list(scheds.keys())
            #['pre', 'post']
            mode_list.sort(reverse=True)
            for mode in mode_list:
                if day != 'none':
                    print_orange('  - {0}'.format(messages_mode[mode]))
                for sched in scheds[mode]:
                    if sys.version_info[0] >= 3:
                        print(" ".join(["   +", schedules['{0}.description'.format(sched)], \
                                '({0})'.format(sched)]))
                    else:
                        print(" ".join(["   +", schedules['{0}.description'.format(sched)],
                                '({0})'.format(sched)]))

        except CreoleClientError:
            pass


class ManageSchedule(object):

    def __init__(self):
        self.config = creole_loader(load_extra=True, owner='schedule')
        self.config.read_write()

    def add(self, script, day):
        try:
            config = getattr(self.config, 'schedule.'+script)
        except AttributeError:
            raise ValueError('script {0} inconnu'.format(script))
        config.day = day

    def delete(self, script):
        try:
            config = getattr(self.config, 'schedule.'+script)
        except AttributeError:
            raise ValueError('script {0} inconnu'.format(script))
        config.day = 'none'

    def save(self):
        if not config_save_values(self.config, 'schedule'):
            raise Exception("Le fichier de configuration n'a pas été enregistré")

if __name__ == '__main__':
    display_schedules()
