# w.c.s. - web application for online forms
# Copyright (C) 2005-2017  Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

import re

from quixote import get_response, get_publisher, redirect
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext
from wcs.qommon import _, ngettext
from wcs.qommon import errors, get_cfg
from wcs.qommon.misc import localstrftime

from wcs.logged_errors import LoggedError

class LoggedErrorDirectory(Directory):
    _q_exports = ['', 'delete', 'ack']

    def __init__(self, parent_dir, error):
        self.parent_dir = parent_dir
        self.error = error

    def _q_index(self):
        get_response().breadcrumb.append(('%s/' % self.error.id, self.error.summary))
        self.parent_dir.html_top(_('Logged Errors - %s') % self.error.summary)
        get_response().filter['sidebar'] = self.get_sidebar()
        r = TemplateIO(html=True)
        r += htmltext('<h2>%s</h2>') % self.error.summary
        r += htmltext('<ul>')
        r += htmltext(' <li>%s %s</li>') % (
                _('First occurence:'),
                localstrftime(self.error.first_occurence_timestamp))
        r += htmltext(' <li>%s %s</li>') % (
                _('Latest occurence:'),
                localstrftime(self.error.latest_occurence_timestamp))
        r += htmltext('  <li>%s %s</li>') % (_('Count:'), self.error.occurences_count)

        formdef = self.error.get_formdef()
        if formdef:
            r += htmltext('  <li>%s <a href="/backoffice/forms/%s/">%s</a></li>') % (
                    _('Form:'), formdef.id, formdef.name)

        workflow = self.error.get_workflow()
        if workflow:
            r += htmltext('  <li>%s <a href="/backoffice/workflows/%s/">%s</a></li>') % (
                    _('Workflow: '), workflow.id, workflow.name)
            status = self.error.get_status()
            if status:
                r += htmltext('<ul>')
                r += htmltext(
                    '<li>%s <a href="/backoffice/workflows/%s/status/%s/">%s</a></li>') % (
                        _('Status:'), workflow.id, status.id, status.name)
                status_item = self.error.get_status_item()
                if status_item:
                    r += htmltext(
                        '<li>%s <a href="/backoffice/workflows/%s/status/%s/items/%s/">%s</a></li>') % (
                            _('Action:'), workflow.id, status.id, status_item.id,
                            _(status_item.description))
                r += htmltext('</ul>')


        if self.error.expression or self.error.expression_type:
            expression_title = {
                'python': N_('Python Expression'),
                'django': N_('Django Expression'),
                'template': N_('Template'),
                'text': N_('Text'),
            }.get(self.error.expression_type, N_('Unknown'))
            r += htmltext('  <li>%s <code>%s</code></li>') % (
                    _('%s:') % expression_title, self.error.expression)

        if self.error.exception_class or self.error.exception_message:
            r += htmltext('  <li>%s <code>%s: %s</code></li>') % (_('Error message:'),
                                                                self.error.exception_class,
                                                                self.error.exception_message)

        if formdef:
            formdata = self.error.get_formdata()
            if formdata:
                r += htmltext('  <li>%s <a href="%s">%s</a>') % (
                        _('Data: '), formdata.get_url(backoffice=True),
                        formdata.get_display_name())
                r += htmltext(' (<a href="%sinspect">%s</a>)') % (
                        formdata.get_url(backoffice=True), _('inspector'))
                r += htmltext('</li>')

        r += htmltext('</ul>')

        if not self.error.traceback:
            return r.getvalue()

        parts = (N_('Exception'), N_('Stack trace (most recent call first)'),
                N_('Form'), N_('Cookies'), N_('Environment'))
        current_part = None
        for line in self.error.traceback.splitlines():
            if line.endswith(':') and line.rstrip(':') in parts:
                if current_part in parts[:2]:
                    r += htmltext('</pre>')
                elif current_part:
                    r += htmltext('</table>')
                current_part = line.rstrip(':')
                r += htmltext('<h3>%s</h3>') % _(current_part)
                if current_part in parts[:2]:
                    r += htmltext('<pre class="traceback">')
                else:
                    r += htmltext('<table class="main compact code">')
                continue
            if current_part in parts[:2]:
                r += line + '\n'
            elif line:
                r += htmltext('<tr><td>%s</td><td>%s</td></tr>') % tuple(
                        re.split(r'\s+', line, maxsplit=1))

        if current_part in parts[:2]:
            r += htmltext('</pre>')
        elif current_part:
            r += htmltext('</table>')
        return r.getvalue()

    def get_sidebar(self):
        r = TemplateIO(html=True)
        r += htmltext('<ul id="sidebar-actions">')
        if not self.error.acked:
            r += htmltext('<li><a href="ack">%s</a></li>') % ('Ack')
        else:
            r += htmltext('<li>%s</li>' % _('Acked'))
        r += htmltext('<li><a href="delete">%s</a></li>') % _('Delete')
        r += htmltext('</ul>')
        return r.getvalue()

    def ack(self):
        self.error.acked = True
        self.error.store()
        return redirect('.')

    def delete(self):
        self.error.remove_self()
        return redirect('..')


