#!/usr/bin/python3.11
#
# Copyright 2008, 2009 Hannes Hochreiner
#
# 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 3 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/.
#
"""Effect to add key bindings to jessyInk slide show"""

import inkex
from inkex import Group, Script
from jessyink_install import JessyInkMixin

KEY_CODES = (
    "LEFT",
    "RIGHT",
    "DOWN",
    "UP",
    "HOME",
    "END",
    "ENTER",
    "SPACE",
    "PAGE_UP",
    "PAGE_DOWN",
    "ESCAPE",
)


class KeyBindings(JessyInkMixin, inkex.EffectExtension):
    """Add key bindings to slide show"""

    modes = ("slide", "index", "drawing")

    def set_options(self, namespace, opt_str, value):
        """Sort through all the options and combine them"""
        slot, action = opt_str.split("_", 1)
        keycodes = getattr(namespace, f"{slot}KeyCodes", {})
        charcodes = getattr(namespace, f"{slot}CharCodes", {})
        if value:
            for val in value.split(","):
                val = val.strip()
                if val in KEY_CODES:
                    keycodes[val + "_KEY"] = self.actions[slot][action]
                elif len(val) == 1:
                    charcodes[val] = self.actions[slot][action]
        setattr(namespace, f"{slot}KeyCodes", keycodes)
        setattr(namespace, f"{slot}CharCodes", charcodes)

    actions = {
        "slide": {
            "export": "slideUpdateExportLayer();",
            "addSlide": "slideAddSlide(activeSlide);",
            "resetTimer": "slideResetTimer();",
            "setDuration": "slideQueryDuration();",
            "backWithEffects": "dispatchEffects(-1);",
            "nextWithEffects": "dispatchEffects(1);",
            "backWithoutEffects": "skipEffects(-1);",
            "nextWithoutEffects": "skipEffects(1);",
            "switchToIndexMode": "toggleSlideIndex();",
            "switchToDrawingMode": "slideSwitchToDrawingMode();",
            "toggleProgressBar": "slideToggleProgressBarVisibility();",
            "firstSlide": "slideSetActiveSlide(0);",
            "lastSlide": "slideSetActiveSlide(slides.length - 1);",
        },
        "drawing": {
            "undo": "drawingUndo();",
            "switchToSlideMode": "drawingSwitchToSlideMode();",
            "pathWidthDefault": "drawingResetPathWidth();",
            "pathWidth1": "drawingSetPathWidth(1.0);",
            "pathWidth3": "drawingSetPathWidth(3.0);",
            "pathWidth5": "drawingSetPathWidth(5.0);",
            "pathWidth7": "drawingSetPathWidth(7.0);",
            "pathWidth9": "drawingSetPathWidth(9.0);",
            "pathColourBlue": 'drawingSetPathColour("blue");',
            "pathColourCyan": 'drawingSetPathColour("cyan");',
            "pathColourGreen": 'drawingSetPathColour("green");',
            "pathColourBlack": 'drawingSetPathColour("black");',
            "pathColourMagenta": 'drawingSetPathColour("magenta");',
            "pathColourOrange": 'drawingSetPathColour("orange");',
            "pathColourRed": 'drawingSetPathColour("red");',
            "pathColourWhite": 'drawingSetPathColour("white");',
            "pathColourYellow": 'drawingSetPathColour("yellow");',
        },
        "index": {
            "selectSlideToLeft": "indexSetPageSlide(activeSlide - 1);",
            "selectSlideToRight": "indexSetPageSlide(activeSlide + 1);",
            "selectSlideAbove": "indexSetPageSlide(activeSlide - INDEX_COLUMNS);",
            "selectSlideBelow": "indexSetPageSlide(activeSlide + INDEX_COLUMNS);",
            "previousPage": "indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS);",
            "nextPage": "indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS);",
            "firstSlide": "indexSetPageSlide(0);",
            "lastSlide": "indexSetPageSlide(slides.length - 1);",
            "switchToSlideMode": "toggleSlideIndex();",
            "decreaseNumberOfColumns": "indexDecreaseNumberOfColumns();",
            "increaseNumberOfColumns": "indexIncreaseNumberOfColumns();",
            "setNumberOfColumnsToDefault": "indexResetNumberOfColumns();",
        },
    }

    def add_arguments(self, pars):
        pars.add_argument("--tab")
        for slot, actions in self.actions.items():
            for action in actions:
                pars.add_argument(f"--{slot}_{action}")

    def effect(self):
        self.is_installed()

        for name in list(self.options.__dict__):
            if "_" in name:
                self.set_options(self.options, name, self.options.__dict__.pop(name))

        # Remove old master slide property
        for node in self.svg.xpath(
            "//svg:g[@jessyink:customKeyBindings='customKeyBindings']"
        ):
            node.delete()

        # Set custom key bindings.
        node_text = """function getCustomKeyBindingsSub()
{
    var keyDict = new Object();
    keyDict[SLIDE_MODE] = new Object();
    keyDict[INDEX_MODE] = new Object();
    keyDict[DRAWING_MODE] = new Object();
"""

        for key, value in self.options.slideKeyCodes.items():
            node_text += f"    keyDict[SLIDE_MODE][{key}] = function() {{ {value} }};\n"

        for key, value in self.options.drawingKeyCodes.items():
            node_text += (
                f"    keyDict[DRAWING_MODE][{key}] = function() {{ {value} }};\n"
            )

        for key, value in self.options.indexKeyCodes.items():
            node_text += f"    keyDict[INDEX_MODE][{key}] = function() {{ {value} }};\n"

        # Set custom char bindings.
        node_text += """    return keyDict;
}

function getCustomCharBindingsSub()
{
    var charDict = new Object();
    charDict[SLIDE_MODE] = new Object();
    charDict[INDEX_MODE] = new Object();
    charDict[DRAWING_MODE] = new Object();
"""

        for key, value in self.options.slideCharCodes.items():
            node_text += (
                f'    charDict[SLIDE_MODE]["{key}"] = function() {{ {value} }};\n'
            )

        for key, value in self.options.drawingCharCodes.items():
            node_text += (
                f'    charDict[DRAWING_MODE]["{key}"] = function() {{ {value} }};\n'
            )

        for key, value in self.options.indexCharCodes.items():
            node_text += (
                f'    charDict[INDEX_MODE]["{key}"] = function() {{ {value} }};\n'
            )

        node_text += "    return charDict;" + "\n"
        node_text += "}" + "\n"

        # Create new script node
        group = self.svg.add(Group())
        script = group.add(Script())
        script.text = node_text
        group.set("jessyink:customKeyBindings", "customKeyBindings")
        group.set(
            "onload",
            "this.getCustomCharBindings = function() { "
            "return getCustomCharBindingsSub(); }; "
            "this.getCustomKeyBindings = function() { return getCustomKeyBindingsSub(); };",
        )


if __name__ == "__main__":
    KeyBindings().run()
