#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# ***Image Module error for PNG format, change back to 'imagaemagick - convert'
#
# Prerequist:
#   # aptitude install apache2 libapache2-mod-wsgi python-imaging imagemagick

import os
import sys
import shutil
import urllib
import Image

#image settings
#thumb: thumbnail image
thumb_qual = 75
max_thumb_size = 128
thumb_prefix = 'thumb_'

#orig_thumb: tiny jpg file, for showing original image orientation
orig_thumb_qual = 75
max_orig_thumb_size = 24
orig_thumb_prefix = 'orig_thumb_'

#view: image for viewing
view_qual = 80                      # viewing image quality
max_view_height = 600
max_view_width = 900
view_prefix = 'view_'               # prefix for viewing image

#system settings
admin_url = '.admin-pythongal'      # url path for admin_mode
template_file = 'template.html'     # template filename
#pymodules_dir = '/var/www/.pymodules'

#internal settings
sys_dir = '._gal'       # hidden dir, store thumbnail img

#global variable
br = '<br />\n'

def _debug(environ):
    txt = ''
    for i in environ:
        txt += br + '<b>'+str(i) + '</b>: ' + str(environ[i])
    return txt

def abs_dir(dir):
    tmp = [i for i in [root,dir] if i != '']
    return os.path.join( *tmp )

def path_join(*argv):
    if type(argv) not in [type(()),type([])]:
        argv = [argv]
    tmp = []
    for i in argv:
        if type(i) in [type(()),type([])]:
            tmp.extend(i)
        elif type(i) != type(''):
            tmp.append(str(i))
        else:
            tmp.append(i)
    return '/'.join( [i for i in tmp if i != ''] )

def get_href(cur_web_dir, *argv):
    if '/' in cur_web_dir:
        return '?a=' + path_join(cur_web_dir,*argv)
    else:
        tmp = path_join(cur_web_dir,*argv)
        if tmp:
            return '?a=' + tmp
        else:
            return '?'

def get_win_loc(environ,string):
    return 'window.location="%s"' % (environ["HTTP_REFERER"].split('?')[0]+string,)

def is_jpg(filename):
    if '.' in filename \
    and os.path.splitext(filename)[1][1:].lower() in ('jpeg','jpg'):
        return True
    else:
        return False

def is_image(filename):
    if '.' in filename \
    and os.path.splitext(filename)[1][1:].lower() in ('jpeg','jpg','png','gif','tif','tiff'):
        return True
    else:
        return False

def get_img_filename(filename,prefix=thumb_prefix):
    """filename.jpg -> thumb_filename.jpg
    filename.png -> thumb_filename.png.jpg"""

    name,ext = os.path.splitext(filename)
    if ext.lower() in ['.jpg','.jpeg']:
        return prefix+filename
    else:
        return prefix+filename+'.jpg'

def get_img_filelist(cwd,prefix="",rename=True):
    """list image files in current dir"""
    file_list = [i for i in os.listdir(cwd) if is_image(i)]
    file_list.sort()
    if rename:
        for i in range(len(file_list)):
            file_list[i] = get_img_filename(file_list[i],prefix)
        return file_list
    else:
        return [ prefix+i for i in file_list ]

def get_breadcrumb(nav):
    """create breadcrumb from url"""
    nav_list = [i for i in nav.split('/') if i != '']
    orig_nav_list = nav_list[:]
    tmp = ''
    for i in range(len(nav_list)-1):
        q = urllib.quote( path_join(orig_nav_list[:i+1]) )
        nav_list[i] = '<a href="?a=%s">%s</a>' % (q, nav_list[i],)
    if nav_list:
        nav_list[-1] = '<strong>%s</strong>' % nav_list[-1]
    if nav:
        nav_list.insert(0,'<a href="?">Root</a>')
    else:
        nav_list.insert(0,'<strong>Root</strong>')
    return '<div class="breadcrumb">' + ' » '.join(nav_list) + '</div>\n'

