# -*- coding: utf-8 -*-
# toolbars.py, see CalcActivity.py for info

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
from mathlib import MathLib

from sugar3.graphics.palette import Palette
from sugar3.graphics.menuitem import MenuItem
from sugar3.graphics.toolbutton import ToolButton
from sugar3.graphics.toggletoolbutton import ToggleToolButton
from sugar3.graphics.style import GRID_CELL_SIZE

import logging
_logger = logging.getLogger('calc-activity')

from gettext import gettext as _


def _icon_exists(name):
    if name == '':
        return False

    theme = Gtk.IconTheme.get_default()
    info = theme.lookup_icon(name, 0, 0)
    if info:
        return True

    return False


class IconToolButton(ToolButton):

    def __init__(self, icon_name, text, cb, help_cb=None, alt_html=''):
        ToolButton.__init__(self)

        if _icon_exists(icon_name):
            self.props.icon_name = icon_name
        else:
            if alt_html == '':
                alt_html = icon_name

            label = Gtk.Label()
            label.set_markup(alt_html)
            label.show()
            self.set_label_widget(label)

        self.create_palette(text, help_cb)

        self.connect('clicked', cb)

    def create_palette(self, text, help_cb):
        p = Palette(text)

        if help_cb is not None:
            item = MenuItem(_('Help'), 'action-help')
            item.connect('activate', help_cb)
            item.show()
            p.menu.append(item)

        self.set_palette(p)


class IconToggleToolButton(ToggleToolButton):

    def __init__(self, items, cb, desc):
        ToggleToolButton.__init__(self)
        self.items = items
        if 'icon' in items[0] and _icon_exists(items[0]['icon']):
            self.props.icon_name = items[0]['icon']
        elif 'html' in items[0]:
            self.set_label(items[0]['html'])
#        self.set_tooltip(items[0][1])
        self.set_tooltip(desc)
        self.selected = 0
        self.connect('clicked', self.toggle_button)
        self.callback = cb

    def toggle_button(self, w):
        self.selected = (self.selected + 1) % len(self.items)
        but = self.items[self.selected]
        if 'icon' in but and _icon_exists(but['icon']):
            self.props.icon_name = but['icon']
        elif 'html' in but:
            _logger.info('Setting html: %s', but['html'])
            self.set_label(but['html'])
#        self.set_tooltip(but[1])
        if self.callback is not None:
            if 'html' in but:
                self.callback(but['html'])
            else:
                self.callback(but)


class TextToggleToolButton(Gtk.ToggleToolButton):

    def __init__(self, items, cb, desc, index=False):
        Gtk.ToggleToolButton.__init__(self)
        self.items = items
        self.set_label(items[0])
        self.selected = 0
        self.connect('clicked', self.toggle_button)
        self.callback = cb
        self.index = index
        self.set_tooltip_text(desc)

    def toggle_button(self, w):
        self.selected = (self.selected + 1) % len(self.items)
        but = self.items[self.selected]
        self.set_label(but)
        if self.callback is not None:
            if self.index:
                self.callback(self.selected)
            else:
                self.callback(but)


class LineSeparator(Gtk.SeparatorToolItem):

    def __init__(self):
        Gtk.SeparatorToolItem.__init__(self)
        self.set_draw(True)


class EditToolbar(Gtk.Toolbar):

    def __init__(self, calc):
        Gtk.Toolbar.__init__(self)

        copy_tool = ToolButton('edit-copy')
        copy_tool.set_tooltip(_('Copy'))
        copy_tool.set_accelerator(_('<ctrl>c'))
        copy_tool.connect('clicked', lambda x: calc.text_copy())
        self.insert(copy_tool, -1)

        menu_item = MenuItem(_('Cut'))

        try:
            menu_item.set_accelerator(_('<ctrl>x'))
        except AttributeError:
            pass

        menu_item.connect('activate', lambda x: calc.text_cut())
        menu_item.show()
        copy_tool.get_palette().menu.append(menu_item)

        self.insert(IconToolButton('edit-paste', _('Paste'),
                                   lambda x: calc.text_paste(),
                                   alt_html='Paste'), -1)

        self.show_all()


