#!/usr/bin/env python
# -*- coding: ISO-8859-15 -*-
#
# pdf2swf.py
# graphical user interface for pdf2swf
#
# Part of the swftools package.
# 
# Copyright (c) 2008,2009 Matthias Kramm <kramm@quiss.org> 
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


import sys
import wx
import os
sys.path+=["../lib/python"]
import gfx
import images
import stat

basedir = os.getcwd()

gfx.verbose(3)

#try:
#    gfx.setparameter("wxwindowparams", "1")
#except:
#    gfx.setoption("wxwindowparams", "1")

class StaticData:
    def __init__(self):
        self.simpleviewer_bitmap = wx.BitmapFromImage(wx.ImageFromData(images.simpleviewer_width,images.simpleviewer_height,images.simpleviewer_data))
        self.raw_bitmap = wx.BitmapFromImage(wx.ImageFromData(images.raw_width,images.raw_height,images.raw_data))
        self.motionpaper_bitmap = wx.BitmapFromImage(wx.ImageFromData(images.motionpaper_width,images.motionpaper_height,images.motionpaper_data))
        self.rfxview_bitmap = wx.BitmapFromImage(wx.ImageFromData(images.rfxview_width,images.rfxview_height,images.rfxview_data))
staticdata = None

HTMLTEMPLATE = """<html>
<body style="padding: 0px; margin: 0px">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
        width="%(width)s"
        height="%(height)s"
        codebase="http://active.macromedia.com/flash5/cabs/swflash.cab#version=%(version)d,0,0,0">
        <param name="MOVIE" value="%(swffilename)s">
        <param name="PLAY" value="true">
        <param name="LOOP" value="true">
        <param name="QUALITY" value="high">
        <param name="FLASHVARS" value="%(flashvars)s">
          <embed src="%(swffilename)s" width="%(width)s" height="%(height)s"
                 play="true" ALIGN="" loop="true" quality="high"
                 type="application/x-shockwave-flash"
                 flashvars="%(flashvars)s"
                 pluginspage="http://www.macromedia.com/go/getflashplayer">
          </embed>
</object>
</body>
</html>
"""

def error(msg):
    dlg = wx.MessageDialog(None, msg, "Error", style=wx.OK, pos=wx.DefaultPosition)
    dlg.ShowModal()
    dlg.Destroy()

def savefilestatus(msg):
    dlg = wx.MessageDialog(None, msg, "Save file status", style=wx.OK, pos=wx.DefaultPosition)
    dlg.ShowModal()
    dlg.Destroy()

def swfcombine(params):
    exe = "swfcombine"
    if os.path.sep == '/':
        locations = [os.path.join(basedir, "swfcombine"), 
                     "/usr/local/bin/swfcombine",
                     "/usr/bin/swfcombine"
                    ]
    else:
        locations = [os.path.join(basedir, "swfcombine.exe"), 
                     "c:\\swftools\\swfcombine.exe"]
        params = ['"'+p+'"' for p in params]

    for e in locations:
        if os.path.isfile(e):
            exe = e
            break

    if hasattr(os,"spawnv"):
        print "spawnv",exe,params
        ret = -1
        try:
            ret = os.spawnv(os.P_WAIT, exe, ["swfcombine"]+params)
        except:
            ret = -1
        if not ret:
            return

    cmd = '"' + exe + '"' + " " + (" ".join(params))
    print "system",cmd
    ret = os.system(cmd)
    if ret&0xff00:
        error("Couldn't execute swfcombine.exe- error code "+str(ret))

ICON_SIZE = 64

EVENT_PAGE_CHANGE = 1
EVENT_FILE_CHANGE = 2
EVENT_STATUS_TEXT = 4

class ProgressFrame(wx.Dialog):
    def __init__(self, parent, message=""):
        wx.Dialog.__init__(self, parent, -1, "Progress", size=(350, 150))
        panel = wx.Panel(self, -1)
        self.count = 0
        
        self.msg = wx.StaticText(panel, -1, message, (20,25))
        self.gauge = wx.Gauge(panel, -1, 100, (20, 50), (250, 25))

        self.gauge.SetBezelFace(3)
        self.gauge.SetShadowWidth(3)

        self.Bind(wx.EVT_WINDOW_DESTROY, self.close, id=wx.ID_CLOSE)

    def setProgress(self, num):
        self.gauge.SetValue(int(num))

    def close(self, event):
        print "close"


def swapextension(filename,newext):
    basename,ext = os.path.splitext(filename)
    return basename + "." + newext

def has_different_size_pages(doc):
    width,height = 0,0
    for i in range(1,doc.pages+1):
        page = doc.getPage(i)
        if i==1:
            width,height = page.width,page.height
        else:
            if abs(width-page.width)>2 or \
               abs(height-page.height)>2:
                   return 1
    return 0


options = []
gfx_options = {}

