# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline 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.
#
# Timeline 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 Timeline.  If not, see <http://www.gnu.org/licenses/>.


import os
import re

import wx

from . import EXPORTER
from timelinelib.plugin.pluginbase import PluginBase
from timelinelib.wxgui.framework import Controller
from timelinelib.wxgui.framework import Dialog
from timelinelib.wxgui.utils import WildcardHelper


class ImageExporter(PluginBase):

    def service(self):
        return EXPORTER

    def display_name(self):
        return _("Export to Image...")

    def wxid(self):
        from timelinelib.wxgui.frames.mainframe.menus import ID_EXPORT_IMAGE
        return ID_EXPORT_IMAGE

    def run(self, main_frame):
        dialog = ExportToImageDialog(
            main_frame,
            main_frame.main_panel.timeline_panel.timeline_canvas
        )
        dialog.ShowModal()
        dialog.Destroy()


class ExportToImageDialog(Dialog):

    """
    <BoxSizerVertical>
        <StaticBoxSizerVertical label="$(options_label)" border="ALL" proportion="1">
            <FlexGridSizer rows="0" columns="2" border="ALL" growableColumns="1">
                <StaticText
                    label="$(image_type_label)"
                    align="ALIGN_CENTER_VERTICAL"
                />
                <BoxSizerHorizontal align="ALIGN_CENTER_VERTICAL">
                    <RadioButton
                        name="image_type_png_button"
                        event_EVT_RADIOBUTTON="on_image_type_changed"
                        label="PNG"
                    />
                    <RadioButton
                        name="image_type_svg_button"
                        event_EVT_RADIOBUTTON="on_image_type_changed"
                        label="SVG"
                    />
                </BoxSizerHorizontal>
                <StaticText
                    label="$(path_label)"
                    align="ALIGN_CENTER_VERTICAL"
                />
                <FileChooser
                    name="path_chooser"
                    event_EVT_FILE_PATH_CHANGED="on_path_changed"
                    dialog_wildcard="$(path_wildcard)"
                    dialog_style="save"
                    width="300"
                />
                <StaticText
                    label="$(width_label)"
                    align="ALIGN_CENTER_VERTICAL"
                />
                <BoxSizerHorizontal>
                    <TextCtrl
                        name="width_text"
                        width="100"
                    />
                </BoxSizerHorizontal>
                <StaticText
                    label="$(height_label)"
                    align="ALIGN_CENTER_VERTICAL"
                />
                <BoxSizerHorizontal>
                    <TextCtrl
                        name="height_text"
                        width="100"
                    />
                    <Spacer />
                    <CheckBox
                        label="$(adjust_automatically_label)"
                        name="automatic_height_checkbox"
                        event_EVT_CHECKBOX="on_automatic_height_changed"
                    />
                </BoxSizerHorizontal>
            </FlexGridSizer>
        </StaticBoxSizerVertical>
        <DialogButtonsOkCancelSizer
            border="LEFT|BOTTOM|RIGHT"
            event_EVT_BUTTON__ID_OK="on_ok_clicked"
        />
    </BoxSizerVertical>
    """

    def __init__(self, parent, timeline_canvas):
        Dialog.__init__(self, ExportToImageDialogController, parent, {
            "options_label": _("Export Options"),
            "image_type_label": _("Image Type:"),
            "path_label": _("Path:"),
            "path_wildcard": WildcardHelper(_("Image files"), ["png", "svg"]).wildcard_string(),
            "width_label": _("Width:"),
            "height_label": _("Height:"),
            "adjust_automatically_label": _("Adjust automatically"),
        }, title=_("Export to Image"))
        self.controller.on_init(timeline_canvas)

    def IsPngSelected(self):
        return self.image_type_png_button.GetValue()

    def SelectPng(self):
        return self.image_type_png_button.SetValue(True)

    def IsSvgSelected(self):
        return self.image_type_svg_button.GetValue()

    def SelectSvg(self):
        return self.image_type_svg_button.SetValue(True)

    def GetPath(self):
        return self.path_chooser.GetFilePath()

    def SetPath(self, path):
        return self.path_chooser.SetFilePath(path)

    def GetWidth(self):
        return self.width_text.GetValue()

    def SetWidth(self, value):
        self.width_text.SetValue(value)

    def GetHeight(self):
        return self.height_text.GetValue()

    def SetHeight(self, value):
        self.height_text.SetValue(value)

    def EnableHeight(self, value):
        self.height_text.Enable(value)

    def IsAutomaticHeight(self):
        return self.automatic_height_checkbox.GetValue()

    def SetAutomaticHeight(self, value):
        self.automatic_height_checkbox.SetValue(value)


