import exceptions, body
import os, sys, traceback, shutil
import string
import re
import Image
import codecs
import functions
from node import Node
from functions import printTraceback, trim, xmlString, getYesNo
from PIL import Image

####################
#    class picture
####################
"""
A model of a picture which inherits from node class.
Opens picture and retrieves width and height
Can print its own index file and the link to it in the main index file
"""

class Picture(Node):
    def __init__(self, props=None, absfilename=None):
        Node.__init__(self)
        self.absfilename = absfilename
        self.width = 0 
        self.height = 0
        self.res_width = 0 
        self.thumb_width = 0
        self.format = None
        self.res_height = 0
        self.thumb_height = 0
        self.date = ""
        self.where = ""
        self.who = ""
        self.what = ""
        self.exif = None
        self.im = None
        self.width = None
        self.height = None
        self.format = None
        self.mode = None
        self.info = None
        self.camera = None
        self.highQuality = 0
        if props:
            self.res_width = props["size"]
            self.thumb_width = props["thumbsize"]
            self.camera = None #props["camerainfo"]     // future property
            self.highQuality = not props["faster"]
        self.getImage()


    def tostring(self):
        return "Filename: " + self.absfilename + "\n" + "Width:" +  str(self.width) + "\n" + "Height:" + str(self.height) + "\n" + "Resized width:" + str(self.res_width) + "\n" + "Resized height:" + str(self.res_height) +"\n"  

    def getAbsfilename(self):
        return self.absFilename

    def getWidth(self):
        return self.width

    def getResizedWidth(self):
        return self.res_width

    def getThumbWidth(self):
        return self.thumb_width

    def getHeight(self):
        return self.height

    def getResizedHeight(self):
        return self.res_height

    def getThumbHeight(self):
        return self.thumb_height

    def getDate(self):
        "Return date, if empty get it from EXIF data in picture"
        if self.date == "":
            self.getExifDate()
        return self.date

    def getWho(self):
        return self.who

    def getWhere(self):
        return self.where

    def getWhat(self):
        return self.what

    def setAbsfilename(self, absfilename):
        self.absfilename = absfilename

    def setWidth(self, width):
        if width is None:
            self.width = 0
        else:
            self.width = int(width)
        
    def setResizedWidth(self, res_width):
        if res_width is None:
            self.res_width = 0
        else:
            self.res_width = int(res_width)

    def setThumbWidth(self, thumb_width):
        if thumb_width is None:
            self.thumb_width = 0
        else:
            self.thumb_width = int(thumb_width)

    def setHeight(self, height):
        if height is None:
            self.height = 0
        else:
            self.height = int(height)

    def setResizedHeight(self, res_height):
        if res_height is None:
            self.res_height = 0
        else:
            self.res_height = int(res_height)

    def setThumbHeight(self, thumb_height):
        if thumb_height is None:
            self.thumb_height = 0
        else:
            self.thumb_height = int(thumb_height)

    def setDate(self, date):
        self.date = date

    def setWho(self, who):
        self.who = who

    def setWhere(self, where):
        self.where = where

    def setWhat(self, what):
        self.what = what

    def unload(self):
        """Unload picture from memory"""
        self.im = None

    def getExifDate(self):
        "Extract timestamp from EXIF data"
        try:
            self.date = self.exif[306].replace(":","-",2)   # date in format yyyy-MM-DD hh:mm:ss
        except:
            return

    def getExifCamera(self):
        "Extract camera from EXIF data"
        # see http://www.exif.org/Exif_2-1.PDF
        try:
            make = self.exif[271]
            model = self.exif[272]
            if make.split()[0] in model:
                result = model # make is in model name, so don't mention it twice
            else:
                result = make + ' ' + model
            t = self.exif[33434]    # shutter time
            d = self.exif[33437]    # diafragma
            focus = self.exif[37386]
            flash = getYesNo(self.exif[37385])
            ep = self.exif[34850]   # exposure program
            eps=['undefined (0)','manual','normal','aperture priority','shutter priority','max. depth','speed','portrait','landscape']
            if ep in range(len(eps)):
                ep = eps[ep]
            else:
                ep = str(ep)
            result = result + (" <BR>Exposure: 1/%d sec. F/%.1f")%(t[1]/t[0], float(d[0])/d[1])
            result = result + (" &nbsp;&nbsp;flash: %s &nbsp;&nbsp;focus %d mm. &nbsp;&nbsp;Exposure program: %s")%(flash, focus[0]/focus[1], ep)
        except:
            result = 'unknown'
        return result
    
    def getExifOrientation(self):
        orientation = self.exif[274]
        rotationOffsets = {3:180, 6:270, 8:90} # CW, upside-down, CCW
        return rotationOffsets.get(orientation, 0)
    
    def getSize(self):
        return (self.width, self.height)

    def getImage(self):
        "Return a PIL Image object of picture, set properties on self"
        try:
            if self.absfilename:
                if self.im is None:
                    self.im  = Image.open(open(self.absfilename, "rb"))

                    self.width = int(self.im.size[0])
                    self.height = int(self.im.size[1])
                    self.format = self.im.format
                    self.mode = self.im.mode

                    if self.format == "JPEG":
                        if self.highQuality:
                            self.im.info["quality"] = 100
                            self.im.info["optimize"] = 1
                        else:
                            self.im.info["quality"] = 1
                        self.im.info["progression"] = 1

                    self.info = self.im.info
                    # if we have PIL lib less than 1.1.4 _getexif() fails, trap it
                    try:
                        self.exif = self.im._getexif()
                        
                    except:
                        pass

        except:
            printTraceback()
        return self.im


    def calculateSize(self, requestedSize):
        """Return tuple describing (width,height) resized picture given a
           requested size. The requested size is the size of the
           longer edge"""
        _height = 0
        _width = 0
        try:
            if self.width > self.height:
                ratio = self.width * 1.0 / requestedSize
                _height = int(self.height / ratio)
                _width = requestedSize
            else:
                "If portrait - use width as height, must calculate width"
                ratio = self.height * 1.0 / requestedSize
                _height = requestedSize
                _width =  int(self.width / ratio)

            return(_width,_height)
        except:
            printTraceback()
        

    def getResizedPicture(self, sizeTuple):
        """Return a PIL Image instance, where size is
           given in supplied tuple (width, heigth) 
           Also check for orientation"""
        im = self.getImage()
        offsetDegree = self.getExifOrientation()
        if offsetDegree != 0:
            im = im.rotate(offsetDegree)
        if self.highQuality:
            return im.resize(sizeTuple,Image.ANTIALIAS)
        else:
            return im.resize(sizeTuple,Image.NEAREST)


    def putResized(self, destdirectory):
        "Put myself in destdirectory and resize to self.res_width"
        try:
            location = self.getLocation(destdirectory) 
            sizeTuple = self.calculateSize(self.res_width)
            self.getResizedPicture(sizeTuple).save(open(location,"wb"), self.format)
        except:
            printTraceback()


    def putThumbnail(self, destdirectory):
        "Put myself in destdirectory and resize to self.thumb_width"
        try:
            location = self.getLocation(destdirectory)
            sizeTuple = self.calculateSize(self.thumb_width)
            self.getResizedPicture(sizeTuple).save(open(location, "wb"), self.format)
        except:
            printTraceback()

            
    def putInDir(self, destdirectory, size):
        """Put myself resized to size in descdirectory. Size is the length of the
        longer side"""
        location = self.getLocation(destdirectory)
        sizeTuple =  self.calculateSize(size)
        self.getResizedPicture(sizeTuple).save(open(location, "wb"), self.format)

    def putFullsize(self, destdirectory):
        "Put self in destdirectory, no resizing"
        location = self.getLocation(destdirectory)
        shutil.copyfile(self.absfilename, location)


    def getLocation(self, destinationDir):
        "Construct directory location from given destinationDir and sourcefile tail"
        return os.path.join(destinationDir, os.path.split(self.absfilename)[1])

    

    def getNameNoExtension(self):
        "Return filename stripped for extension"
        filename = os.path.basename(self.absfilename)
        return  filename[0:filename.rfind(".")]

    def getTail(self):
        "Return filename stripped for extension"
        return  os.path.split(self.absfilename)[1]

        
    def getLinkHTML(self, fullsize=None,):
        "Return HTML for inclusion in gallery index file"
        (xthumb_width, xthumb_height) = self.calculateSize(self.thumb_width)
        html = []
        html.append("\n     <td><a href=\"" + functions.quoteUrl(self.getNameNoExtension()) + ".html\"" + ">")
        html.append("<img src=\"thumbnails/" + functions.quoteUrl(self.getTail())+  "\" height=\"" + str(xthumb_height) + "\" width=\"" + str(xthumb_width) + "\" alt=\"" + self.getTail() + "\"")
        html.append("></a>")
        if fullsize:
           html.append("<br><a href=\"")
           html.append("fullsize/%s" % functions.quoteUrl(self.getTail().strip()))
           html.append("\">Full size</a>")
        html.append("</td>")
        return "".join(html) 
    

    def getLinkHTMLForSinglePic(self, fullsize=None):
        """If a directory has only a single picture,
           resize it to 640 and center it"""
        html = []
        html.append("<td id=\"sidelinks\"><div></div></td>\n\n<td width=\"100 %\"><center><a href=\"" + functions.quoteUrl(self.getNameNoExtension()) + ".html\"" + ">")
        html.append("<img src=\"indexpic/" + functions.quoteUrl(self.getTail()) + "\"")
        html.append("</a>")
        html.append("</center></td>\n\n")
        html.append("<td></td>")
        return "".join(html) 
        

    
    def createPictureHTML(self, directory, stylesheet, fullsize, footer):
        "Create HTML file to display resized picture"
        html = []
        html.append("<html>\n  <head>\n    <title>\n      " + self.getTail())
        html.append("\n    </title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"" + stylesheet + "\">\n")
	html.append(r'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">')
	  
	html.append("</head>\n  <body>\n")

        html.append(self.navigationBar(fullsize))
        
        html.append("\n     <hr>\n     <table>\n     <tr>\n        <td>\n           <img src=\"resized/"
                    + functions.quoteUrl(self.getTail()) + "\">\n        </td>")
                 
        if self.height > self.width:
            # place date right of  picture,  after 30
            html.append("\n       <td width=30>\n       </td>\n       <td  valign=\"top\">")
            html.append(self.tagLabelContent())
            html.append("\n        </td>")
        else:
            # place date under picture
            html.append("\n      </tr>\n       <tr>\n        <td height=10>\n        </td>\n      </tr>\n      <tr>\n         <td>")
            html.append(self.tagLabelContent())
            html.append("\n         </td>") 
        html.append("\n       </tr>\n     </table>\n    <hr>")
        html.append(self.navigationBar(fullsize))
        html.append(footer.getHTML())

        raw = os.path.join(directory, self.getNameNoExtension()) + ".html"
        file = open(raw, "w")
        file.write("".join(html).encode('utf-8'))
        file.close()


    def navigationBar(self, fullsize):
        "Return navigation bar, only simple links at the moment"
        html = []
        if self.next !=  None:
            html.append("\n     <p>\n      [<a href=\"" + functions.quoteUrl(self.next.getNameNoExtension()) + ".html\">Next</a>]")
        if self.previous != None:
            html.append("\n      [<a href=\"" + functions.quoteUrl(self.previous.getNameNoExtension()) + ".html\">Previous</a>]" )
        if fullsize:
            html.append("\n      [<a href=\"fullsize/" + functions.quoteUrl(self.getTail()) + "\">Fullsize</a>]")
        html.append("\n      [<a href=\"index.html\">Gallery</a>]\n     </p>\n")
        return string.joinfields(html)



    def tagLabelContent(self):
        "Return picture descriptions"
        html = []
        html.append("\n          <B class=tag_label>Date:</B> " + self.getDate())
        if self.who:
            html.append("<BR>\n          <B class=tag_label>Who:</B> " + self.who)
        if  self.where:
            html.append("<BR>\n          <B class=tag_label>Where:</B> " + self.where)
        if self.what:
            html.append("<BR>\n          <B class=tag_label>What:</B> " + self.what)
        if self.camera:
            html.append("<BR>\n          <B class=tag_label>Camera:</B> " + self.getExifCamera())
        return string.joinfields(html)    

    

    def getXML(self, xml):
        "Return XML code for this picture"
        xml.append("\n            <picture>")
        xml.append("\n                <filename>" + xmlString(self.getTail()) + "</filename>")
        xml.append("\n                <width>" + str(self.width) + "</width>")
        xml.append("\n                <resized_width>" + str(self.res_width) + "</resized_width>")
        xml.append("\n                <thumb_width>" + str(self.thumb_width) + "</thumb_width>")
        xml.append("\n                <height>" + str(self.height) + "</height>")
        xml.append("\n                <resized_height>" + str(self.res_height) + "</resized_height>")
        xml.append("\n                <thumb_height>" + str(self.thumb_height) + "</thumb_height>")
        xml.append("\n                <date>" + xmlString(self.date) + "</date>")
        xml.append("\n                <who>" + xmlString(self.who) + "</who>")
        xml.append("\n                <where>" + xmlString(self.where) + "</where>")
        xml.append("\n                <what>" + xmlString(self.what) + "</what>")
        xml.append("\n                <camera>" + xmlString(self.getExifCamera()) + "</camera>")
        xml.append("\n            </picture>")
        return xml

    
        
