"""
Draws Canvas with Card
"""
#  Copyright (C) 2004  Henning Jacobs <henning@srcco.de>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  $Id: ContactViewWidget.py 93 2004-11-28 16:05:34Z henning $

from Tkinter import *
import vcard
import debug
import Preferences
from AbstractContactView import *
import IconImages
import broadcaster
import ToolTip

# Canvas Width and Height:
CANVASWD = 506
CANVASHT = 406
    
class ContactViewWidget(AbstractContactView, Frame):
    hide_fields = ["FormattedName", "DisplayName", "SortName", "Rev", "Photo", "Logo"]
    def __init__(self, master, **kws):
        self.savedialog = None
        self.canvas_items = []
        self._selectcommand = kws.get("selectcommand", None)
        AbstractContactView.__init__(self)
        Frame.__init__(self, master, class_="ContactView")
        self.__createWidgets()
        
    def bind_contact(self, contact):
        AbstractContactView.bind_contact(self, contact)
        self.rebindWidgets()
        
    def renderAddress(self, adr, realadrobj, x, y, font):
        # adr is a dictionary (Fieldname: Value)
        # realadrobj is a real contact.adr[n] Object
        id = self.canvas.create_text(
            x, y, font=font, anchor=NW, text="Address:")
        self.canvas_items.append(id)
        zeilen = [adr["POBox"],
            adr["Extended"],
            adr["Street"],
            " ".join(filter(None, [adr["PostalCode"], adr["City"]])),
            ", ".join(filter(None, [adr["Region"], adr["Country"]]))]
        adrright = 0; adrtop = y; adrheight = 0;    
        for zeile in filter(None, zeilen):
            id = self.canvas.create_text(
                100, y, font=font, anchor=NW, text=zeile, width=CANVASWD-110)
            self.bindCopyToClipboard(id)
            self.canvas_items.append(id)        
            self.makeLink(id, command=lambda x=realadrobj: self.composeLetter(x))
            x1, y1, x2, y2 = self.canvas.bbox(id)
            y += (y2 - y1) + 2
            adrright = max(adrright, x2)
            adrheight += (y2 - y1) +2
        image_x = adrright+8; image_y = adrtop + adrheight/2
        self.renderIcons(vcard.vC_adr_types,
            realadrobj.params.get("type"),
            image_x, image_y)
        return y    
        
    def renderIcons(self, typelist, set, x, y):
        "Render GIF-Icons specified in set (typelist defines the ordering)"
        for type in typelist:
            if type in set:
                try:
                    self.canvas_items.append(self.canvas.create_image(x, y, anchor=W,
                            image=IconImages.IconImages[type]))
                    x += 20
                except:
                    # Icons are not _that_ important..
                    print "renderIcons(): ERROR: Could not render icon '%s'" % (type,)

    def renderPhoto(self, imagedata, x, y):
        "draw photographic picture"
        msg = ""
        photoimage = None
        try:
            try:
                import ImageTk
            except:
                msg = "renderPhoto(): Could not import ImageTK - \n"
                msg += " You must install PIL (Python Imaging Library).\n"
            import base64
            photoimage = ImageTk.PhotoImage(data=base64.decodestring(imagedata))
            self.canvas_items.append(self.canvas.create_image(x, y, anchor=NE, image=photoimage))
        except:
            msg += "renderPhoto(): Could not render PhotoImage."
            broadcaster.Broadcast('Notification', 'Error', {'message':msg})
        return photoimage
    
    def rebindWidgets(self):
        "Redraw our Canvas"
        normalfont = ("Helvetica", -12)
        # delete all previous canvas items
        for x in self.canvas_items:
            self.canvas.delete(x)
        del self.canvas_items[:]
        y = 38
        # first, draw picture in the background
        if not self._contact.photo.is_empty():
            self._photoimage = self.renderPhoto(self._contact.photo.get(), CANVASWD-10, y)
            if self._photoimage:
                y += self._photoimage.height() + 6
        # draw company logo
        if not self._contact.logo.is_empty():
            self._logoimage = self.renderPhoto(self._contact.logo.get(), CANVASWD-10, y)
        # card title
        self.canvas.itemconfig(self.fn, text=self._contact.fn.get())
        # revision date
        self.canvas.itemconfig(self.rev, text="Rev: %s" % self._contact.rev.get())
        y = 40
        previous_fieldname = ""
        addresses = []
        for fieldname in vcard.FIELDNAMES:
            value = self._contact.getFieldValue(fieldname)
            valuecount = 0
            while value:
                valuecount += 1
                font = normalfont
                if fieldname in vcard.ADRFIELDS:
                    # Collect all necessary address fields:
                    if len(addresses) < valuecount: addresses.append({})
                    adr = addresses[valuecount-1]
                    adr[fieldname] = value.get()
                    if len(adr) == len(vcard.ADRFIELDS):
                        # Now draw our complete address at once:
                        y = self.renderAddress(adr, self._contact.adr[valuecount-1], 10, y, font)
                elif not value.is_empty() and fieldname not in self.hide_fields:
                    if previous_fieldname != fieldname:
                        self.canvas_items.append(self.canvas.create_text(
                            10, y, font=normalfont, anchor=NW, text=fieldname+":"))
                    id = self.canvas.create_text(
                        100, y, font=font, anchor=NW, text=value.get(), width=CANVASWD-110)
                    self.bindCopyToClipboard(id)
                    self.canvas_items.append(id)        
                    if fieldname == "Email":
                        self.makeLink(id, command=lambda x=value.get(): self.sendEMail(x))
                    elif fieldname == "URL":
                        self.makeLink(id, command=lambda x=value.get(): self.viewURL(x))
                    elif fieldname == "Phone" and value.params.get("type").contains("fax"):
                        self.makeLink(id, command=lambda name=self._contact.fn.get(),number=value.get(): self.sendFax(name, number))
                    x1, y1, x2, y2 = self.canvas.bbox(id)
                    image_x = x2+8; image_y = y+(y2-y1)/2
                    if fieldname == "Phone":
                        self.renderIcons(vcard.vC_tel_types, value.params.get("type"), image_x, image_y)
                    elif fieldname == "Email":
                        self.renderIcons(vcard.vC_email_types, value.params.get("type"), image_x, image_y)
                    y += (y2 - y1) + 2
                    previous_fieldname = fieldname
                value = self._contact.getFieldValue(fieldname)
             
    def makeLink(self, canvas_id, command):
        # Special handling of hypertext links:
        hyperfont = ("Helvetica", -12, "underline")
        def MouseOver(event, canvas=self.canvas):
            canvas["cursor"] = "hand2"
        def MouseOut(event, canvas=self.canvas):
            canvas["cursor"] = ""
        def MouseClick(event, command=command):
            command()
        self.canvas.itemconfigure(canvas_id, font=hyperfont)
        self.canvas.tag_bind(canvas_id, "<Enter>", MouseOver)
        self.canvas.tag_bind(canvas_id, "<Leave>", MouseOut)
        self.canvas.tag_bind(canvas_id, "<1>", MouseClick)

    def bindCopyToClipboard(self, canvas_id):
        def copyToClipboard(event, canvas=self.canvas, id=canvas_id):
            text = self.canvas.itemcget(id, "text")
            canvas.clipboard_clear()
            canvas.clipboard_append(text)
        self.canvas.tag_bind(canvas_id, "<3>", copyToClipboard)

    def composeLetter(self, adr):
        broadcaster.Broadcast('Command', 'Compose Letter',
            data={'card':self._contact, 'adr':adr})
                        
    def sendEMail(self, recipient):
        "Start the preferred Mail Client and compose"
        import mailtowrapper
        recipient = "%s <%s>" % (self._contact.fn.get(), recipient)
        mailtowrapper.mailto(recipient)
        
    def sendFax(self, recipient, telnumber):
        "Send a Fax"
        import faxtowrapper
        faxtowrapper.faxto(recipient, telnumber)
                
    def viewURL(self, url):
        "Fire up the preferred browser and go to url"
        browserprog = Preferences.get("client.url_viewer").split(' ')
        if browserprog[0]:
            import os
            os.spawnvp(os.P_NOWAIT, browserprog[0], browserprog + [url])
        else:    
            import webbrowser
            webbrowser.open(url)
    
    def asksavefile(self):
        import os
        import tkFileDialog
        try:
            dir = os.getcwd()
        except os.error:
            dir = ""
        if not self.savedialog:
            filetypes = [
                ("Encapsulated PostScript", "*.eps *.ps"),
                ("All files", "*"),
                ]
            self.savedialog = tkFileDialog.SaveAs(master=self,
                filetypes=filetypes)
        root, ext = os.path.splitext(
            self.savedialog.show(initialdir=dir))
        if root and not ext: ext = ".eps"
        return root+ext
        
    def save_as_postscript(self):
        filename = self.asksavefile()
        if filename:
            self.canvas.postscript(file=filename)
        return "break"

    def __createWidgets(self):
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.canvas = Canvas(self, width=CANVASWD, height=CANVASHT,
            borderwidth=0,
            highlightthickness=0)
        if self._selectcommand:
            def selectcommand(event, self=self):
                self._selectcommand(self.cardhandle())
            self.canvas.bind("<Double-1>", selectcommand)
        self.canvas.grid()
        ToolTip.ToolTip(self.canvas, "Click Right Mouse-Button to copy text to clipboard")
        
        # 'Export to EPS' is not very useful, so hide the button:
        # self.btnSavePostscript = Button(self,
        #       text="Save as Encapsulated PostScript (.eps)",
        #       command=self.save_as_postscript)
        # self.btnSavePostscript.grid(sticky=S+E)
        
        # Draw card shadow:
        self.canvas.create_rectangle(10, 10, CANVASWD, CANVASHT, outline='', fill='#666666')
        # Draw card paper:
        self.canvas.create_rectangle(2, 2, CANVASWD-6, CANVASHT-6, width=1, fill='white')
        # Draw head box (here goes the card title):
        self.canvas.create_rectangle(2, 2, CANVASWD-6, 33, width=1, fill='#ffbb88')
        self.fn = self.canvas.create_text(10,4,
            font=("Helvetica",-24,"bold"),anchor=NW)
        self.bindCopyToClipboard(self.fn)
        self.rev = self.canvas.create_text(CANVASWD-10,CANVASHT-6,
            font=("Helvetica",-10),anchor=SE, fill="#888888")
        self.bindCopyToClipboard(self.rev)
    
