#!/usr/bin/env python
# -*- coding: utf-8; mode: Python -*-
#
#
# Lars Jørgen Solberg <supersolberg@gmail.com> 2014
#

from __future__ import print_function
from __future__ import division
from __future__ import unicode_literals

import argparse
import sys
import io
import time

from PIL import Image

from shellpic import *

def main():    
    # parse command line parameters
    parser = argparse.ArgumentParser()
    parser.add_argument("image", help="Use '-' to read from STDIN")
    parser.add_argument("--version", action="version", version="Version: " + shellpic.VERSION,
                        help="Print verions number and exit.")

    parser.add_argument("--shell4", action="store_const", const=Shell4Bit, dest='formatter_class',
                        help="Print text suitable for a shell capable of displaying 16 colors")
    parser.add_argument("--shell8", action="store_const", const=Shell8Bit, dest='formatter_class',
                        help="Print text suitable for a shell capable of displaying 8bit colors (default)")
    parser.add_argument("--shell24", action="store_const", const=Shell24Bit, dest='formatter_class', 
                        help="Print text suitable for a shell capable of displaying 24bit colors")
    parser.add_argument("--irc", action="store_const", const=Irc, dest='formatter_class', 
                        help="Print text suitable for piping to an irc client")
    parser.add_argument("--nuts", action="store_const", const=Nuts, dest='formatter_class', 
                        help="Print text suitable for piping to a NUTS talker client")

    parser.add_argument("--no-scale", action="store_true",
                        help="Do not attempt to scale the image to fit the terminal")
    parser.add_argument("--scale-x", nargs=1, type=int,
                        help="Scale the image to this width")
    parser.add_argument("--scale-y", nargs=1, type=int,
                        help="Scale the image to this height")

    parser.add_argument("--animate", action="store_true", 
                        help="Animate the image once")
    parser.add_argument("--loop", action="store_true", 
                        help="Animate the image and loop indefinetly")
    args = parser.parse_args()    




    # create the right kind of 'Formatter'
    if args.formatter_class:
        formatter = args.formatter_class()
    else:
        formatter = Shell8Bit()

    dimentions = formatter.dimentions()

    # load the image
    if args.image == '-':
        # we need to copy the entire image to a buffer as PIL likes to seek()
        buf = io.StringIO()
        buf.write(sys.stdin.read())
        buf.seek(0)
        img = Image.open(buf)
        img.load() 
    else:
        try:
            img = Image.open(args.image)
        except IOError as ecxp:
            sys.stderr.write(str(excp) + '\n')
            exit(1)

    # grab what we need from the info-property, as some transformations might change them
    if 'background' in img.info:
        formatter.bgcolor = shellpic.ensure_rgb(img.palette, img.info['background'])
    if 'duration' in img.info:
        frame_delay = img.info['duration']
    else:
        frame_delay = 0

    # extract the frames for animation
    dispose_frames = []    
    if args.animate or args.loop:
        frames = [img.copy()]

        while True:
            try:
                if hasattr(img, 'dispose'):
                    dispose_frames.append(img.dispose)
                else:
                    dispose_frames.append(None)
                img.seek(img.tell() + 1)
                frames.append(img.copy())
            except EOFError:
                break
    else:
        frames = [img.copy()]
        if hasattr(img, 'dispose'):
            dispose_frames = [img.dispose]

    # scale it to fit the terminal
    if not args.no_scale:
        if args.scale_x:
            dimentions = [args.scale_x[0], dimentions[1]]
        if args.scale_y:
            dimentions = [dimentions[0], args.scale_y[0]]
        
        # it seems like each frame must be resized individually 
        for i in range(len(frames)):
            frames[i] = shellpic.scale(frames[i], *dimentions)

        try:
            for i in range(len(dispose_frames)):
                if dispose_frames[i]:
                    dispose_frames[i] = shellpic.scale(dispose_frames[i], *dimentions)
        except ValueError:
            # how is this possible? This exception should be cought in scale()
            pass # FIXME do something smart

    # convert the image to RGBA, this must be done after any
    # resizing to prevent artifacts
    for i in range(len(frames)):
        frames[i] = frames[i].convert('RGBA')
    for i in range(len(dispose_frames)):
        if dispose_frames[i]:
            dispose_frames[i] = dispose_frames[i].convert('RGBA')

    # print the image as an animation
    if args.animate or args.loop:
        try:
            delay = frame_delay / 1000
            while True:
                for frame, dispose in zip(frames, dispose_frames):
                    start = time.time()
                    if sys.version_info[0] == 3:
                        print(formatter.format(frame, dispose), end='')
                    else:
                        print(formatter.format(frame, dispose).encode('utf-8'), end='')
                    done = time.time()
                    time.sleep(max(0.0 , delay - (done - start)))
                if not args.loop:
                    print()
                    break
        except KeyboardInterrupt:
            if sys.version_info[0] == 3:
                print(formatter.format(frame, dispose))
            else:
                print(formatter.format(frame, dispose).encode('utf-8'))
            
        except NotImplementedError:
            sys.stderr.write('Animation is not implemented for ' + formatter.__class__.__name__ + '\n')
            exit(1)
    else:
        # or print the result to STDOUT        
        if sys.version_info[0] == 3:
            print(formatter.format(frames[0]))
        else:
            print(formatter.format(frames[0]).encode('utf-8'))


if __name__ == "__main__":
    main()
