#
# 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.
#

from __future__ import print_function

from PIL import Image
import os, sys

_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)

##
# Displays a given image.
#
# @param image An image object.
# @param title Optional title.  Not all viewers can display the title.
# @param **options Additional viewer options.
# @return True if a suitable viewer was found, false otherwise.

def show(image, title=None, **options):
    for viewer in _viewers:
        if viewer.show(image, title=title, **options):
            return 1
    return 0

##
# Base class for viewers.

class Viewer:

    # main api

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

        # save temporary image to disk
        if image.mode[:4] == "I;16":
            # @PIL88 @PIL101
            # "I;16" isn't an 'official' mode, but we still want to
            # provide a simple way to show 16-bit images.
            base = "L"
            # FIXME: auto-contrast if max() > 255?
        else:
            base = Image.getmodebase(image.mode)
        if base != image.mode and image.mode != "1":
            image = image.convert(base)

        self.show_image(image, **options)

    # hook methods

    format = None

    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))

    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 = "BMP"
        def get_command(self, file, **options):
            return ("start /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 = "BMP"
        def get_command(self, file, **options):
            # on darwin open returns immediately resulting in the temp
            # file removal while app is opening
            command = "open -a /Applications/Preview.app"
            command = "(%s %s; sleep 20; rm -f %s)&" % (command, file, file)
            return command

    register(MacViewer)

else:

    # unixoids

    def which(executable):
        path = os.environ.get("PATH")
        if not path:
            return None
        for dirname in path.split(os.pathsep):
            filename = os.path.join(dirname, executable)
            if os.path.isfile(filename):
                # FIXME: make sure it's executable
                return filename
        return None

    class UnixViewer(Viewer):
        def show_file(self, file, **options):
            command, executable = self.get_command_ex(file, **options)
            command = "(%s %s; rm -f %s)&" % (command, file, file)
            os.system(command)
            return 1

    # implementations

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

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

    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:
                # FIXME: do full escaping
                command = command + " -name \"%s\"" % title
            return command, executable

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

if __name__ == "__main__":
    # usage: python ImageShow.py imagefile [title]
    print(show(Image.open(sys.argv[1]), *sys.argv[2:]))
