#
# The Python Imaging Library.
# $Id$
#
# im.show() drivers
#
# History:
# 2008-04-06 fl   Created
#
# Copyright (c) Secret Labs AB 2008.
#
# See the README file for information on usage and redistribution.
#
import os
import shutil
import subprocess
import sys
import tempfile
from shlex import quote

from PIL import Image

_viewers = []


def register(viewer, order=1):
    try:
        if issubclass(viewer, Viewer):
            viewer = viewer()
    except TypeError:
        pass  # raised if viewer wasn't a class
    if order > 0:
        _viewers.append(viewer)
    elif order < 0:
        _viewers.insert(0, viewer)


def show(image, title=None, **options):
    r"""
    Display a given image.

    :param image: An image object.
    :param title: Optional title.  Not all viewers can display the title.
    :param \**options: Additional viewer options.
    :returns: True if a suitable viewer was found, false otherwise.
    """
    for viewer in _viewers:
        if viewer.show(image, title=title, **options):
            return 1
    return 0


class Viewer:
    """Base class for viewers."""

    # main api

    def show(self, image, **options):

        # save temporary image to disk
        if not (
            image.mode in ("1", "RGBA") or (self.format == "PNG" and image.mode == "LA")
        ):
            base = Image.getmodebase(image.mode)
            if image.mode != base:
                image = image.convert(base)

        return self.show_image(image, **options)

    # hook methods

    format = None
    options = {}

    def get_format(self, image):
        """Return format name, or None to save as PGM/PPM"""
        return self.format

    def get_command(self, file, **options):
        raise NotImplementedError

    def save_image(self, image):
        """Save to temporary file, and return filename"""
        return image._dump(format=self.get_format(image), **self.options)

    def show_image(self, image, **options):
        """Display given image"""
        return self.show_file(self.save_image(image), **options)

    def show_file(self, file, **options):
        """Display given file"""
        os.system(self.get_command(file, **options))
        return 1


# --------------------------------------------------------------------


if sys.platform == "win32":

    class WindowsViewer(Viewer):
        format = "PNG"
        options = {"compress_level": 1}

        def get_command(self, file, **options):
            return (
                'start "Pillow" /WAIT "%s" '
                "&& ping -n 2 127.0.0.1 >NUL "
                '&& del /f "%s"' % (file, file)
            )

    register(WindowsViewer)

elif sys.platform == "darwin":

    class MacViewer(Viewer):
        format = "PNG"
        options = {"compress_level": 1}

        def get_command(self, file, **options):
            # on darwin open returns immediately resulting in the temp
            # file removal while app is opening
            command = "open -a Preview.app"
            command = "({} {}; sleep 20; rm -f {})&".format(
                command, quote(file), quote(file)
            )
            return command

        def show_file(self, file, **options):
            """Display given file"""
            fd, path = tempfile.mkstemp()
            with os.fdopen(fd, "w") as f:
                f.write(file)
            with open(path, "r") as f:
                subprocess.Popen(
                    ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
                    shell=True,
                    stdin=f,
                )
            os.remove(path)
            return 1

    register(MacViewer)

else:

    # unixoids

    class UnixViewer(Viewer):
        format = "PNG"
        options = {"compress_level": 1}

        def get_command(self, file, **options):
            command = self.get_command_ex(file, **options)[0]
            return "({} {}; rm -f {})&".format(command, quote(file), quote(file))

        def show_file(self, file, **options):
            """Display given file"""
            fd, path = tempfile.mkstemp()
            with os.fdopen(fd, "w") as f:
                f.write(file)
            with open(path, "r") as f:
                command = self.get_command_ex(file, **options)[0]
                subprocess.Popen(
                    ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
                )
            os.remove(path)
            return 1

    # implementations

    class DisplayViewer(UnixViewer):
        def get_command_ex(self, file, **options):
            command = executable = "display"
            return command, executable

    if shutil.which("display"):
        register(DisplayViewer)

    class EogViewer(UnixViewer):
        def get_command_ex(self, file, **options):
            command = executable = "eog"
            return command, executable

    if shutil.which("eog"):
        register(EogViewer)

    class XVViewer(UnixViewer):
        def get_command_ex(self, file, title=None, **options):
            # note: xv is pretty outdated.  most modern systems have
            # imagemagick's display command instead.
            command = executable = "xv"
            if title:
                command += " -name %s" % quote(title)
            return command, executable

    if shutil.which("xv"):
        register(XVViewer)

if __name__ == "__main__":

    if len(sys.argv) < 2:
        print("Syntax: python ImageShow.py imagefile [title]")
        sys.exit()

    with Image.open(sys.argv[1]) as im:
        print(show(im, *sys.argv[2:]))