class AlgebraToolbar(Gtk.Toolbar):

    def __init__(self, calc):
        Gtk.Toolbar.__init__(self)

        self.insert(IconToolButton('algebra-square', _('Square'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_OP_POST, '**2'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_TEXT, 'help(square)'),
                                   alt_html='x<sup>2</sup>'), -1)

        self.insert(IconToolButton('algebra-sqrt', _('Square root'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_FUNCTION, 'sqrt'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_TEXT, 'help(sqrt)'),
                                   alt_html='√x'), -1)

        self.insert(IconToolButton('algebra-xinv', _('Inverse'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_OP_POST, '**-1'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_TEXT, 'help(inv)'),
                                   alt_html='x<sup>-1</sup>'), -1)

        self.insert(LineSeparator(), -1)

        self.insert(IconToolButton('algebra-exp', _('e to the power x'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_FUNCTION, 'exp'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_TEXT, 'help(exp)'),
                                   alt_html='e<sup>x</sup>'), -1)

        self.insert(IconToolButton('algebra-xpowy', _('x to the power y'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_FUNCTION, 'pow'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_TEXT, 'help(pow)'),
                                   alt_html='x<sup>y</sup>'), -1)

        self.insert(IconToolButton('algebra-ln', _('Natural logarithm'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_FUNCTION, 'ln'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_TEXT, 'help(ln)')), -1)

        self.insert(LineSeparator(), -1)

        self.insert(IconToolButton(
            'algebra-fac', _('Factorial'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'factorial'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT,
                                          'help(factorial)')), -1)

        self.show_all()