class Option:
    def __init__(self, parameter, text, options, default, mapping=None):
        self.parameter = parameter
        self.text = text
        self.options = options
        self.default = default
        self.mapping = mapping
        self.control = None
        self.enabled = 1
        self.register()

    def generateControl(self, panel):
        if type(self.options) == type((0,)):
            control = wx.Choice(panel, -1, choices=self.options)
            control.SetSelection(self.default)
        elif self.options == "slider":
            control = wx.Slider(panel, -1, self.default, 0, 100, size=(100, -1), style=wx.SL_HORIZONTAL|wx.SL_LABELS|wx.SL_TOP)
        elif self.options == "spinner":
            control = wx.SpinCtrl(panel, -1, str(self.default))
        else:
            control = wx.Choice(panel, -1, choices=["broken"])
            control.SetSelection(0)

        self.control = control
        return self.control

    def getSettings(self):
        value = ""
        if type(self.options) == type((0,)):
            value = self.options[self.control.GetCurrentSelection()]
            if self.mapping and value in self.mapping:
                value = str(self.mapping[value])
            if value == "yes": 
                value = "1"
            elif value == "no":
                value = "0"
            return {self.parameter:value}
        elif self.options == "slider" or self.options == "spinner":
            value = str(self.control.GetValue())
            return {self.parameter:value}

    def register(self):
        global options
        options += [self]

class Option2(Option):

    def __init__(self, parameter, text, options, default, mapping=None):
        Option.__init__(self, parameter, text, options, default, mapping)
        self.enabled = 0

    def generateControl(self, panel):
        p = wx.Panel(panel, -1)
        #p.SetOwnBackgroundColour('#ff0000')
        h = wx.BoxSizer(wx.HORIZONTAL)
        control = wx.Choice(p, -1, choices=self.options)
        control.SetSelection(self.default)
        text = wx.StaticText(p, -1, self.text)
        h.Add(text,1,wx.EXPAND|wx.ALIGN_LEFT|wx.TOP, 5)
        h.Add(control,1,wx.EXPAND|wx.ALIGN_RIGHT|wx.ALIGN_TOP)
        self.control = control
        if self.enabled:
            control.Enable()
        else:
            control.Disable()
        p.SetSizer(h)
        p.Fit()
        return p 
    
    def Disable(self):
        self.enabled=0
        if self.control:
            self.control.Disable()

    def Enable(self):
        self.enabled=1
        if self.control:
            self.control.Enable()
    
    def getSettings(self):
        if not self.enabled:
            return {}
        return Option.getSettings(self)

class ChooseAndText(Option):
    def __init__(self, parameter, text, options, default, editselection, textvalue=""):
        Option.__init__(self, parameter, text, options, default)
        self.editselection = editselection
        self.selection = default
        self.textvalue = textvalue
        self.enabled = 0
        self.choice = None

    def generateControl(self, panel):
        p = wx.Panel(panel, -1)
        h = wx.BoxSizer(wx.HORIZONTAL)
        control = wx.Choice(p, -1, choices=self.options)
        p.Bind(wx.EVT_CHOICE, self.OnChoice, control)
        control.SetSelection(self.default)
        text = wx.StaticText(p, -1, self.text)
        if self.selection == self.editselection:
            edittext = wx.TextCtrl(p, -1, self.textvalue)
            self.textvalue = ""
        else:
            edittext = wx.TextCtrl(p, -1, "")
            edittext.Disable()
        p.Bind(wx.EVT_TEXT, self.OnText, edittext)
        h.Add(text,1,wx.EXPAND|wx.ALIGN_LEFT|wx.TOP, 5)
        h.Add(control,1,wx.EXPAND|wx.ALIGN_RIGHT)
        h.Add(edittext,1,wx.EXPAND|wx.ALIGN_RIGHT)
        self.choice = control
        self.edittext = edittext
        if self.enabled:
            control.Enable()
        else:
            control.Disable()
        p.SetSizer(h)
        p.Fit()
        return p 

    def OnText(self, event):
        text = self.edittext.GetValue()
        text2 = "".join(c for c in text if c.isdigit())
        if text2!=text:
            self.edittext.SetValue(text2)

    def OnChoice(self, event):
        self.selection = self.choice.GetCurrentSelection()
        if self.selection != self.editselection:
            if not self.textvalue and self.edittext.GetValue():
                self.textvalue = self.edittext.GetValue()
            self.edittext.SetValue("")
            self.edittext.Disable()
        else:
            if self.textvalue and not self.edittext.GetValue():
                self.edittext.SetValue(self.textvalue)
                self.textvalue = ""
            self.edittext.Enable()
    
    def Disable(self):
        self.enabled=0
        if not self.choice:
            return
        self.choice.Disable()
        self.edittext.Disable()

    def Enable(self):
        self.enabled=1
        if not self.choice:
            return
        self.choice.Enable()
        if self.choice.GetCurrentSelection() == self.editselection:
            if self.textvalue and not self.edittext.GetValue():
                self.edittext.SetValue(self.textvalue)
                self.textvalue = ""
            self.edittext.Enable()
        else:
            self.edittext.Disable()
    
    def getSettings(self):
        if not self.enabled:
            return {}
        if self.choice.GetCurrentSelection() != self.editselection:
            value = self.options[self.choice.GetCurrentSelection()]
        else:
            value = self.edittext.GetValue().strip()
        return {self.parameter:value}

