# -*- coding: utf-8 -*-
# This file is part of pygal_sphinx_directives
#
# Pygal sphinx integration
# Copyright © 2012-2016 Florian Mounier
#
# This library is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This library 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 Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>.

from traceback import format_exc, print_exc

import docutils.core
import pygal
from docutils.parsers.rst import Directive
from sphinx.directives.code import CodeBlock

# Patch default style

pygal.config.Config.style.value = pygal.style.RotateStyle(
    '#2980b9',
    background='#fcfcfc',
    plot_background='#ffffff',
    foreground='#707070',
    foreground_strong='#404040',
    foreground_subtle='#909090',
    opacity='.8',
    opacity_hover='.9',
    transition='400ms ease-in'
)


class PygalDirective(Directive):
    """Execute the given python file and puts its result in the document."""
    required_arguments = 0
    optional_arguments = 2
    final_argument_whitespace = True
    has_content = True

    def run(self):
        width, height = map(int, self.arguments[:2]
                            ) if len(self.arguments) >= 2 else (600, 400)
        if len(self.arguments) == 1:
            self.render_fix = bool(self.arguments[0])
        elif len(self.arguments) == 3:
            self.render_fix = bool(self.arguments[2])
        else:
            self.render_fix = False
        self.content = list(self.content)
        content = list(self.content)
        if self.render_fix:
            content[-1] = 'rv = ' + content[-1]
        code = '\n'.join(content)
        scope = {'pygal': pygal}
        try:
            exec(code, scope)
        except Exception:
            print(code)
            print_exc()
            return [
                docutils.nodes.system_message(
                    'An exception as occured during code parsing:'
                    ' \n %s' % format_exc(),
                    type='ERROR',
                    source='/',
                    level=3
                )
            ]
        if self.render_fix:
            rv = scope['rv']
        else:
            chart = None
            for key, value in scope.items():
                if isinstance(value, pygal.graph.graph.Graph):
                    chart = value
                    self.content.append(key + '.render()')
                    break
            if chart is None:
                return [
                    docutils.nodes.system_message(
                        'No instance of graph found',
                        level=3,
                        type='ERROR',
                        source='/'
                    )
                ]
            chart.config.width = width
            chart.config.height = height
            chart.explicit_size = True

        try:
            svg = '<embed src="%s" />' % chart.render_data_uri()
        except Exception:
            return [
                docutils.nodes.system_message(
                    'An exception as occured during graph generation:'
                    ' \n %s' % format_exc(),
                    type='ERROR',
                    source='/',
                    level=3
                )
            ]
        return [docutils.nodes.raw('', svg, format='html')]


class PygalWithCode(PygalDirective):
    def run(self):
        node_list = super(PygalWithCode, self).run()
        node_list.extend(
            CodeBlock(
                self.name, ['python'], self.options, self.content, self.lineno,
                self.content_offset, self.block_text, self.state,
                self.state_machine
            ).run()
        )

        return [docutils.nodes.compound('', *node_list)]


class PygalTable(Directive):
    """Execute the given python file and puts its result in the document."""
    required_arguments = 0
    optional_arguments = 0
    final_argument_whitespace = True
    has_content = True

    def run(self):

        self.content = list(self.content)
        content = list(self.content)
        content[-1] = 'rv = ' + content[-1]
        code = '\n'.join(content)
        scope = {'pygal': pygal}
        try:
            exec(code, scope)
        except Exception:
            print_exc()
            return [
                docutils.nodes.system_message(
                    'An exception as occured during code parsing:'
                    ' \n %s' % format_exc(),
                    type='ERROR',
                    source='/',
                    level=3
                )
            ]
        rv = scope['rv']

        return [docutils.nodes.raw('', rv, format='html')]


class PygalTableWithCode(PygalTable):
    def run(self):
        node_list = super(PygalTableWithCode, self).run()
        node_list.extend(
            CodeBlock(
                self.name, ['python'], self.options, self.content, self.lineno,
                self.content_offset, self.block_text, self.state,
                self.state_machine
            ).run()
        )

        return [docutils.nodes.compound('', *node_list)]


def setup(app):
    app.add_directive('pygal', PygalDirective)
    app.add_directive('pygal-code', PygalWithCode)
    app.add_directive('pygal-table', PygalTable)
    app.add_directive('pygal-table-code', PygalTableWithCode)

    return {'version': '1.0.1'}
