#!/usr/bin/env python
# Time-stamp: <getwhiteboard.py 2011-04-22 11:35:08 Mark Voorhies>
"""Script to copy whiteboard images from my camera and insert them
at the current point in the presentation."""

import dbus
from glob import glob
import os
import re
from subprocess import Popen, PIPE, check_call
import sys

basedir = "/home/mvoorhie/Projects/Courses/PracticalBioinformatics/python/"
imagedir = basedir + "whiteboard/"
#  presentation.tex for testing.  Since we've got all of the tex
#  in git, it will be safe to switch to the real presentation in practice.
presentation = basedir + "presentation.tex"

def get_page():
    """Return the current page being shown by konqueror
    (counting from 1)."""
    # Connect to the desktop bus for this session (KDE4/Gnome specific)
    # c.f. http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html
    bus = dbus.SessionBus()
    
    # Find the current konqueror session
    k = [i for i in bus.list_names()
         if(i.startswith("org.kde.konqueror"))]
    assert(len(k) > 0)
    if(len(k) > 1):
        sys.stderr.write("WARNING: multiple konqueror sessions!\n")
    konqueror = k[0]

    # Query okular (embedded pdf viewer) for current page
    okular = bus.get_object(konqueror, "/okular")
    return int(okular.currentPage())

def get_new_images(imagedir, old_images = []):
    """Download any images on the camera that are not in old_images
    and return a list of filenames."""
    old = frozenset(old_images)
    new = []
    gphoto_re = re.compile("^#(?P<n>[\d]+)[\s]+(?P<jpg>[\w]+\.JPG).*image/jpeg")
    for line in Popen(("gphoto2","--list-files"), stdout = PIPE).stdout:
         p = gphoto_re.search(line)
         if((p is not None) and (p.group("jpg") not in old)):
             new.append((p.group("n"), p.group("jpg")))

    if(len(new) > 0):
        # gphoto2 downloads to current directory, so make sure we're
        # where we want to be
        os.chdir(imagedir)
        check_call(("gphoto2","--get-file",",".join(i[0] for i in new)))

    return [i[1] for i in new]

def insert_images(images, presentation, page):
    # Buffer for modified presentation
    newcontent = ""
    fp = open(presentation)
    
    # Scan to insertion point
    
    pagecount = 0
    inpage = False
    # assuming in-line comments are not relevant for page count
    comment_re = re.compile("^[\s]*%")
    for line in fp:
        newcontent += line
        if(comment_re.search(line) is not None):
            continue
        elif(line.find("\\begin{frame}") > -1):
            pagecount += 1
            inpage = True
        elif(line.find("\\pause") > -1):
            pagecount += 1
        elif(line.find("\\end{frame}") > -1):
            inpage = False

        if((pagecount >= page) and (not inpage)):
            break
        
    else:
        raise ValueError, "Error locating insert point in file!"

    # Insert new content
    for image in images:
        newcontent += """
\\begin{frame}{Whiteboard Image}
   \\begin{center}
     \\includegraphics{whiteboard/%s}
   \\end{center}
\\end{frame}
        """ % image

    # concatenate rest of file
    for line in fp:
        newcontent += line

    # Generated new content without crashing -- go ahead and
    # write to disk
    fp.close()
    open(presentation,"w").write(newcontent)

def downsample(imagedir, old_images):
    """Use imagemagick to scale each image in old_images to a pre-defined size
    and return a list of the names of the new images.  Old images are assumed
    to have a ".JPG" suffix, and all filenames are relative to imagedir."""
    new_images = []
    for old in old_images:
        new = old.replace("JPG","jpg")
        check_call(("convert","-resize","800x600",imagedir+old,imagedir+new))
        new_images.append(new)
    return new_images
         
if(__name__ == "__main__"):
    # Get current point in presentation
    curpage = get_page()
    print curpage
    
    # Check images already on disk
    old_images = [i[i.rfind("/")+1:] for i in glob(imagedir+"*.JPG")]
    
    # Transfer any new images to laptop
    new_images = get_new_images(imagedir, old_images)

    if(len(new_images) > 0):
        # Downsample images for slides
        small_images = downsample(imagedir, new_images)

        # Insert slides into presentation
        insert_images(small_images, presentation, curpage)

        # Recompile presentation (two passes to get LaTeX references right)
        os.chdir(basedir)
        check_call(("pdflatex",presentation))
        check_call(("pdflatex",presentation))