class TextOption:
    def __init__(self, parameter, label, default=""):
        self.parameter = parameter
        self.label = label
        self.default = default
        self.register()

    def generateControl(self, panel):
        v = wx.BoxSizer(wx.VERTICAL)
        self.control = wx.TextCtrl(panel, -1, self.default, size=(250, -1))
        self.control.Fit()
        return self.control

    def getSettings(self):
        settings = {}
        for items in self.control.GetValue().split(" "):
            if "=" in items:
                l = items.split("=")
                if len(l) == 2:
                    settings[l[0]] = l[1]
        return settings

    def register(self):
        global options
        options += [self]

class RadioOption(Option):
    def __init__(self, text, options):
        self.text = text
        self.options = options
        self.selected = "==nothing=="
        self.radios = []
        self.register()
        
    def generateControl(self, panel):
        control = wx.Panel(panel, -1)
        vsplit = wx.BoxSizer(wx.VERTICAL)
        for i in range(len(self.options)/2):
            text = self.options[i*2]
            if i == 0:
                c = wx.RadioButton(control, -1, text, style=wx.RB_GROUP)
            else:
                c = wx.RadioButton(control, -1, text)
            control.Bind(wx.EVT_RADIOBUTTON, self.OnRadio, c)
            self.radios += [c]
            vsplit.Add(c)
        control.SetSizer(vsplit)
        control.Fit()
        self.control = control
        return control

    def OnRadio(self, event):
        self.selected = event.GetEventObject().GetLabel()

    def getSettings(self):
        for i in range(len(self.options)/2):
            if self.options[i*2] == self.selected:
                return self.options[i*2+1]
        return self.options[1]

class BitmapWindow(wx.Window):
    def __init__(self, parent, image):
        wx.Window.__init__(self, parent, -1)
        self.image = image
        self.SetMinSize((image.GetWidth()+2, image.GetHeight()+2))
        self.SetMaxSize((image.GetWidth()+2, image.GetHeight()+2))
        self.SetSize((image.GetWidth()+2, image.GetHeight()+2))
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Update()
    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        self.Draw(dc)
    def Draw(self,dc=None):
        if not dc:
            dc = wx.ClientDC(self)
        dc.DrawRectangleRect((0, 0, self.image.GetWidth()+2, self.image.GetHeight()+2))
        dc.DrawBitmap(self.image, 1, 1, False)

class ImageRadioOption(Option):
    def __init__(self, text, options):
        self.text = text
        self.options = options
        self.selected = "==nothing=="
        self.radios = []
        self.register()
        self.ids = []
        
    def generateControl(self, panel):
        control = wx.Panel(panel, -1)
        vsplit = wx.BoxSizer(wx.VERTICAL)
        first = 1
        for image,text,params,selected,extraoptions in self.options:
            hsplit = wx.BoxSizer(wx.HORIZONTAL)

            v = wx.BoxSizer(wx.VERTICAL)

            name,text = text.split("- ")

            c = wx.CheckBox(control, -1, name)
            control.Bind(wx.EVT_CHECKBOX, self.OnRadio, c)

            # radio buttons crash windows when clicked on- even without event bindings.
            # This is caused by the subpanel which is created for extra options
            # (I tried this with a empty Panel(), and even that crashed)
            #if first:
            #    c = wx.RadioButton(control, -1, name, style=wx.RB_GROUP)
            #else:
            #    c = wx.RadioButton(control, -1, name)
            #control.Bind(wx.EVT_RADIOBUTTON, self.OnRadio, c)

            self.ids += [c.GetId()]

            first = 0

            if "disable" in text:
                c.Enable(False)
            if selected:
                self.selected = c.GetId()
                c.SetValue(True)
            else:
                c.SetValue(False)
            self.radios += [c]

            bitmap = BitmapWindow(control, image)
            t = wx.StaticText(control, -1, text, size=(400,50))
            
            v.Add(c, 0, wx.EXPAND)
            v.Add(t, 0, wx.EXPAND|wx.LEFT, 20)
           
            for o in extraoptions:
                cx = o.generateControl(control)
                if selected:
                    o.Enable()
                else:
                    o.Disable()
                v.Add(cx, 0, wx.EXPAND|wx.LEFT, 20)
            
            v.SetMinSize((330,170))
            
            hsplit.Add(bitmap, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_TOP, 5)
            hsplit.Add(v, 0, wx.EXPAND)
            vsplit.Add(hsplit, 0, wx.EXPAND)

        control.SetSizer(vsplit)
        control.Fit()
        self.control = control
        return vsplit

    def OnRadio(self, event):
        self.selected = event.GetEventObject().GetId()
        for c in self.radios:
            if c.GetId() == self.selected:
                c.SetValue(1)
            else:
                c.SetValue(0)
        i = 0
        for image,text,params,selected,extraoptions in self.options:
            if self.ids[i] == self.selected:
                for xo in extraoptions:
                    xo.Enable()
                pass
            else:
                for xo in extraoptions:
                    xo.Disable()
                pass
            i = i + 1
        event.ResumePropagation(0)

    def getSettings(self):
        i = 0
        for image,text,params,s,extraoptions in self.options:
            id = self.ids[i]
            i = i + 1
            if id == self.selected:
                return params
        return {}