def create_scale_img(cwd,filename,rotate=0,force=False):
    """Scale image to fit x < max_view_width or y < max_view_height,
    force overwrite"""
    cmd_thumb = ''
    cmd_orig_thumb = ''
    cmd_view = ''
    img_file = os.path.join(cwd,filename)
    thumb_file = os.path.join(cwd,sys_dir,get_img_filename(filename,thumb_prefix))
    orig_thumb_file = os.path.join(cwd,sys_dir,get_img_filename(filename,orig_thumb_prefix))
    view_file = os.path.join(cwd,sys_dir,get_img_filename(filename,view_prefix))

    img = Image.open(img_file)
    if int(rotate) in [90,270,-90,-270]:
        isy,isx = img.size
    else:
        isx,isy = img.size

    if force or not os.path.exists(thumb_file):
        #thumbnail image
        sx = float(max_thumb_size)/isx
        sy = float(max_thumb_size)/isy
        if sx > 1 or sy > 1:
            if is_jpg(filename):
                shutil.copyfile(img_file,thumb_file)
            else:
                os.system('convert %s %s' % (img_file,thumb_file,))
        else:
            if sx > sy:
                new_size = 'x'+str(max_thumb_size)
            else:
                new_size = str(max_thumb_size)
            if rotate:
                cmd_thumb += ' -rotate %s' % (rotate,)
            cmd_thumb += ' -thumbnail %s' % (new_size,)
            cmd_thumb += ' -quality %s' % (thumb_qual,)
            cmd_thumb += " '%s'" % (thumb_file,)

    if force or not os.path.exists(view_file):
        #view image
        sx = float(max_view_width)/isx
        sy = float(max_view_height)/isy
        if sx > 1 or sy > 1:
            if is_jpg(filename):
                shutil.copyfile(img_file,view_file)
            else:
                os.system('convert %s %s' % (img_file,view_file,))
        else:
            if sx > sy:
                new_size = 'x'+str(max_view_height)
            else:
                new_size = str(max_view_width)
            if cmd_thumb:
                cmd_view += ' \( +clone '
            if rotate:
                cmd_view += ' -rotate %s' % (rotate,)
            cmd_view += ' -resize %s' % (new_size,)
            cmd_view += ' -quality %s' % (view_qual,)
            if cmd_thumb:
                cmd_view += ' -write'
            cmd_view += " '%s'" % (view_file,)
            if cmd_thumb:
                cmd_view += ' +delete \) '

    if not os.path.exists(orig_thumb_file):
        #original thumbnail
        sx = float(max_orig_thumb_size)/isx
        sy = float(max_orig_thumb_size)/isy
        if sx > sy:
            new_size = 'x'+str(max_orig_thumb_size)
        else:
            new_size = str(max_orig_thumb_size)
        if cmd_thumb or cmd_view:
            cmd_orig_thumb += ' \( +clone '
        cmd_orig_thumb += ' -thumbnail %s' % (new_size,)
        cmd_orig_thumb += ' -quality %s' % (orig_thumb_qual,)
        if cmd_thumb or cmd_view:
            cmd_orig_thumb += ' -write'
        cmd_orig_thumb += " '%s'" % (orig_thumb_file,)
        if cmd_thumb or cmd_view:
            cmd_orig_thumb += ' +delete \) '

    if cmd_view or cmd_thumb or cmd_orig_thumb:
        cmd = "convert '%s'" % (img_file,) + cmd_view + cmd_orig_thumb + cmd_thumb
        os.system(cmd)
    return

def create_img(cur_web_dir):
    """Create copy of images in directory - cur_web_dir"""
    cwd = abs_dir(cur_web_dir)
    file_list = get_img_filelist(cwd,prefix="",rename=False)
    if not file_list:
        return
    #cwd = current working directory
    sys_cwd = os.path.join(cwd,sys_dir)
    if not os.path.isdir(sys_cwd):
        os.mkdir(sys_cwd)
    for i in range(len(file_list)):
        create_scale_img(cwd,file_list[i])

    fl_jpg = get_img_filelist(cwd,prefix="",rename=True)
    tmp = [ thumb_prefix+i for i in fl_jpg ]
    tmp.extend( [orig_thumb_prefix+i for i in fl_jpg] )
    tmp.extend( [view_prefix+i for i in fl_jpg] )
    for f in get_img_filelist(sys_cwd):
        if f not in tmp:
            os.remove(os.path.join(sys_cwd,f))
    return