class LoggedErrorsDirectory(Directory):
    _q_exports = ['']

    @classmethod
    def get_errors(cls, formdef_id=None, workflow_id=None):
        errors = []
        if formdef_id:
            errors = LoggedError.get_with_indexed_value('formdef_id', formdef_id)
        elif workflow_id:
            errors = LoggedError.get_with_indexed_value('workflow_id', workflow_id)
        return list(errors)

    @classmethod
    def errors_block(cls, formdef_id=None, workflow_id=None):
        errors = cls.get_errors(formdef_id=formdef_id, workflow_id=workflow_id)
        if not errors:
            return ''
        errors.sort(key=lambda x: x.id, reverse=True)

        r = TemplateIO(html=True)
        r += htmltext('<div class="bo-block logged-errors">')
        r += htmltext('<h3><a href="logged-errors/">%s</a></h3>') % ngettext(
                '%(count)d error', '%(count)d errors', len(errors)) % {'count': len(errors)}
        r += htmltext('<ul>')
        for error in errors[:3]:
            r += htmltext('<li><a href="logged-errors/%s/">%s</a> ') % (error.id, error.summary)
            if error.exception_class or error.exception_message:
                r += htmltext(_('error %(class)s (%(message)s)')) % {
                    'class': error.exception_class,
                    'message': error.exception_message,
                }
            r += htmltext('</li>')
        if len(errors) > 3:
            r += htmltext('<li>...</li>')
        r += htmltext('</ul>')
        r += htmltext('</div>')
        return r.getvalue()

    def __init__(self, parent_dir, formdef_id=None, workflow_id=None):
        self.parent_dir = parent_dir
        self.formdef_id = formdef_id
        self.workflow_id = workflow_id

    def _q_index(self):
        get_response().breadcrumb.append(('logged-errors/', _('Logged Errors')))
        self.parent_dir.html_top(_('Logged Errors'))
        r = TemplateIO(html=True)
        r += htmltext('<div class="bo-block">')
        r += htmltext('<h2>%s</h2>') % _('Logged Errors')
        r += htmltext('<ul class="biglist">')
        for error in self.get_errors(formdef_id=self.formdef_id, workflow_id=self.workflow_id):
            r += htmltext('<li><strong><a href="%s/">%s</a></strong> ') % (error.id, error.summary)
            if error.exception_class or error.exception_message:
                r += htmltext(_('error %(class)s (%(message)s)')) % {
                    'class': error.exception_class,
                    'message': error.exception_message,
                }
            r += htmltext('<p class="details badge">%s</p>') % error.occurences_count
            r += htmltext('</li>')

        r += htmltext('</ul>')
        r += htmltext('</div>')
        return r.getvalue()

    def _q_lookup(self, component):
        try:
            error = LoggedError.get(component)
        except KeyError:
            raise errors.TraversalError()
        get_response().breadcrumb.append(('logged-errors/', _('Logged Errors')))
        return LoggedErrorDirectory(self.parent_dir, error)