class OptionFrame(wx.Dialog):

    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, -1, "Options")

        #self.nb = wx.Notebook(self, -1)#, wx.Point(0,0), wx.Size(0,0), wxNB_FIXEDWIDTH)
        self.nb = wx.Notebook(self, -1)

        self.needreload = 0
        
        options0 = [RadioOption('Rendering mode', 
                        ["Convert polygons to polygons and fonts to fonts", {},
                         "Convert fonts to fonts, everything else to bitmaps", {"poly2bitmap":"1"},
                         "Convert everthing to bitmaps", {"poly2bitmap":"1", "bitmapfonts":"1"}
                        ])]

        mp_options = []
        sv_options = [Option2('flashversion', 'Flash version:', ('4','5','6','7','8'), 2),
                      Option2('transparent', 'Make SWF file transparent:', ('no','yes'), 0),
                     ]

        raw_options = [Option2('flashversion', 'Flash version:', ('4','5','6','7','8','9'), 2),
                       Option2('insertstop', 'Insert stop after each frame:', ('no','yes'), 0),
                       Option2('transparent', 'Make SWF file transparent:', ('no','yes'), 0),
                      ]
        rfxview_options = [ChooseAndText('rfxwidth', 'Width:', ('same as PDF','fullscreen','custom'),1,2,"600"),
                           ChooseAndText('rfxheight', 'Height:', ('same as PDF','fullscreen','custom'),1,2,"800"),
                           Option2('rfxzoomtype', 'Initial zoom level:', ('Original resolution','Show all','Maximum width/height'),2),
                          ]

        options4 = [ImageRadioOption('Select Paging GUI', 
                        [(staticdata.raw_bitmap, "No Viewer- The SWF will be in \"raw\" format, with each page a seperate frame. Use this if you want to add a viewer yourself afterwards.", {}, 0, raw_options),
                         (staticdata.simpleviewer_bitmap, "SimpleViewer- A tiny viewer, which attaches directly to the SWF, and provides small previous/next buttons in the upper left corner", {"simpleviewer":"1", "insertstop":"1"}, 0, sv_options),
                         (staticdata.rfxview_bitmap, "rfxView- A more sophisticated viewer with zooming and scrolling.", {"rfxview":"1", "flashversion":"8"}, 1, rfxview_options),
                         #(staticdata.motionpaper_bitmap, "MotionPaper- A highly sophisticated viewer with page flipping. (disabled in this evaluation version)", {}, 0, mp_options),
                         #(staticdata.motionpaper_bitmap, "Your advertisement here- Are you are company who developed a viewer for pdf2swf, or who offers commercial PDF hosting service? Place your advertisement or demo viewer here, or allow pdf2swf to upload SWFs directly to your site! contact sales@swftools.org for details.", {}, 0, mp_options),
                        ])]

        options1 = [Option('zoom', 'Resolution (in dpi):', "spinner", 72),
                    Option('fontquality', 'Font quality:', "slider", 20),
                    Option('storeallcharacters', 'Insert full fonts in SWF file:', ('no','yes'), 0),
                    Option('splinequality', 'Polygon quality:', "slider", 100),
                    Option('jpegquality', 'JPEG quality:', "slider", 75),
                    Option('jpegsubpixels', 'JPEG image resolution:', ('same as in PDF', '1x', '2x', '4x'), 0, {"same as in PDF": 0, "1x": 1, "2x": 2, "3x": 3}),
                    Option('ppmsubpixels', 'non-JPEG image resolution:', ('same as in PDF', '1x', '2x', '4x'), 0, {"same as in PDF": 0, "1x": 1, "2x": 2, "3x": 3}),
                   ]
        
        
        options3 = [TextOption('_additional_', 'Additional options')]

        panel1 = [('Rendering options', options0,''),
                  ('Quality',options1,'v')]
        panel3 = [('Select paging GUI', options4,'')]
        panel4 = [('Additional options', options3,'')]

        panels = [('Quality', panel1),
                  ('Viewer', panel3),
                  ('Advanced', panel4)]

        for name,poptions in panels:
            panel = wx.Panel(self.nb, -1)
            self.nb.AddPage(panel, name)
        
            vsplit = wx.BoxSizer(wx.VERTICAL)
      
            for name,options,align in poptions:
                optiongroup = wx.StaticBox(panel, -1, name)
                optiongroupsizer= wx.StaticBoxSizer(optiongroup, wx.VERTICAL)
                optiongroup.SetSizer(optiongroupsizer)

                if align == 'v':
                    grid = wx.GridSizer(rows=len(options), cols=2, hgap=3, vgap=3)
                    optiongroupsizer.Add(grid, 1, wx.EXPAND, 0)
                else:
                    grid = wx.GridSizer(rows=len(options), cols=1, hgap=3, vgap=3)
                    optiongroupsizer.Add(grid, 1, wx.EXPAND, 0)

                for option in options:
                    if align=='v':
                        t = wx.StaticText(panel, -1, option.text)
                        grid.Add(t, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
                    optionbox = option.generateControl(panel)
                    grid.Add(optionbox, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)

                vsplit.Add(optiongroupsizer, 0, wx.EXPAND, 0)

            #hs = wx.BoxSizer(wx.HORIZONTAL)
            #hs.Add(gobutton, 0, wx.ALIGN_CENTER, 0)
            gobutton = wx.Button(panel, -1, "Apply")
            self.Bind(wx.EVT_BUTTON, self.Apply, gobutton)

            vsplit.Add(gobutton, 0, wx.ALIGN_CENTER|wx.ALL, 0)
            
            panel.SetSizer(vsplit)
            panel.Fit()

        self.nb.Fit()

        self.Fit()
        

    def updateOptions(self):
        global options,gfx_options
        a = []

        # FIXME: we clear *our* options- but gfx will still have
        #        stored the old ones. Critical for options in the "imageradio" section.
        gfx_options.clear()
        i = 0
        print "----- options ------"
        for option in options:
            for k,v in option.getSettings().items():
                gfx_options[k] = v
                gfx.setparameter(k,v)
                print k,v
            i = i + 1

        # TODO: filter out "global" options, and do this only if
        # pdf layer is affected
    
    def Apply(self, event):
        self.updateOptions()
        self.Hide()
        self.needreload = 1


class State:
    def __init__(self):
        self.pdf = None
        self.page = None
        self.pagenr = 1
        self.pagebitmap = None
        self.bitmap_width = 0
        self.bitmap_height = 0
        self.bitmap_page = 0
        self.filename = None
        self.status_text = None
        self.lastsavefile = "output.swf"
        self.lasthtmlfile = "index.html"

        self.listeners = []

    def onEvent(self,event_type, function):
        self.listeners += [(event_type,function)]
    def loadPDF(self,filename):
        self.filename = filename
        self.lastsavefile = swapextension(filename,"swf")
        self.lasthtmlfile = swapextension(filename,"html")

        self.pdf = gfx.open("pdf",filename)
        if(has_different_size_pages(self.pdf)):
            # just let the user know- for now, we can't handle this properly
            dlg = wx.MessageDialog(app.frame, """In this PDF, width or height are not the same for each page. This might cause problems if you export pages of different dimensions into the same SWF file.""", "Notice", style=wx.OK, pos=wx.DefaultPosition)
            dlg.ShowModal()
            dlg.Destroy()

        self.changePage(1)

        for type,f in self.listeners:
            if type&EVENT_PAGE_CHANGE or type&EVENT_FILE_CHANGE:
                f()
        self.setStatus("File loaded successfully.")

    def saveSWF(self, filename, progress, pages=None, html=0):
        if html:
            basename,ext = os.path.splitext(filename)
            if not ext:
                html = basename + ".html"
                filename = basename + ".swf"
            elif ext.lower() != ".swf":
                html = filename
                filename = basename + ".swf"
            else:
                html = basename + ".html"
                filename = filename

        steps = 100.0 / (self.pdf.pages*2 + 3)
        pos = [0]
        
        self.lastsavefile = filename
        if html:
            self.lasthtmlfile = html

        swf = gfx.SWF()
        for k,v in gfx_options.items():
            swf.setparameter(k,v)
        if pages is None:
            pages = range(1,self.pdf.pages+1)
        pdfwidth,pdfheight=0,0
        for pagenr in pages:
            page = self.pdf.getPage(pagenr)
            pdfwidth = page.width
            pdfheight = page.height
            swf.startpage(page.width, page.height)
            page.render(swf)
            swf.endpage()
        swf.save(filename)
        if not os.path.isfile(filename):
            error("Couldn't create file "+filename)

        if gfx_options.get("rfxview",None):
            rfxview = os.path.join(basedir, "rfxview.swf")
            if not os.path.isfile(rfxview):
                error("File rfxview.swf not found in working directory")
            else:
                size1 = os.stat(filename)[stat.ST_SIZE]
                swfcombine([rfxview,"viewport="+filename,"-o",filename])
                size2 = os.stat(filename)[stat.ST_SIZE]
                if size1 == size2:
                    error("Couldn't add viewer to file "+filename)
        
        if html:
            version = int(gfx_options.get("flashversion", "8"))
            swf = gfx.open("swf", filename)
            page1 = swf.getPage(1)

            width,height = str(page1.width),str(page1.height)


            w = gfx_options.get("rfxwidth","")
            if w == "fullscreen":    width = "100%"
            elif w == "same as PDF": width = pdfwidth+40
            elif w.isdigit():        width = w
            else:                    width = pdfwidth
            
            h = gfx_options.get("rfxheight","")
            if h == "fullscreen":    height = "100%"
            elif h == "same as PDF": height = pdfheight+70
            elif h.isdigit():        height = h
            else:                    height = pdfwidth

            flashvars = ""
            zoomtype = gfx_options.get("rfxzoomtype","")
            if zoomtype=="Original resolution":
                flashvars = "zoomtype=1"
            elif zoomtype=="Show all":
                flashvars = "zoomtype=2"
            elif zoomtype=="Maximum width/height":
                flashvars = "zoomtype=3"

            swffilename = os.path.basename(filename)
            fi = open(html, "wb")
            fi.write(HTMLTEMPLATE % locals())
            fi.close()


    def changePage(self,page):
        self.pagenr = page
        self.page = self.pdf.getPage(self.pagenr)
        for type,f in self.listeners:
            if type&EVENT_PAGE_CHANGE:
                f()

    def getPageIcon(self,pagenr):
        page = self.pdf.getPage(pagenr)
        return wx.BitmapFromImage(wx.ImageFromData(ICON_SIZE,ICON_SIZE,page.asImage(ICON_SIZE,ICON_SIZE)))
        #return wx.BitmapFromImage(wx.ImageFromData(8,8,"0"*(64*3)))

    def getPageImage(self, width, height):
        if self.bitmap_width == width and self.bitmap_height == height and self.bitmap_page == self.pagenr:
            return self.pagebitmap
        else:
            self.bitmap_width = width
            self.bitmap_height = height
            self.bitmap_page = self.pagenr
            self.pagebitmap = wx.BitmapFromImage(wx.ImageFromData(width,height,self.page.asImage(width,height)))
            #self.pagebitmap = wx.BitmapFromImage(wx.ImageFromData(8,8,"0"*(64*3)))
            return self.pagebitmap

    def setStatus(self,text):
        self.status_text = text
        for type,f in self.listeners:
            if type&EVENT_STATUS_TEXT:
                f()

state = State()

class PageListWidget(wx.ListCtrl):
    def __init__(self,parent):
        wx.ListCtrl.__init__(self,parent,style=wx.LC_ICON|wx.LC_AUTOARRANGE)
        #self.SetMinSize((ICON_SIZE+8,-1))
        #self.SetMaxSize((ICON_SIZE+8,-1))
        #self.SetSize((ICON_SIZE+8,-1))
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.SelectItem)
        state.onEvent(EVENT_FILE_CHANGE, self.reload)
        state.onEvent(EVENT_PAGE_CHANGE, self.switchPage)
        self.reload()
        self.dontcare = 0
        #self.Bind(wx.EVT_IDLE, self.OnIdle)
        #print dir(self)

    def processFiles(self):
        if self.filepos >= 0 and self.filepos < state.pdf.pages:
            icon = state.getPageIcon(self.filepos+1)
            self.imglist.Add(icon)
            self.InsertImageStringItem(self.filepos, str(self.filepos+1), self.filepos)
            self.filepos = self.filepos + 1
        self.Update()

    def OnIdle(self,event):
        self.processFiles()
        event.ResumePropagation(0)

    def reload(self):
        self.filepos = -1
        self.DeleteAllItems()
        self.imglist = wx.ImageList(ICON_SIZE,ICON_SIZE,mask=False)
        self.AssignImageList(self.imglist,wx.IMAGE_LIST_NORMAL)
        self.filepos = 0
        while state.pdf and self.filepos < state.pdf.pages:
            self.processFiles()

    def switchPage(self):
        if self.dontcare:
            self.dontcare = 0
            return
        for i in range(0,self.GetItemCount()):
            self.Select(i, False)
        self.Select(state.pagenr-1, True)
        self.Focus(state.pagenr-1)
        self.Update()

    def SelectItem(self,event):
        self.dontcare = 1 #ignore next change event
        state.changePage(event.GetIndex()+1)