def get_rotate_link(c,f):
    txt = '<img class="nomg" src="%s/%s/%s" title="Rotate from riginal image" />' \
        % (c,sys_dir,get_img_filename(f,prefix=orig_thumb_prefix),)
    txt += ' <a href="?a=%s/_r90/%s" title="Rotate right 90deg">&gt;</a> ' % (c,f,)
    txt += ' <a href="?a=%s/_r180/%s" title="Rotate 180degree">C</a> ' % (c,f,)
    txt += ' <a href="?a=%s/_r270/%s" title="Rotate left 270deg">&lt;</a> ' % (c,f,)
    txt += ' <a href="?a=%s/_r360/%s" title="Rotate 360degree">O</a> ' % (c,f,)
    return txt

def get_rotate_radio(n,filename):
    txt = ''
    for i in [0,90,180,270,360]:
        txt += '<input type="radio" name="rot_%s" value="%s/%s" />%s' % (n,filename,i,i,)
        if i == 180: txt += '<br />' 
    return txt

def show_view(cur_web_dir,filename):
    tt = '%s - Click to enlarge' % (filename,)
    href = '/'.join( [i for i in [cur_web_dir,filename] if i != ''] )
    src = path_join(cur_web_dir,sys_dir,get_img_filename(filename,prefix=view_prefix))
    txt = '''\
  <a id="show_img" href="%s"><img src="%s" alt="%s" title="%s" /></a>\
''' % (href,src,tt,tt,)
    if admin_mode:
        txt += get_rotate_link(cur_web_dir,filename)
    return '''\
<div class="show">
  <div class="clear">&nbsp;</div>
  %s
</div>\
''' % (txt,)

def show_thumb_line(cur_web_dir,prev_img,next_img,is_tiny=False):

    def thumb_div(cur_web_dir,filename,dim,is_tiny=False):
        href = get_href(cur_web_dir,filename)
        src = path_join(cur_web_dir,sys_dir,get_img_filename(filename,prefix=thumb_prefix))
        tt = "%s - Click to enlarge" % (filename,)
        txt = '<a href="%s"><img src="%s" %s alt="%s" title="%s" /></a>'\
            % (href,src,dim,tt,tt,)
        if admin_mode and not is_tiny:
            txt += '<br />' + get_rotate_link(cur_web_dir,filename)
        return '<div class="show_thumb">%s</div>' % (txt,)

    txt = ''
    if is_tiny:
        dim = 'width="24"'
        klass = "tiny nav"
    else:
        dim = 'height="86"'
        klass = "nav center"
    if is_tiny:
        if prev_img:
            txt += thumb_div(cur_web_dir,prev_img[-1],dim,is_tiny)
    else:
        for filename in prev_img:
            txt += thumb_div(cur_web_dir,filename,dim)
    if cur_web_dir:
        href = '?a=' + path_join(cur_web_dir.split('/'))
    else:
        href = '?'
    txt += '<a class="button" href="%s">Up</a>' % (href,)
    if is_tiny:
        if next_img:
            txt += thumb_div(cur_web_dir,next_img[0],dim,is_tiny)
    else:
        for filename in next_img:
            txt += thumb_div(cur_web_dir,filename,dim)

    return '''
  <div class="%s">
    %s
  </div>''' % (klass,txt,)
    
def view_page(page,cur_web_dir,filename):
    dir_list = [ i for i in os.listdir(os.path.join(root,cur_web_dir))\
                if is_image(i)]
    dir_list.sort()
    l = len(dir_list)
    n = 0
    if filename in dir_list:
        n = dir_list.index(filename)
    prev_img = []
    img_count = 3
    if admin_mode:
        img_count = 1
    for i in range(-img_count,0,1):
        if n+i >= 0:
            prev_img.append(dir_list[n+i])
    next_img = []
    if admin_mode:
        img_count = 10
    for i in range(1,img_count+1):
        if n+i < l:
            next_img.append(dir_list[n+i])

    #SHOW
    page['main'].append( show_view(cur_web_dir,filename) )

    #LOWER NAV: THUMB
    page['main'].append( show_thumb_line(cur_web_dir,prev_img,next_img,is_tiny=False) )

    #TINY NAV: THUMB
    page['head'].append( show_thumb_line(cur_web_dir,prev_img,next_img,is_tiny=True) )

    return page

