#!/usr/bin/python

"""Use xss_base to make a simple clone of chbg

   Doesn't bother with the fades, just selects the images"""

from __future__ import division
import xss_base
import os
import Image
import sys
import random
import optparse
import subprocess
import time

noisy = False

def fit_rect((in_w,in_h), (target_w, target_h)):
    """Fit input rectangle maximally within target rectangle"""

    in_ratio = in_w/in_h

    if target_h * in_ratio > target_w:
        return (target_w, target_w / in_ratio)
    else:
        return (target_h * in_ratio, target_h)

def int_rect((f_w,f_h)):
    """convert rectangle to ints to keep PIL happy"""
    return (int(f_w), int(f_h))


class chbg(xss_base.xss_base):
    """pick backgrounds from a directory"""

    delay = 5

    def __init__(self, picture_dir):
        xss_base.xss_base.__init__(self)

        self.recent = []
        # scan directories up front, but just keep sizes
        self.picture_dir = picture_dir
        self.sizes = {}
        self.age = {}
        now = time.time()
        for picfile in os.listdir(self.picture_dir):
            picpath = os.path.join(self.picture_dir, picfile)
            if not os.path.isfile(picpath):
                continue
            try:
                tmp_im = Image.open(picpath)
            except IOError, exc:
                if not picfile.endswith(".whence"):
                    print "Image.open failed on", picfile, "with:", exc
                continue
            if tmp_im.mode != "RGB":
                # TODO: put_pil_image supports "1" but I don't know why
                # TODO: support "P" for gif
                # TODO: support "RGBA" for png
                # TODO: support "L" for some jpgs                
                if noisy:
                    print "Wrong PIL mode", tmp_im.mode, "for", picfile, "- only RGB/ZPixmap supported"
                continue
            # w, h = tmp_im.size
            # if w <= self.rootscreen.width_in_pixels or h <= self.rootscreen.height_in_pixels:
            #     print "pic normally small thus boring, skipping"
            #     continue
            self.sizes[picpath] = tmp_im.size
            self.age[picpath] = now - os.path.getmtime(picpath)

    def render(self):
        imgpaths = self.sizes.keys()
        # bias towards newest ones; make 10 of them as likely as the rest?
        if len(imgpaths) > 10:
            emphasis = int(len(imgpaths)/9)
            young_line = sorted(self.age.values())[10]
            for picpath, age in self.age.items():
                if age < young_line:
                    imgpaths.extend([picpath] * emphasis)

        # add some bias against repetition - try again if we repeat one of the last N
        while True:
            picpath = random.choice(imgpaths)
            if picpath not in self.recent:
                print "chose", os.path.basename(picpath)
                break
            print "suppressed", os.path.basename(picpath)

        # 350 paths -> 35-deep suppression; 1 path -> none
        self.recent.append(picpath)
        if len(self.recent) > len(imgpaths)/10:
            self.recent.pop(0)
            
        # picpath = sorted(self.sizes.keys())[0]
        tmp_im = Image.open(picpath)

        if noisy:
            print "Trying:", os.path.basename(picpath)
            subprocess.call(["identify", picpath])

        geom = self.window.get_geometry()
        w, h = fit_rect(tmp_im.size,
                        (geom.width, geom.height))

        if (w, h) != tmp_im.size:
            if noisy:
                print "Resizing", tmp_im.size, "to", (w, h)
            tmp_im = tmp_im.resize(int_rect((w, h)), Image.ANTIALIAS)

        # center (modern python lacks a rectangle module...)
        x_off = geom.width/2 - w/2
        y_off = geom.height/2 - h/2

        self.window.clear_area(0, 0, 0, 0) # clear_window
        self.window.put_pil_image(self.gc, x_off, y_off, tmp_im)


if __name__ == "__main__":
    # TODO: add arg-stripping to xss_base
    parser = optparse.OptionParser(usage=__doc__)
    # parser.add_option("--window-id")
    parser.add_option("--noisy", action="store_true")
    # options, args = parser.parse_args(args=map(lambda x: 
    #                                            x.replace("-w", "--w"),
    #                                            sys.argv[1:]))
    options, args = xss_base.parse_args(parser)
    assert os.getenv("XSCREENSAVER_WINDOW"), os.environ
    if options.window_id:
        assert os.getenv("XSCREENSAVER_WINDOW") == options.window_id, options.window_id

    noisy = options.noisy
    picdir, = args
    saver = chbg(picdir)
    saver.run()