helptxt = """
This is the SWF preview window.
Here, you will see how the SWF file generated from
the PDF file will look like. Changing parameters in
the configuration which affect the appeareance of
the final SWF will affect this preview, too, so you
can always evaluate the final output beforehand.
"""

        
class OnePageWidget(wx.Window):
    def __init__(self,parent):
        wx.Window.__init__(self, parent)
        self.SetSize((160,100))
        self.SetMinSize((160,100))
        self.Fit()
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_KEY_DOWN, self.key_down)
        state.onEvent(EVENT_PAGE_CHANGE, self.OnPageChange)
    
    def key_down(self, event):
        if state.pdf:
            if event.GetKeyCode() == 312 and state.pagenr>1:
                state.changePage(state.pagenr-1)
            elif event.GetKeyCode() == 313 and state.pagenr<state.pdf.pages:
                state.changePage(state.pagenr+1)

    def OnPageChange(self):
        self.Refresh()

    def OnSize(self, event):
        self.Refresh()

    def Draw(self,dc=None):
        global bitmap
        if not dc:
            dc = wx.ClientDC(self)
        posx = 0 
        posy = 0
        window_width,window_height = self.GetSize()
        dc.Clear()

        if not state.pdf or not state.page:
            return

        if state.page.width * window_height > state.page.height * window_width:
            width = window_width
            height = window_width * state.page.height / state.page.width
            posy = (window_height - height) / 2
        else:
            width = window_height * state.page.width / state.page.height
            height = window_height
            posx = (window_width - width) / 2

        dc.DrawBitmap(state.getPageImage(width,height), posx,posy, False)
        #state.getPageImage(

    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        self.Draw(dc)