class ExportToImageDialogController(Controller):

    def on_init(self, timeline_canvas):
        self.timeline_canvas = timeline_canvas
        self.EXTENSIONS = {
            "png": {
                "pattern": "[.][pP][nN][gG]$",
                "name": "png",
                "is_selected_fn": self.view.IsPngSelected,
                "select_fn": self.view.SelectPng,
            },
            "svg": {
                "pattern": "[.][sS][vV][gG]$",
                "name": "svg",
                "is_selected_fn": self.view.IsSvgSelected,
                "select_fn": self.view.SelectSvg,
            },
        }
        self.view.SetPath(os.path.expanduser("~/export.png"))
        self.on_path_changed(None)
        self.view.SetWidth(str(self.timeline_canvas.GetSize()[0]))
        self.view.SetHeight(str(self.timeline_canvas.GetSize()[1]))
        self.view.SetAutomaticHeight(True)
        self.on_automatic_height_changed(None)

    def on_image_type_changed(self, event):
        extension = self._get_selected_extension()
        if not re.search(extension["pattern"], self.view.GetPath()):
            self.view.SetPath(os.path.splitext(self.view.GetPath())[0]+"."+extension["name"])

    def on_path_changed(self, event):
        matched_extension = self._get_matched_extension()
        if matched_extension:
            matched_extension["select_fn"]()

    def on_automatic_height_changed(self, event):
        self.view.EnableHeight(not self.view.IsAutomaticHeight())

    def on_ok_clicked(self, event):
        try:
            self.timeline_canvas.SaveAsImage(
                path=self._get_path(),
                width=self._get_width(),
                height=self._get_height(),
                image_type=self._get_selected_extension()["name"]
            )
            self.view.Close()
        except ValidationError:
            pass

    def _get_path(self):
        if not self._get_matched_extension():
            self.view.DisplayErrorMessage(_("Path has invalid extension."))
            raise ValidationError()
        path = self.view.GetPath()
        if not os.path.exists(os.path.dirname(path)):
            self.view.DisplayErrorMessage(_("Directory in path does not exist."))
            raise ValidationError()
        if (os.path.exists(path) and
            self.view.AskYesNo(_("File '%s' exists. Overwrite?") % path) == wx.NO):
            raise ValidationError()
        return path

    def _get_width(self):
        try:
            return int(self.view.GetWidth())
        except ValueError:
            self.view.DisplayErrorMessage(_("Width is not a number."))
            raise ValidationError()

    def _get_height(self):
        if self.view.IsAutomaticHeight():
            return None
        try:
            return int(self.view.GetHeight())
        except ValueError:
            self.view.DisplayErrorMessage(_("Height is not a number."))
            raise ValidationError()

    def _get_matched_extension(self):
        for extension in self.EXTENSIONS.values():
            if re.search(extension["pattern"], self.view.GetPath()):
                return extension

    def _get_selected_extension(self):
        for extension in self.EXTENSIONS.values():
            if extension["is_selected_fn"]():
                return extension
        raise ValueError("Could not determine file extension.")


class ValidationError(Exception):
    pass
