# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim 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.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.

import os
import sys
from pathlib import Path

from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import GObject

from gajim.common import app
from gajim.common.i18n import _

from gajim.gtk.const import Filter
from gajim.gtk.types import FilterList  # pylint: disable=unused-import


def _require_native() -> bool:
    if app.is_flatpak():
        return True
    if sys.platform in ('win32', 'darwin'):
        return True
    return False


# Notes: Adding mime types to Gtk.FileFilter forces non-native dialogs

class BaseFileChooser:
    def _on_response(self, dialog, response, accept_cb, cancel_cb):
        if response == Gtk.ResponseType.ACCEPT:
            if self.get_select_multiple():
                accept_cb(dialog.get_filenames())
            else:
                accept_cb(dialog.get_filename())

        if response in (Gtk.ResponseType.CANCEL,
                        Gtk.ResponseType.DELETE_EVENT):
            if cancel_cb is not None:
                cancel_cb()

    def _add_filters(self, filters):
        for filterinfo in filters:
            filter_ = Gtk.FileFilter()
            filter_.set_name(filterinfo.name)
            if isinstance(filterinfo.pattern, list):
                for mime_type in filterinfo.pattern:
                    filter_.add_mime_type(mime_type)
            else:
                filter_.add_pattern(filterinfo.pattern)
            self.add_filter(filter_)
            if filterinfo.default:
                self.set_filter(filter_)

    def _update_preview(self, filechooser):
        path_to_file = filechooser.get_preview_filename()
        preview = filechooser.get_preview_widget()
        if path_to_file is None or os.path.isdir(path_to_file):
            # nothing to preview
            preview.clear()
            return
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                path_to_file, *self._preivew_size)
        except GObject.GError:
            preview.clear()
            return
        filechooser.get_preview_widget().set_from_pixbuf(pixbuf)


class BaseFileOpenDialog:

    _title = _('Choose File to Send…')
    _filters = [Filter(_('All files'), '*', True)]  # type: FilterList


class BaseAvatarChooserDialog:

    _title = _('Choose Avatar…')
    _preivew_size = (100, 100)

    if _require_native():
        _filters = [Filter(_('PNG files'), '*.png', True),
                    Filter(_('JPEG files'), '*.jp*g', False),
                    Filter(_('SVG files'), '*.svg', False)]  # type: FilterList
    else:
        _filters = [Filter(_('Images'), ['image/png',
                                         'image/jpeg',
                                         'image/svg+xml'], True)]


class NativeFileChooserDialog(Gtk.FileChooserNative, BaseFileChooser):

    _title = ''
    _filters = []  # type: FilterList
    _action = Gtk.FileChooserAction.OPEN

    def __init__(self, accept_cb, cancel_cb=None, transient_for=None,
                 path=None, file_name=None, select_multiple=False,
                 modal=False):

        Gtk.FileChooserNative.__init__(self,
                                       title=self._title,
                                       action=self._action,
                                       transient_for=transient_for)

        self.set_current_folder(path or str(Path.home()))
        if file_name is not None:
            self.set_current_name(file_name)
        self.set_select_multiple(select_multiple)
        self.set_do_overwrite_confirmation(True)
        self.set_modal(modal)
        self._add_filters(self._filters)

        self.connect('response', self._on_response, accept_cb, cancel_cb)
        self.show()


class ArchiveChooserDialog(NativeFileChooserDialog):

    _title = _('Choose Archive')
    _filters = [Filter(_('All files'), '*', False),
                Filter(_('ZIP files'), '*.zip', True)]


class FileSaveDialog(NativeFileChooserDialog):

    _title = _('Save File as…')
    _filters = [Filter(_('All files'), '*', True)]
    _action = Gtk.FileChooserAction.SAVE


class AvatarSaveDialog(FileSaveDialog):

    if sys.platform == 'win32':
        _filters = [Filter(_('Images'), '*.png;*.jpg;*.jpeg;*.svg', True)]


class NativeFileOpenDialog(BaseFileOpenDialog, NativeFileChooserDialog):
    pass


class NativeAvatarChooserDialog(BaseAvatarChooserDialog, NativeFileChooserDialog):
    pass


class GtkFileChooserDialog(Gtk.FileChooserDialog, BaseFileChooser):

    _title = ''
    _filters = []  # type: FilterList
    _action = Gtk.FileChooserAction.OPEN
    _preivew_size = (200, 200)

    def __init__(self, accept_cb, cancel_cb=None, transient_for=None,
                 path=None, file_name=None, select_multiple=False,
                 preview=True, modal=False):

        Gtk.FileChooserDialog.__init__(
            self,
            title=self._title,
            action=self._action,
            buttons=[Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                     Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT],
            transient_for=transient_for)

        self.set_current_folder(path or str(Path.home()))
        if file_name is not None:
            self.set_current_name(file_name)
        self.set_select_multiple(select_multiple)
        self.set_do_overwrite_confirmation(True)
        self.set_modal(modal)
        self._add_filters(self._filters)

        if preview:
            self.set_use_preview_label(False)
            self.set_preview_widget(Gtk.Image())
            self.connect('selection-changed', self._update_preview)

        self.connect('response', self._on_response, accept_cb, cancel_cb)
        self.show()

    def _on_response(self, *args):
        super()._on_response(*args)
        self.destroy()


class GtkFileOpenDialog(BaseFileOpenDialog, GtkFileChooserDialog):
    pass


class GtkAvatarChooserDialog(BaseAvatarChooserDialog, GtkFileChooserDialog):
    pass


def FileChooserDialog(*args, **kwargs):
    if _require_native():
        return NativeFileOpenDialog(*args, **kwargs)
    return GtkFileOpenDialog(*args, **kwargs)


def AvatarChooserDialog(*args, **kwargs):
    if _require_native():
        return NativeAvatarChooserDialog(*args, **kwargs)
    return GtkAvatarChooserDialog(*args, **kwargs)