class Pdf2swfFrame(wx.Frame):
    #def __init__(self):
        #wx.Window.__init__(self, None, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize)
    def __init__(self,application):
        wx.Frame.__init__(self, None, -1, style = wx.DEFAULT_FRAME_STYLE)
        self.application = application
        
        self.SetTitle("pdf2swf")
        self.createMenu()
        self.createToolbar()
        self.createStatusBar()
        self.createMainFrame()
        
        self.SetSize((800,600))

        self.options = OptionFrame(None)
        self.options.Show(False)
        self.options.updateOptions()

        state.onEvent(EVENT_STATUS_TEXT, self.status_change)
        self.html = 0
       
        #self.table = wx.AcceleratorTable([(wx.ACCEL_ALT,  ord('X'), 333),])
        #self.SetAcceleratorTable(self.table)

        self.Bind(wx.EVT_IDLE, self.OnIdle)
        self.Bind(wx.EVT_CLOSE, self.menu_exit)
        return

    def menu_open(self,event):
        global state
        if state.filename:
            dlg = wx.FileDialog(self, "Choose PDF File:", style = wx.DD_DEFAULT_STYLE, defaultFile = state.filename, wildcard = "PDF files (*.pdf)|*.pdf|all files (*.*)|*.*")
        else:
            dlg = wx.FileDialog(self, "Choose PDF File:", style = wx.DD_DEFAULT_STYLE, wildcard = "PDF files (*.pdf)|*.pdf|all files (*.*)|*.*")

        if dlg.ShowModal() == wx.ID_OK:
            self.filename = dlg.GetFilename() 
            state.loadPDF(self.filename)

    def menu_save(self,event,pages=None):
        html,self.html = self.html,0
        global state
        if not state.pdf:
            return
        print "html",html
        if not html:
            defaultFile = state.lastsavefile
        else:
            defaultFile = state.lasthtmlfile
        dlg = wx.FileDialog(self, "Choose Save Filename:", style = wx.SAVE | wx.OVERWRITE_PROMPT, defaultFile = defaultFile, wildcard = "all files (*.*)|*.*|SWF files (*.swf)|*.swf|HTML template (*.html)|*.html")
        
        if dlg.ShowModal() == wx.ID_OK:
            filename = os.path.join(dlg.GetDirectory(),dlg.GetFilename())
        
            #progress = ProgressFrame(self, "Saving %s File '%s'..." % (html and "HTML" or "SWF", filename))
            #progress.Show(True)
            progress = None
            state.saveSWF(filename, progress, pages, html)
            #progress.Destroy()
    
    def menu_save_selected(self,event):
        if not state.pdf:
            return
        p = []
        for i in range(0,self.pagelist.GetItemCount()):
            if self.pagelist.IsSelected(i):
                p += [i+1]
        self.menu_save(event, pages=p)

    def menu_save_html(self,event):
        self.html = 1
        return self.menu_save(event)

    def menu_save_selected_html(self,event):
        self.html = 1
        return self.menu_save_selected(event)

    def menu_exit(self,event):
        self.application.Exit()

    def menu_selectall(self,event):
        for i in range(0,self.pagelist.GetItemCount()):
            self.pagelist.Select(i, True)
    def menu_options(self,event):
        self.options.Show(True)

    def status_change(self):
        self.statusbar.SetStatusText(state.status_text)

    def OnIdle(self,event):
        if self.options.needreload:
            self.options.needreload = 0
            if state.pdf:
                # reload
                state.loadPDF(state.filename)

    def createMenu(self):
        menubar = wx.MenuBar()

        menu = wx.Menu();menubar.Append(menu, "&File")
        menu.Append(wx.ID_OPEN, "Open PDF\tCTRL-O");self.Bind(wx.EVT_MENU, self.menu_open, id=wx.ID_OPEN)
        menu.AppendSeparator()
        menu.Append(wx.ID_SAVE, "Save SWF (all pages)\tCTRL-W");self.Bind(wx.EVT_MENU, self.menu_save, id=wx.ID_SAVE)
        menu.Append(wx.ID_SAVEAS, "Save SWF (selected pages)\tCTRL-S");self.Bind(wx.EVT_MENU, self.menu_save_selected, id=wx.ID_SAVEAS)
        menu.AppendSeparator()
        menu.Append(2001, "Save HTML template (all pages)\tCTRL-H");self.Bind(wx.EVT_MENU, self.menu_save_html, id=2001)
        menu.Append(2002, "Save HTML template (selected pages)");self.Bind(wx.EVT_MENU, self.menu_save_selected_html, id=2002)
        menu.AppendSeparator()
        menu.Append(wx.ID_EXIT, "Exit\tCTRL-Q");self.Bind(wx.EVT_MENU, self.menu_exit, id=wx.ID_EXIT)

        menu = wx.Menu();menubar.Append(menu, "&Edit")
        menu.Append(wx.ID_SELECTALL, "Select All\tCTRL-A");self.Bind(wx.EVT_MENU, self.menu_selectall, id=wx.ID_SELECTALL)
        menu.AppendSeparator()
        menu.Append(wx.ID_PREFERENCES, "Options\tCTRL-R");self.Bind(wx.EVT_MENU, self.menu_options, id=wx.ID_PREFERENCES)

        menu = wx.Menu();menubar.Append(menu, "&Help")

        self.SetMenuBar(menubar)


    def createToolbar(self):

        tsize = (16,16)
        self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT)

        self.toolbar.AddSimpleTool(wx.ID_OPEN,
                                   wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize),
                                   "Open")
        self.toolbar.AddSimpleTool(wx.ID_SAVE,
                                   wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, tsize),
                                   "Save selected pages")
        self.toolbar.AddSimpleTool(wx.ID_PREFERENCES,
                                   wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_TOOLBAR, tsize),
                                   "Options")
        #self.toolbar.AddSeparator()
        self.toolbar.Realize()

    def createStatusBar(self):
        self.statusbar = self.CreateStatusBar(1)

    def createMainFrame(self):
        
        if 0:
            self.pagelist = PageListWidget(self)
            self.onepage = OnePageWidget(self)
            hsplit = wx.BoxSizer(wx.HORIZONTAL)
            pagelistbox = wx.StaticBox(self, -1, "Pages")
            pagelistboxsizer= wx.StaticBoxSizer(pagelistbox, wx.VERTICAL)
            pagelistboxsizer.Add(self.pagelist, proportion=1, flag=wx.EXPAND)
            onepagebox = wx.StaticBox(self, -1, "Page 1")
            onepageboxsizer= wx.StaticBoxSizer(onepagebox, wx.VERTICAL)
            onepageboxsizer.Add(self.onepage, proportion=1, flag=wx.EXPAND)
            hsplit.Add(pagelistboxsizer, 0, wx.EXPAND, 0)
            hsplit.Add(onepageboxsizer, 1, wx.EXPAND, 0)
            self.SetAutoLayout(True)
            self.SetSizer(hsplit)
            hsplit.Fit(self)
            hsplit.SetSizeHints(self)
        else:
            hsplit = wx.SplitterWindow(self, style=wx.SP_3D|wx.SP_LIVE_UPDATE)
            #p1 = wx.Panel(hsplit,-1, style=wx.SUNKEN_BORDER)
            #p2 = wx.Panel(hsplit,-1, style=wx.SUNKEN_BORDER)
            self.pagelist = PageListWidget(hsplit)
            self.onepage = OnePageWidget(hsplit)
            #hsplit.SplitVertically(p1,p2, sashPosition=64)
            hsplit.SplitVertically(self.pagelist, self.onepage, sashPosition=ICON_SIZE*3/2)
            hsplit.SetMinimumPaneSize(10)

class MyApp(wx.App):
    def __init__(self):
        wx.App.__init__(self, redirect=False, filename=None, useBestVisual=False)
        
        #state.loadPDF("sitis2007.pdf")
        #state.loadPDF("wxPython-Advanced-OSCON2004.pdf")
        global staticdata
        staticdata = StaticData()

        self.frame = Pdf2swfFrame(self)
        self.SetTopWindow(self.frame)
        self.frame.Show(True)

        #self.frame = TestFrame(self)
        #self.frame.Show(True)

    def OnInit(self):
        return True

app = MyApp()
app.MainLoop()
        
