#!/usr/bin/env python
# Copyright (C) 2008 Willi Richert <w.richert@gmx.net>
#
# $Id: AlbumFS.py,v 6cbb32764ed9 2009/04/05 12:39:52 w $
#

import os, tempfile, sys, shutil, errno, fuse
from PIL import Image
fuse.fuse_python_api = (0, 2)
IMG_SUFFIX=[".png", ".jpg", ".jpeg", ".gif"]
flat2real = {}

def get_real_path(path):
    real_path, flat_file = os.path.split(path)
    if path!="/":
        try: real_path = os.path.join(real_path, flat2real[flat_file])
        except: return None
    return real_path

class AlbumFS(fuse.Fuse):
    def __init__(self, root_path, *args, **kw):
        fuse.Fuse.__init__(self, *args, **kw)
        self.root_path = root_path
        self.file_class = AlbumFSFile
        os.chdir(self.root_path)
        self.parse(values=self, errex=1)
        self.thumb_temp_dir = tempfile.mkdtemp()
        self.statfs()
        
    def getattr(self, path):
        real_path = get_real_path(path)
        if real_path:
            return os.lstat(real_path)

    def readdir(self, path, offset):
        for target_name in flat2real.iterkeys():
            yield fuse.Direntry(target_name)

    def _create_thumb(self, unique_name):
        fn, ext = os.path.splitext(unique_name)
        im = Image.open(flat2real[unique_name])
        im.thumbnail((128, 128), Image.ANTIALIAS)
        thumb_fn = os.path.join(self.thumb_temp_dir, fn+"_thumbnail"+ext)
        im.save(thumb_fn)
        self.flat2thumb[unique_name] = thumb_fn
    
    def _reset_mapping(self):
        global flat2real
        flat2real = {}
        self.flat2thumb = {}
        for parent, dirs, files in os.walk("."):
            for fn in [fn for fn in files if os.path.splitext(fn)[1] in IMG_SUFFIX and os.path.isfile(os.path.join(parent,fn))]:
                elements = parent.split("/")
                if elements[0]==".": elements = elements[1:]
                parent = "_".join(elements)
                if parent:
                    unique_name = parent+"_"+fn
                    flat2real[unique_name] = os.path.join(self.root_path,parent,fn)
                else:
                    uniqe_name = fn
                    flat2real[unique_name] = os.path.join(self.root_path,fn)
                self._create_thumb(unique_name)
        flat2real["album.html"] = os.path.join(self.thumb_temp_dir, "album.html")

    def _gen_album_html(self):
        html_content = ['<div align="center"><h4>Album %s</h4><table cellspacing="10"><tbody align="center" valign="bottom" style="font-size:4px"><tr>'%self.root_path]
        max_items = len(self.flat2thumb)
        for idx, (unique_name, thumb_fn) in enumerate(self.flat2thumb.items()):
            img_info = Image.open(flat2real[unique_name]).size
            row_content = '<td><a href="file://%s" title="%s"><img src="%s" alt=""><br>%s</a><br>Size: %s</td>'%\
                          (flat2real[unique_name], unique_name, thumb_fn, unique_name, img_info)
            if 0<idx<max_items and idx%3==0:
                row_content = "</tr><tr>"+row_content
            html_content.append(row_content)
        html_content.append("</tr></tbody></table></div><body>")
        f=file(os.path.join(self.thumb_temp_dir, "album.html"), "w")
        f.writelines(html_content)
        f.close()
        
    def fsdestroy(self): shutil.rmtree(self.thumb_temp_dir)
    def statfs(self):
        self._reset_mapping()
        self._gen_album_html()
        return os.statvfs(".")
        
def flag2mode(flags):
    md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'}
    m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)]
    if flags | os.O_APPEND:
        m = m.replace('w', 'a', 1)
    return m

class AlbumFSFile(object):
    def __init__(self, path, flags, *mode):
        self.file = os.fdopen(os.open(get_real_path(path), flags, *mode), flag2mode(flags))
        self.fd = self.file.fileno()

    def read(self, length, offset):
        self.file.seek(offset)
        return self.file.read(length)

    def release(self, flags): 
        self.file.close()

if __name__ == '__main__':
    server = AlbumFS(sys.argv[2])
    server.main()