def show_upper_dir_list(cur_web_dir):
    upper_web_dir = path_join(cur_web_dir.split('/')[:-1])
    this_dir = cur_web_dir.split('/')[-1]
    abs_upper_dir = os.path.join(root,upper_web_dir)
    dir_list = [i for i in os.listdir(abs_upper_dir)\
        if os.path.isdir(os.path.join(abs_upper_dir,i))
        and i[0] != '.'] 
    dir_list.sort()
    dir_list.insert(0,'..')
    for i in range(len(dir_list)):
        if dir_list[i] == this_dir:
            dir_list[i] = '<span class="invert">%s</span>' % (dir_list[i],)
        elif dir_list[i] == '..':
            dir_list[i] = '<a href="?">%s</a>' % (dir_list[i],)
        else:
            dir_list[i] = '<a href="?a=%s">%s</a></li>' \
                % (path_join(upper_web_dir,dir_list[i]),dir_list[i],)

    dir_list = ['<li class="sbl">%s</li>' % (i,) for i in dir_list]
    return '''\
<ul class="none">
  %s
</ul>''' % ('\n'.join(dir_list),)

def browse_page(page,cur_web_dir):
    #Get sidebar-left from same level dir list
    if cur_web_dir:
        page['sbleft'].append( show_upper_dir_list(cur_web_dir) )

    #Browse
    txt_thumb = ''
    abs_cur_dir = abs_dir(cur_web_dir)
    #DIR
    dir_list = [i for i in os.listdir(abs_cur_dir) \
        if os.path.isdir(os.path.join(abs_cur_dir,i))\
        and i[0] != '.']
    dir_list.sort()
    if cur_web_dir:
        dir_list.insert(0,'..')
    for d in dir_list:
        if d == '..':
            if '/' in cur_web_dir:
                href = '?a=' + path_join(cur_web_dir.split('/')[:-1])
            else:
                href = '?'
            tt = 'Up'
        else:
            tt = path_join(cur_web_dir,d)
            href = '?a=' + tt

        sub_sys_dir = path_join(abs_cur_dir,d,sys_dir)
        tmp = ''
        if os.path.exists(sub_sys_dir) and os.path.isdir(sub_sys_dir):
            tmp = get_img_filelist(path_join(abs_cur_dir,d),prefix=thumb_prefix,rename=True)
            if tmp:
                txt = '<img src="%s" /><br />'\
                    % (path_join(cur_web_dir,d,sys_dir,tmp[0]),)
        if not tmp:
            txt = ''

        txt_thumb += '<a class="show_folder" href="%s" title="%s">%s%s</a>'\
            % (href,tt,txt,d,)

    #FILE
    if admin_mode:
        #all files
        dir_list = [ i for i in os.listdir(abs_cur_dir)\
            if os.path.isfile(os.path.join(abs_cur_dir,i))\
            and i[0] != '.']
    else:
        #only image files
        dir_list = [ i for i in os.listdir(abs_cur_dir)\
            if os.path.isfile(os.path.join(abs_cur_dir,i))\
            and i[0] != '.'\
            and is_image(os.path.join(abs_cur_dir,i))]
    dir_list.sort()

    img_exist = False
    for f in dir_list:
        thumb_name = get_img_filename(f,prefix=thumb_prefix)
        view_name = get_img_filename(f,prefix=view_prefix)
        if os.path.exists(os.path.join(abs_cur_dir,sys_dir,thumb_name)):
            tt = 'Click to enlarge - %s' % (f,)
            src= path_join(cur_web_dir,sys_dir,thumb_name)
            href= '?a=' + path_join(cur_web_dir,f)
            #txt = '<img class="show_thumb" src="%s" alt="%s" title="%s" />'\
            txt = '<img src="%s" alt="%s" title="%s" />'\
                % (src,tt,tt,)
            klass = "show_thumb"
        else:
            tt = txt = f
            href= path_join(cur_web_dir,f)
            klass = "show_file"

        if admin_mode:
            n = 0
            if is_image(f):
                n = dir_list.index(f)
                if not img_exist:
                    img_exist = True
                radio = get_rotate_radio(n,f)
                tmp = "Rotate from original image"
                src = path_join(cur_web_dir,sys_dir,\
                    get_img_filename(f,prefix=orig_thumb_prefix))
                img = '<img src="%s" alt="%s" title="%s" />' % (src,tmp,tmp,)
            else:
                radio = img = ''
            txt_thumb += '<div class="%s"><a href="%s" title="%s">%s</a><br /><div class="tiny_rotate">%s%s</div></div>'\
                % (klass,href,tt,txt, img,radio,)
        else:
            txt_thumb += '<a class="%s" href="%s" title="%s">%s</a>'\
                % (klass,href,tt,txt,)

    if admin_mode:
        if img_exist:
            show_btn = '<input type="submit" value="Rotate selection" />\n<input type="hidden" name="cur_web_dir" value="%s" />' % (cur_web_dir,)
        else:
            show_btn = ''
        txt_thumb = '''\
<form name="rot" method="GET">
  %s
  %s
</form>''' % (txt_thumb,show_btn)

    page['main'].append('''\
<div class="nav">
  %s
  <div class="clear">&nbsp;</div>
</div>''' % (txt_thumb,) )

    return page