class TrigonometryToolbar(Gtk.Toolbar):

    def __init__(self, calc):
        Gtk.Toolbar.__init__(self)

        self.insert(IconToolButton(
            'trigonometry-sin', _('Sine'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'sin'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(sin)')), -1)

        self.insert(IconToolButton(
            'trigonometry-cos', _('Cosine'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'cos'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(cos)')), -1)

        self.insert(IconToolButton(
            'trigonometry-tan', _('Tangent'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'tan'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(tan)')), -1)

        self.insert(LineSeparator(), -1)

        self.insert(IconToolButton(
            'trigonometry-asin', _('Arc sine'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'asin'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(asin)')), -1)

        self.insert(IconToolButton(
            'trigonometry-acos', _('Arc cosine'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'acos'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(acos)')), -1)

        self.insert(IconToolButton(
            'trigonometry-atan', _('Arc tangent'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'atan'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(atan)')), -1)

        self.insert(LineSeparator(), -1)

        self.insert(IconToolButton(
            'trigonometry-sinh', _('Hyperbolic sine'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'sinh'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(sinh)')), -1)

        self.insert(IconToolButton(
            'trigonometry-cosh', _('Hyperbolic cosine'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'cosh'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(cosh)')), -1)

        self.insert(IconToolButton(
            'trigonometry-tanh', _('Hyperbolic tangent'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'tanh'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(tanh)')), -1)

        self.show_all()


class BooleanToolbar(Gtk.Toolbar):

    def __init__(self, calc):
        Gtk.Toolbar.__init__(self)

        self.insert(IconToolButton(
            'boolean-and', _('Logical and'),
            lambda x: calc.button_pressed(calc.TYPE_OP_POST, '&'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(And)')), -1)

        self.insert(IconToolButton(
            'boolean-or', _('Logical or'),
            lambda x: calc.button_pressed(calc.TYPE_OP_POST, '|'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(Or)')), -1)

#        self.insert(IconToolButton('boolean-xor', _('Logical xor'),
#            lambda x: calc.button_pressed(calc.TYPE_OP_POST, '^'),
#            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(xor)')), -1)

        self.insert(LineSeparator(), -1)

        self.insert(IconToolButton(
            'boolean-eq', _('Equals'),
            lambda x: calc.button_pressed(calc.TYPE_OP_POST, '==')), -1)

        self.insert(IconToolButton(
            'boolean-neq', _('Not equals'),
            lambda x: calc.button_pressed(calc.TYPE_OP_POST, '!=')), -1)

        self.show_all()


class MiscToolbar(Gtk.Toolbar):

    def __init__(self, calc, target_toolbar=None):
        self._target_toolbar = target_toolbar

        Gtk.Toolbar.__init__(self)

        self.insert(IconToolButton('constants-pi', _('Pi'),
                                   lambda x: calc.button_pressed(
                                       calc.TYPE_TEXT, 'pi'),
                                   alt_html='π'), -1)

        self.insert(IconToolButton(
            'constants-e', _('e'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'e')), -1)

        self.insert(IconToolButton(
            'constants-eulersconstant', _('γ'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT,
                                          '0.577215664901533')), -1)

        self.insert(IconToolButton(
            'constants-goldenratio', _('φ'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT,
                                          '1.618033988749895')), -1)

        self._line_separator1 = LineSeparator()
        self._line_separator2 = LineSeparator()

        self._plot_button = IconToolButton(
            'plot', _('Plot'),
            lambda x: calc.button_pressed(calc.TYPE_FUNCTION, 'plot'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(plot)'))

        el = [
            {'icon': 'format-deg', 'desc': _('Degrees'), 'html': 'deg'},
            {'icon': 'format-rad', 'desc': _('Radians'), 'html': 'rad'},
        ]
        self._angle_button = IconToggleToolButton(
            el,
            lambda x: self.update_angle_type(x, calc),
            _('Degrees / Radians'))
        self.update_angle_type('deg', calc)

        el = [
            {'icon': 'format-sci', 'html': 'sci'},
            {'icon': 'format-exp', 'html': 'exp'},
        ]
        self._format_button = IconToggleToolButton(
            el,
            lambda x: self.update_format_type(x, calc),
            _('Exponent / Scientific notation'))

        el = [
            {'icon': 'digits-9', 'html': '9'},
            {'icon': 'digits-12', 'html': '12'},
            {'icon': 'digits-15', 'html': '15'},
            {'icon': 'digits-6', 'html': '6'},
        ]
        self._digits_button = IconToggleToolButton(
            el,
            lambda x: self.update_digits(x, calc),
            _('Number of shown digits'))

        el = [
            {'icon': 'base-10', 'html': '10'},
            {'icon': 'base-2', 'html': '2'},
            {'icon': 'base-16', 'html': '16'},
            {'icon': 'base-8', 'html': '8'}
        ]

        self._base_button = IconToggleToolButton(
            el,
            lambda x: self.update_int_base(x, calc),
            _('Integer formatting base'))

        self.update_layout()

        self.show_all()

    def update_layout(self):
        if Gdk.Screen.width() < 14 * GRID_CELL_SIZE or \
                self._target_toolbar is None:
            target_toolbar = self
            if self._target_toolbar is not None:
                self._remove_buttons(self._target_toolbar)
        else:
            target_toolbar = self._target_toolbar

        target_toolbar.insert(self._line_separator1, -1)
        target_toolbar.insert(self._plot_button, -1)
        target_toolbar.insert(self._line_separator2, -1)
        target_toolbar.insert(self._angle_button, -1)
        target_toolbar.insert(self._format_button, -1)
        target_toolbar.insert(self._digits_button, -1)
        target_toolbar.insert(self._base_button, -1)

    def _remove_buttons(self, toolbar):
        for item in [self._plot_button, self._line_separator1,
                     self._line_separator2, self._angle_button,
                     self._format_button, self._digits_button,
                     self._base_button]:
            toolbar.remove(item)

    def update_angle_type(self, text, calc):
        var = calc.parser.get_var('angle_scaling')
        if var is None:
            _logger.warning('Variable angle_scaling not defined.')
            return

        if text == 'deg':
            var.value = MathLib.ANGLE_DEG
        elif text == 'rad':
            var.value = MathLib.ANGLE_RAD
        _logger.debug('Angle scaling: %s', var.value)

    def update_format_type(self, text, calc):
        if text == 'exp':
            calc.ml.set_format_type(MathLib.FORMAT_EXPONENT)
        elif text == 'sci':
            calc.ml.set_format_type(MathLib.FORMAT_SCIENTIFIC)
        _logger.debug('Format type: %s', calc.ml.format_type)

    def update_digits(self, text, calc):
        calc.ml.set_digit_limit(int(text))
        _logger.debug('Digit limit: %s', calc.ml.digit_limit)

    def update_int_base(self, text, calc):
        calc.ml.set_integer_base(int(text))
        _logger.debug('Integer base: %s', calc.ml.integer_base)
