# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8

__all__ = ('TasksCLI',)

from ulib.base.output import uprint, enote, eerror, ewarn, get_color
from ulib.base.words import plural
from ulib.base.uio import _u
from ulib.base.control import die, ERROR_STATUS
from ulib.base.editor import edit_template
from ulib.base.lines import Lines
from ulib.base.dates import parse_date, Date
from ulib.tasks.tasks import Task
from ulib.tasks.tasksctl import TasksCtl

class TasksCLI(TasksCtl):
    def __init__(self, tsrc=None, ctl=None):
        TasksCtl.__init__(self, tsrc, ctl)

    def get_width(self, tasks):
        return max(map(lambda t: len(t.id), tasks) or [1])

    # =========================================================================

    def __print_task(self, t, width=1, showbody=False):
        parts = []

        prefix_color = u""
        reset_color = get_color("reset")
        if t.is_task_type():
            if t.is_urgent():
                prefix = u"[ ]"
                prefix_color = get_color(self._tsrc.get_urgent_color())
            elif t.is_normal():
                prefix = u"[ ]"
                prefix_color = get_color(self._tsrc.get_normal_color())
            elif t.is_planned():
                prefix = u"Pl>"
                prefix_color = get_color(self._tsrc.get_planned_color())
            elif t.is_obsolete():
                prefix = u"Ob>"
                prefix_color = get_color(self._tsrc.get_obsolete_color())
            elif t.is_done():
                prefix = u"[x]"
                prefix_color = get_color(self._tsrc.get_done_color())
            else:
                prefix = u"??>"
        elif t.is_event_type():
            if t.is_done():
                prefix = u"[x]"
                prefix_color = get_color(self._tsrc.get_done_color())
            else:
                prefix = u"Ev>"
                prefix_color = get_color(self._tsrc.get_event_color())
        elif t.is_idea_type():
            prefix = u"Id>"
            prefix_color = get_color(self._tsrc.get_idea_color())
        elif t.is_activity_type():
            prefix = u"Ac>"
            prefix_color = get_color(self._tsrc.get_activity_color())
        else:
            prefix = u"??>"
        parts.append(prefix_color)
        parts.append(prefix)
        parts.append(u" %*s " % (width, t.id))
        project_color = get_color(self._tsrc.get_project_color())
        for p in t.get_projects():
            parts.append(project_color)
            parts.append(p)
            parts.append(reset_color)
            parts.append(prefix_color)
            parts.append(u" ")
        context_color = get_color(self._tsrc.get_context_color())
        for c in t.get_contexts():
            parts.append(context_color)
            parts.append(c)
            parts.append(reset_color)
            parts.append(prefix_color)
            parts.append(u" ")
        parts.append(t.get_title1())
        if t.is_task_type() or t.is_event_type():
            urgency = t.get_urgency()
            if urgency:
                parts.append(" (")
                parts.append(urgency)
                parts.append(")")
        parts.append(reset_color)
        uprint(''.join(parts))

        body = t.get_body()
        if showbody:
            if body: uprint(body)
            tag_color = get_color(self._tsrc.get_tag_color())
            for name, value in t.get_props().items():
                uprint(u"%s%s=%s%s" % (tag_color, name, value, reset_color))

    def __print_stats(self, tasks, nb_showable, nb_total):
        tasks_of_task_type = [task for task in tasks if task.is_task_type()]
        nb_tasks = len(tasks_of_task_type)
        nb_done = len([task for task in tasks_of_task_type if task.is_done()])
        infos = []
        if nb_total != nb_tasks:
            infos.append(plural(u"%i ligne%# au total", nb_total))
        if nb_total != nb_showable:
            infos.append(plural(u"%i ligne%# masquée%#", nb_total - nb_showable))
        if infos: notes = u" [%s]" % u", ".join(infos)
        else: notes = u""
        enote(u"%i / %s%s" % (nb_tasks - nb_done, plural(u"%i tâche%#", nb_tasks), notes))

    SHOW_ALL = 0
    SHOW_SHOWABLE = 1
    SHOW_DOABLE = 2

    def list(self, ids=None, text=None, props=None, projects=None, contexts=None,
             showwhat=False, showbody=False, showstats=True, store=None):
        if store is None: store = self.get_stores()
        tasks = store.find_tasks(ids, text, props, projects, contexts)
        nb_total = len(tasks)
        if showwhat == self.SHOW_ALL:
            pass
        elif showwhat == self.SHOW_SHOWABLE:
            tasks = [task for task in tasks if task.is_showable()]
        elif showwhat == self.SHOW_DOABLE:
            tasks = [task for task in tasks if task.is_doable()]
        tasks.sort(Task.cmp)
        nb_showable = len(tasks)
        width = self.get_width(tasks)
        for t in tasks:
            self.__print_task(t, width, showbody=showbody)
        if showstats:
            self.__print_stats(tasks, nb_showable, nb_total)

    def list_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args, 'aqdln',
                                      ['show-all', 'show-showable', 'show-doable',
                                       'show-body', 'no-stats'])
        showwhat = None
        showbody = False
        showstats = True
        for option, value in options:
            if option in ('-a', '--show-all'): showwhat = self.SHOW_ALL
            elif option in ('-q', '--show-showable'): showwhat = self.SHOW_SHOWABLE
            elif option in ('-d', '--show-doable'): showwhat = self.SHOW_DOABLE
            elif option in ('-l', '--show-body'): showbody = True
            elif option in ('-n', '--no-stats'): showstats = False
            elif self.is_option(option, value): pass

        store = self.get_stores()
        ids, text, props, projects, contexts, filtered = self.get_filters(map(_u, args), store=store)
        if showwhat is None:
            if filtered: showwhat = self.SHOW_ALL
            else: showwhat = self.SHOW_SHOWABLE
        self.list(ids, text, props, projects, contexts, showwhat, showbody, showstats, store=store)

    # =========================================================================

    def add(self, args, do=False, edit=False):
        store = self.get_wstore()
        t = store.new_task_from_clargs(args)
        if do: t.do()
        t.save()
        self.__print_task(t)
        if edit: self.edit(t)

    def add_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args, 'de', ['do', 'edit'])
        do = False
        edit = False
        for option, value in options:
            if option in ('-d', '--do'): do = True
            elif option in ('-e', '--edit'): edit = True
            elif self.is_option(option, value): pass

        return self.add(args, do, edit)

    # =========================================================================

    def edit(self, task=None, tasks=None):
        if tasks is None and task is not None:
            tasks = [task]
        if tasks is None: return

        width = self.get_width(tasks)
        for t in tasks:
            title = Lines(t.title)
            title = title[0:1] and title[0] or u""
            text = edit_template(t.output(join=True, help=True, modeline=True, lastnl=True), row=3, col=len(title))
            t.input(text)
            t.save()
            self.__print_task(t, width, showbody=True)

    def edit_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args)
        for option, value in options:
            if self.is_option(option, value): pass

        store = self.get_stores()
        tasks = self.get_filtered(args, store=store)
        self.edit(tasks=tasks)

    # =========================================================================

    def do(self, task=None, tasks=None):
        if tasks is None and task is not None:
            tasks = [task]
        if tasks is None: return

        width = self.get_width(tasks)
        for t in tasks:
            t.do()
            t.save()
            self.__print_task(t, width, showbody=True)

    def do_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args)
        for option, value in options:
            if self.is_option(option, value): pass

        store = self.get_stores()
        tasks = self.get_filtered(args, store=store)
        self.do(tasks=tasks)

    def nodo(self, task=None, tasks=None):
        if tasks is None and task is not None:
            tasks = [task]
        if tasks is None: return

        width = self.get_width(tasks)
        for t in tasks:
            t.nodo()
            t.save()
            self.__print_task(t, width, showbody=True)

    def nodo_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args)
        for option, value in options:
            if self.is_option(option, value): pass

        store = self.get_stores()
        tasks = self.get_filtered(args, store=store)
        self.nodo(tasks=tasks)

    # =========================================================================

    def __one(self, tasks):
        if len(tasks) == 1: return tasks[0]
        elif len(tasks) > 1: eerror(u"Plusieurs tâches correspondent au filtre")
        else: eerror(u"Aucune tâche trouvée")
        return None

    def start(self, task, summary=None, exclusive=False, store=None):
        u"""
        """
        if exclusive:
            if store is None: store = task.get_store()
            store.stop_all()
            store.save()
        date, time = task.start(summary)
        task.save()
        self.__print_task(task)
        enote(u"Démarrage de la tâche à %s le %s" % (time, date))

    def start_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args, 'x', ['exclusive'])
        exclusive = False
        for option, value in options:
            if option in ('-x', '--exclusive'): exclusive = True
            elif self.is_option(option, value): pass

        store = self.get_stores()
        task = self.__one(self.get_filtered(args[0:1], store=store))
        summary = u" ".join(args[1:])
        if task is not None:
            self.start(task, summary=summary or None,
                       exclusive=exclusive, store=store)

    def stop(self, task, summary=None):
        u"""
        """
        date, time = task.stop(summary)
        task.save()
        self.__print_task(task)
        enote(u"Arrêt de la tâche à %s le %s" % (time, date))

    def stop_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args, 'a', ['stop-all'])
        stop_all = False
        for option, value in options:
            if option in ('-a', '--stop-all'): stop_all = True
            elif self.is_option(option, value): pass

        store = self.get_stores()
        if stop_all:
            if store.stop_all():
                enote(u"Toutes les tâches ont été arrêtées")
        else:
            task = self.__one(self.get_filtered(args[0:1], store=store))
            summary = u" ".join(args[1:])
            if task is not None: self.stop(task, summary=summary or None)

    def toggle_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args, 'x', ['exclusive'])
        exclusive = False
        for option, value in options:
            if option in ('-x', '--exclusive'): exclusive = True
            elif self.is_option(option, value): pass

        store = self.get_stores()
        task = self.__one(self.get_filtered(args[0:1], store=store))
        summary = u" ".join(args[1:])
        if task is not None:
            if task.is_started():
                self.stop(task, summary=summary or None)
            else:
                self.start(task, summary=summary or None,
                           exclusive=exclusive, store=store)

    # =========================================================================

    def plan(self, date=None, task=None, tasks=None):
        if tasks is None and task is not None:
            tasks = [task]
        if tasks is None: return

        width = self.get_width(tasks)
        for t in tasks:
            t.plan(date)
            t.save()
            self.__print_task(t, width, showbody=True)

    def plan_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args, 'd:', ['date='])
        date = Date()
        for option, value in options:
            if option in ('-d', '--date'):
                if value: date = parse_date(value)
                else: date = None
            elif self.is_option(option, value): pass

        store = self.get_stores()
        tasks = self.get_filtered(args, store=store)
        self.plan(date, tasks=tasks)

    # =========================================================================

    def remove(self, task=None, tasks=None):
        if tasks is None and task is not None:
            tasks = [task]
        if tasks is None: return

        width = self.get_width(tasks)
        for t in tasks:
            self.__print_task(t, width, showbody=True)
            store = t.get_store()
            if store is None: continue

            if store.remove(t):
                store.save()
                enote(u"Tâche supprimée")
            else:
                ewarn(u"Tâche non supprimée")

    def remove_cmd(self, *args, **kw):
        u"""
        """
        options, args = self.get_args(args)
        for option, value in options:
            if self.is_option(option, value): pass

        store = self.get_stores()
        tasks = self.get_filtered(args, store=store)
        self.remove(tasks=tasks)

    # =========================================================================

    def purge_cmd(self, *args, **kw):
        u"""
        """
        store = self.get_stores()

    # =========================================================================

    def report_cmd(self, *args, **kw):
        u"""
        """
        store = self.get_stores()

    # =========================================================================

    def run(self, args=None, cmd_name=None, **ignored):
        cmd = {'add': self.add_cmd,
               'list': self.list_cmd,
               'edit': self.edit_cmd,
               'do': self.do_cmd,
               'nodo': self.nodo_cmd,
               'start': self.start_cmd,
               'stop': self.stop_cmd,
               'toggle': self.toggle_cmd,
               'plan': self.plan_cmd,
               'remove': self.remove_cmd,
               'purge': self.purge_cmd,
               'report': self.report_cmd,
               }.get(cmd_name, None)
        if cmd is None: die(u"Commande invalide: %s" % _u(cmd_name))
        return cmd(*args)