def main(environ,time_count):
    page = dweb.dwsgi.DBlock()
    page.read_template(os.path.join(root,template_file))
    page['head'] = ''
    page['main'] = ''
    page['sbleft'] = ''

    #start view
    form = dweb.dwsgi.get_FieldStorage(environ)
    
    filename = ''
    nav = ''
    cmd_javascript = []
    if form.has_key("a"):#NOT ROOT
        nav = form["a"][0]
        if is_image(nav):   #VIEW MODE
            viewing = True
            filename = os.path.basename(nav)
            #ADMIN MODE: rotate image in _view and _thumb
            rot = ''
            for i in ['/_r90/','/_r180/','/_r270/','/_r360/']:
                if i in nav:
                    rot = '+' + i.strip('/_r').strip('/')
                    nav = path_join(nav.split(i))
                    break
            cur_web_dir = os.path.dirname(nav).strip('/')
            if rot: #CREATE NEW ROTATED IMG FROM ORIG
                #def create_scale_img(cwd,filename,rotate=0,force=False):
                create_scale_img(abs_dir(cur_web_dir),filename,rotate=rot,force=True)
                cmd_javascript.append('window.location="%s"' % (environ["HTTP_REFERER"].split('?')[0] + '?a=' + nav,))
        else:               #SHOW THUMBNAIL
            viewing = False
            cur_web_dir = nav
    else:               #ROOT
        viewing = False
        cur_web_dir = ''
    if form.has_key("cur_web_dir"):
        cur_web_dir = form["cur_web_dir"][0]
    if 'rot_' in [i[:4] for i in form.keys() if len(i) > 4]:
        rot_images = [j[0].split('/') for i,j in form.iteritems() if i[:4] == 'rot_']
        for filename,rotate in rot_images:
            create_scale_img(os.path.join(root,cur_web_dir),filename,rotate,force=True)
        cmd_javascript.append(get_win_loc(environ,'?a=%s' % (cur_web_dir,)))
    if admin_mode:
        create_img(cur_web_dir)

    if viewing: #VIEW MODE
        page = view_page(page,cur_web_dir,filename)
    else:   #NO VIEWING, BROWSE THUMBNAIL
        page = browse_page(page,cur_web_dir)
    page['head'].append(get_breadcrumb(nav))

    if cmd_javascript:
        page['main'].append('''\
<script type="text/javascript">
  %s
</script>
''' % (';\n'.join(cmd_javascript),) )

    page['main'].append( br + '<font class="footer">(%6.4f sec)</font>' % (time_count.all()))
    if admin_mode:
        page['main'].append( br + _debug(environ) )

    return page.content()
        
def application(environ, start_response):
    #current web root
    global root
    root = os.path.dirname(environ['SCRIPT_FILENAME'])
    if root not in sys.path:
        sys.path.insert(0,root)

    #pymodules path
    pymodules_dir = os.path.join(root,'.pymodules')
    if pymodules_dir not in sys.path:
        sys.path.insert(0,pymodules_dir)

    dirname = os.path.dirname(str(environ['SCRIPT_NAME']))

    #if this is hidden dir., assume admin_mode
    global admin_mode
    if dirname.split('/')[-1] == admin_url:
        admin_mode = True
    else:
        admin_mode = False

    #pymodules: dweb
    global dweb
    import dweb

    output = ''
    time_count = dweb.util.TimeIt()
    output += main(environ,time_count)

    status = '200 OK'
    response_headers = [('Content-type', 'text/html')]
    start_response(status, response_headers)
    return [output]

