# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - Gallery2 parser

    PURPOSE:
        This parser is used to visualize a couple of images as a thumbnail gallery.
        Optional a description of an image could be added including WikiName.
        On default the image name and it's creation date is shown.
        If you click on a thumbnail you get the webnails shown. By a menue you are able to toggle between the slides.

    CALLING SEQUENCE:
      {{{
      #!Gallery2 [columns=columns],[filter=filter],[mode=mode],
                 [show_text=show_text],[show_date=show_date], [show_tools=show_tools],
                 [sort_by_name=sort_by_name],[sort_by_date=sort_by_date], [sort_by_alias=sort_by_alias],
                 [reverse_sort=reverse_sort],
                 [only_items=only_items],[template_itemlist=template_itemlist],
                 [album=album],[album_name=album_name],[front_image=front_image],
                 [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],
                 [image_for_webnail=image_for_webnail],
                 [sequence_name=sequence_name], [sequence_fps=sequence_fps],
                 [border_thick=border_thick],[renew=renew],[help=help]
      * [image1.jpg alias]
      * [image2.jpg alias]
      }}}

    KEYWORD PARAMETERS:
        columns:           number of columns for thumbnails
        filter:            regex to select images
        show_text:         default is 1 description is shown
                           any other means no description
        show_date:         default is 1 date info from exif header if available is shown
        show_tools:        default is 1 icon toolbar is show any other disables this
        sort_by_name:      default is 1, the images are sorted by name, but not if only_items is 1
        sort_by_date:      default is 0, if set to 1 the images are sorted to the modification time
                           if they do have all the same time then the result is random
        sort_by_alias      default is 0, if set to 1 and only_items set to 1 it is used to order the images by the alias name
        reverse_sort:      default is 0, if set to 1 the file list is reversed
                           any other means no description
        mode:              default is 1 this means description below the image
                           any other number means description right of image
        only_items:        default is 0 if it is set to 1 only images which are described in listitem are shown
                           dependend on the order of the items
        template_itemlist: default is 0, if set to 1 an item list is shown which could be copied into the script. 
        album:             default is 0 if set to 1 only the first image of a series is shown but slideshow over all images 
        album_name:        useful for album. default is 'album' use it as short name for the album. 
        front_image:       Useful for album.  default is ''. The first image is shown in front of the album and slideshow.
                           If set to an existing image name this is shown in front of album and slideshow. 
                           The slide show could start by this somewhere.
        border_thick:      default is 1 this is the thickness in pixeln of the outer frame
        renew:             default is 0 if set to 1 then all selected thumbnails_* and webnails_* removed.
                           Afterwards they are new created.
        thumbnail_width:   default is 128
        webnail_width:     default is 640
        text_width:        default is 140		   
        image_for_webnail  default is 0 if set to 1 then the image is shown as preview and not the webnail
        sequence_name:     default is ''  if set this name is used for an image
                           sequence with an duration of one image per second.
        sequence_fps:      (frames per second) default is 1 it is not allowed to set values below 1
        help:              default is 0 if set a copy of the CALLING SEQUENCE is shown, 
                           (there are some new ideas around to show help to an user so this will be later replaced)
                           

    OPTIONAL INPUTS:
        itemlist : if it is used and only_items is 1 then only the images in this list are ahown.
                   The alias text is used as description of the image instead of the file name


    EXAMPLE:
= GalleryTest =

== all images shown, one is decribed ==
{{{
{ { {
#!Gallery2
* [100_1185.JPG Bremen, SpaceCenter]
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2
* [100_1185.JPG Bremen, SpaceCenter]
}}}

== only thumbnails and only_items ==
{{{
{ { {
#!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
 * [100_1185.JPG Bremen, SpaceCenter]
 * [100_1194.JPG Bremen]
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
 * [100_1185.JPG Bremen, SpaceCenter]
 * [100_1194.JPG Bremen]
}}}

== only_items by two columns and text right ==

{{{
{ { {
#!Gallery2 mode=2,columns=2,only_items=1
 * [100_1185.JPG Bremen, SpaceCenter]
 * [100_1194.JPG Bremen]
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2 mode=2,columns=2,only_items=1
 * [100_1185.JPG Bremen, SpaceCenter]
 * [100_1194.JPG Bremen, behind SpaceCenter]
}}}

----

== only_items by two columns, date supressed ==

{{{
{ { {
#!Gallery2 columns=2,only_items=1,show_date=0
 * [100_1185.JPG Bremen, SpaceCenter]
 * [100_1194.JPG Bremen, behind SpaceCenter]
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2 columns=2,only_items=1,show_date=0
 * [100_1185.JPG Bremen, SpaceCenter]
 * [100_1194.JPG Bremen, behind SpaceCenter]
}}}


== filter regex used, mode 2, icons and date supressed, one column and border_thick=5 ==
{{{
{ { {
#!Gallery2 columns=1,filter=100_118[0-5],mode=2,show_date=0,show_tools=0,border_thick=5
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2 columns=1,filter=100_118[0-7],mode=2,show_date=0,show_tools=0,border_thick=5
}}}

== other macro calls ==
{{{
{ { {
#!Gallery2 only_items=1,show_date=0
 * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2 only_items=1,show_date=0
 * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
}}}

== renew means always new thumbnails and webnails of selection ==
{{{
{ { {
#!Gallery2 only_items=1,show_date=0,show_tools=0,renew=1
 * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2 only_items=1,show_date=0,renew=1
 * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
}}}

== template_itemlist ==
{{{
{ { {
#!Gallery2 template_itemlist=1
* [100_1185.JPG Bremen, SpaceCenter]
} } }
}}}

Result: [[BR]]
 {{{
#!Gallery2 template_itemlist=1
* [100_1185.JPG Bremen, SpaceCenter]
}}}

== help to show Calling Sequence ==
 {{{
{ { {
#!Gallery2 help=1
} } }
}}}

Result: [[BR]]
{{{
#!Gallery2 help=1
}}}


    PROCEDURE:
      ABOUT:
      While I have first implemented Gallery2 for something like photos I do use it at work since a while for
      output of model calculations too.
      Because of the possibility to share a standalone playable file to colleagues I have first decided to use
      fli or mpeg as output format for an image sequence. mpeg is not quite good for displaying our data
      and fli does sometimes eat a lot of cpu power. Both would make a lot of work getting them working
      on a non posix OS. For further development it would be better to have a python only version of Gallery2.
      That's the reason why I switch the sequence format to flash now. I do use the library of Matthias Kramm
      (http://www.swftools.org).
      
      HOWTO:
      Download some images to a page and start with the examples.
      Aliasing of the filenames are done by adding an itemlist, see example.

      NEEDS:
      This routine requires the Action macro gallery2image which is used to rotate or delete a
      selected image. The actual version is gallery2image-1.5.4-13.py.
      Only users which have the rights to delete are able to execute this action macro. 
      The icons of these are only shown if you have enough rights. 
      Furthermore it requires:
       * the PIL (Python Imaging Library).
       * the EXIF routine from http://home.cfl.rr.com/genecash/digital_camera.html
         (you need a modifed version you'll get it from the Gallery2 documentation page)
       * the SWF library from http://www.swftools.org

      Do install them to the usual python library path.
      
      REQUIRED IMAGES:
      You have to put them into wiki/mg/ dir. e.g.: http://moinmoin.wikiwikiweb.de/ParserMarket/Gallery2/ModernImages
      
      GENERAL:
      Please remove the Version number from the code!

      If you want to upload many files at once please look on MoinMoin versions less 1.5.0
      at FeatureRequests/UploadMultipleAttachmentFiles/RulesForUnzip
      
      With many images you can get in trouble by the SurgeProtection for attachment. Then you have to adjust the parameters see HelpOnConfiguration/SurgeProtection. 
      
      RESTRICTIONS:
      If you rotate an image at the moment the exif is destroyed. PIL ignores the exif header.
      This is not a quite big problem normally files with an EXIF header are right rotated.
      
      HISTORY:
      While recognizing how to write MiniPage I got the idea to write a Gallery Parser.
      We have used in our wikis in the past the Gallery macro of SimonRyan.
      I have tried to modify it a bit to change it for 1.3 but my python skills weren't enough
      or it was easier to write it completly new.
      So this one shows now a way how a Gallery could be used by the parser and an action Macro.
      Probably it is a good example for others who like to know how to do this

      OUTLOOK:
      Dependent on Matthias Kramm's python interface development the webnails could be exchanged to a
      flash animation with action controls. That will ommit the javascript slide show and will give less files.
      swftools is able to do this by now but that will need an os.system call. At the moment I like to avoid this.
      If you are interested the command is swfcombine -o output.swf movie_control.swf viewport=input.swf.
      It is still in the code but commented off. movie_control.swf embbeds the controls 24 pixels above the flash so it's a good idea to resize the flash by the -X and -Y option.

    MODIFICATION HISTORY:
        Version 1.3.3.-1
        @copyright: 2005 by Reimar Bauer (R.Bauer@fz-juelich.de)
        @license: GNU GPL, see COPYING for details.
        2005-03-26: Version 1.3.3-2 keyword renew added
                    creation of thumbnails and webnails in two calls splitted
                    Version 1.3.3-3 bug fixed if itemlist is given to describe only some of the images
                                    but only_items is not set to 1
                                    Example code changed
        2005-03-27: Version 1.3.3-4 Action macro added and the form to call it. User which have rights to delete
                                    could use the functions of gallery2Image.
        2005-08-03: Version 1.3.3-5 theme path for icons corrected and a platform independent path joining
                                    os.unlink removed as suggested by CraigJohnson
                                    sort_by_name is default if not only_items is 1
                                    optional sort_by_date could be used
                                    keyword template_itemlist added 
                                    keyword help added
                                    extra frame by mode=2 removed 
        2005-08-06: Version 1.3.5-6 slideshow mode added
                                    keyword image_for_webnail added
        2005-08-13: Version 1.3.5-7 syntax changed from GET to POST
                                    forms instead of links
                                    filenames from images submitted to gallery2image too
                                    new keyword sort_by_alias
                                    internal code clean up
                                    this version needs: gallery2image-1.3.5-5.py
        2005-08-14: Version 1.3.5-8 (TW) cleanup                                    
        2005-08-14: Version 1.3.5-9 html code for tables changed
                                    because of the ugly extra space of form elements
                                    div tag removed so now we use the page style
                                    slide show action goes to right webnail now
                                    this version needs: gallery2image-1.3.5-5.py
       2005-08-17: Version 1.3.5-10 html code separated in functions     
                                    structure of code changed, now you see the thumbnails after creation
                                    bug removed if quote is given but file does not exist
       2005-09-02: Version 1.3.5-11 keyword album, album_name and front_image added          
                                    image urls changed to complete server url      
       2005-11-12: Version 1.3.5-12 bug fixed for image_for_webnail=1            
                                    bug fixed at last cell table end tr instead of td
                                    bug fixed don't render a filename as WikiName
                                    bug fixed " is allowed in alias name
                                    bug fixed ' is allowed in alias name
                                    bug fixed linebreak by a space in alias  
                                    not quite a bug but makes it very difficult to code in 
                                    gallery2image so additional id removed in alias name
      2005-11-17: Version 1.3.5-13  implementation of sequence video clips at first step for posix only 
                                    sequence_type could be used to ommit the autoselection
                                    fli/flc files are used for gif and png files,  mpeg files for
                                    jpeg files. Duration on both is 1 image/second 
                                    feature added of recognising the right url pattern (http opr https)
      
 
                                    
     Version 1.5.4-16 2006-08-02 based on 1.3.5-13                    
     FlorianFesti: major changes    more flexible but better aligned layout
                                    better support for border_width=0              
                                    use of cfg.url_prefix insted of hard coding /wiki
                                         
     ReimarBauer:                   PEP8 style
                                    mode2 changed to Florians style too
                                    some other changes to get things compatible to previous versions
                                    flash (swf) format is used as sequence format
                                    keyword sequence_fps added
                                    keyword eo_info added
                                    EXIF.py moved to python lib 
                                       used the version of StigIversen
                                       
                                    file names of webnails and thumbnails does now have a prefix of tmp.   
                                    direct serving of webnails and thumbnails is possible but not default
                                       You have to set the var document_root in your wikiconfig.py to the absolute path of
                                       the wiki alias. For the default installation it is document_root = '/usr/share/moin/htdocs'
                                       Using this method MoinMoin can't use acls for the webnails and thumbnails.

    2006-08-11 1.6.0-17 RB ported to 1.6.0 dev alpha version
    2006-08-22 1.6.0-18 RB for the call of Frame a test if parameters are submitted is added
                                       
                                   
"""
Dependencies = ['time'] # do not cache

from MoinMoin.action import AttachFile
from MoinMoin import wikiutil, config
from MoinMoin.Page import Page

import os, re, sys, Image, StringIO, codecs
from random import randint

try:
    import EXIF
except ImportError:
    EXIF = None

try:
    import SWF
except ImportError:
    SWF = None


from MoinMoin.parser import text_moin_wiki

class Parser:
    extensions = '*'
    def __init__(self, raw, request, **kw):
        self.sort_by_date = '0'
        self.sort_by_name = '1'
        self.sort_by_alias = '0'
        self.album = '0'
        self.album_name = 'album'
        self.front_image = ''
        self.template_itemlist = '0'
        self.reverse_sort = '0'
        self.border_thick = '1'
        self.columns = '4'
        self.filter = '.'
        self.mode = '1'
        self.help = '0'
        self.show_text = '1'
        self.show_date = '1'
        self.show_tools = '1'
        self.only_items = '0'
        self.image_for_webnail = '0'
        self.renew = '0'
        self.thumbnail_width = '128'
        self.webnail_width = '640'
        self.text_width = '140'
        self.sequence_name = ''
        self.sequence_fps = '1'
        self.eo_info = '0'
        
        
        test = kw.get('format_args', '')
        if test:
            for arg in kw.get('format_args', '').split(','):
                if arg.find('=') > -1:
                    key, value = arg.split('=')
                    setattr(self, key, wikiutil.escape(value.strip(), quote=1))

        self.width = str(int(self.thumbnail_width) +
                         int(self.text_width))

        self.raw = raw
        self.request = request
        self.form = request.form
        self._ = request.getText

        self.outer_table_style = ' border="%s"' % self.border_thick
        self.inner_table_style = ' style="border-style:none; margin:10px;"'
        self.td_style = ' align="center" style="padding:0; margin:2px 2px; border-style:none"'

    def images2swf(request, images, swf_filename, swf_fps, description, exif_date):
    ## this code is based on
    ## http://www.quiss.org/swftools/python/jpeg2swf_exif.py
    ## by Matthias Kramm
    ##
    ## Thanks Matthias

        xmax, ymax = 0, 0
        depth = 1
        SWF.verbose(0)
        # verbose is not used everybody
        swf = SWF.create(version=6, bbox=(0, 0, 0, 0), fps=float(swf_fps))

        i = 0
        for filename in images:
            pic = Image.open(filename)
            pic.load()

            width, height = pic.size
            if width > xmax: xmax = width
            if height > ymax: ymax = height

            pic = pic.convert("RGBA")
            image = SWF.Image(pic.im)

            swf.tags += image
            shape = SWF.ImageShape(image)
            swf.tags += shape
            swf.tags += SWF.PlaceObject(shape, depth=depth)
            depth += 1
            swf.tags += SWF.ShowFrame()

            i += 1

        swf.bbox = (0, 0, xmax, ymax)
        swf.save(swf_filename)

        return xmax, ymax

    def show_tools_restricted(self, this_target):
        if not self.request.user.may.delete(self.pagename):
            return ''

        return '''
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
          <td%(style)s>
            <input type="hidden" name="action" value="gallery2image">
            <input type="hidden" name="do" value="RL">
            <input type="hidden" name="target" value="%(this_target)s">
            <input type="image" value="submit" src="%(htdocs)s/img/to_right.png" title="rotate to left">
          </td>
        </form>
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
          <td%(style)s>
            <input type="hidden" name="action" value="gallery2image">
            <input type="hidden" name="do" value="RR">
            <input type="hidden" name="target" value="%(this_target)s">
            <input type="image"  value="submit" src="%(htdocs)s/img/to_left.png" title="rotate to right" >
          </td>
        </form>
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
          <td%(style)s>
            <input type="hidden" name="action" value="gallery2image">
            <input type="hidden" name="do" value="RM">
            <input type="hidden" name="target" value="%(this_target)s">
            <input type="image" value="submit" src="%(htdocs)s/img/to_bak.png" title="move to bak" >
           </td>
        </form>''' % {
            'baseurl': self.request.getBaseURL(),
            'style': self.td_style,
            'htdocs': self.request.cfg.url_prefix,
            "pagename": self.quoted_pagename,
            "this_target": this_target}

    def tools_html(self, idx):
        this_image = self.full[idx]

        text = '''
            <TABLE align="center" width="%(thumbnail_width)s"%(tablestyle)s>
                <TR>
                    <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
                        <td%(style)s>
                            <input type="hidden" name="action" value="AttachFile">
                            <input type="hidden" name="do" value="get">
                            <input type="hidden" name="target" value='%(this_target)s'>
                            <input type="image" value="submit" src="%(htdocs)s/img/to_full.png" title="load image">
                        </td>
                    </form>
                    <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
                        <td%(style)s>
                            <input type="hidden" name="action" value="gallery2image">
                            <input type="hidden" name="do" value="VS">
                            <input type="hidden" name="full" value='%(full)s'>
                            <input type="hidden" name="alias" value='%(description)s'>
                            <input type="hidden" name="target" value='%(target)s'>
                            <input type="hidden" name="exif_date" value='%(exif_date)s'>
                            <input type="image" value="submit" src="%(htdocs)s/img/to_slide.png" title="slide_show" >
                       </td>
                    </form>
                    %(show_tools_restricted)s
                </TR>
            </TABLE>'''   % {
            "baseurl": self.request.getScriptname(),
            "pagename": self.quoted_pagename,
            "htdocs": self.request.cfg.url_prefix,
            "tablestyle": self.inner_table_style,
            "style": self.td_style,
            "thumbnail_width": self.thumbnail_width,
            "full": self.full[idx] + ',' + ','.join(self.full),
            "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
            "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
                                         ','.join(self.exif_date)),
            "target": self.webimg[idx] + ',' + ','.join(self.webimg),
            "this_target": self.full[idx],
            "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
            "show_tools_restricted":self.show_tools_restricted(this_image)
            }

        return text

    def show_alias_mode2(self, idx):
       if self.show_text == '1':
           return '''
            <td valign="top" width="%(text_width)s" %(style)s>
           %(this_alias)s
        </td>''' % {
        "this_alias":self.description[idx],
        "text_width":self.text_width,
        "style": ' align="left" style="padding:0px; margin:2px 2px; border-style:none"'}
       else:
          return ''

    def show_date_mode2(self, idx):
       if self.show_date == '1':
           return '''
                  <td%(style)s><p>%(this_exif_date)s</p></td>''' % {
                  "style": self.td_style,
                  "this_exif_date": self.to_htmltext(self.exif_date[idx]) }
       else:
            return ''

    def show_tools_mode2(self, idx):
        if self.show_tools == '1':
            return "<td align=""center""%(style)s> %(tools)s </td>" % {
                "style":self.td_style,
                "tools":self.tools_html(idx)}
        else:
            return ''

    def mode2_html(self, idx):
        text = '''
        <tr valign="center">
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
            <td align="center" valign="center" width="%(thumbnail_width)s"
            %(tdstyle)s>
                <input type="hidden" name="action" value="gallery2image">
                <input type="hidden" name="do" value="VS">
                <input type="hidden" name="full" value='%(full)s'>
                <input type="hidden" name="alias" value='%(description)s'>
                <input type="hidden" name="exif_date" value='%(exif_date)s'>
                <input type="hidden" name="target" value='%(target)s'>
                <input type="image" value="submit" src="%(thumbnail)s">
            </td>
        </form>
            %(alias_html)s 
    </tr>
    <tr>%(tools_html)s%(date_html)s</tr>''' % {
     "tdstyle": self.td_style,
     "baseurl": self.request.getScriptname(),
     "pagename": self.quoted_pagename,
     "thumbnail_width": self.thumbnail_width,
     "full": self.full[idx] + ',' + ','.join(self.full),
     "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
     "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
                                  ','.join(self.exif_date)),
     "target": self.webimg[idx] + ',' + ','.join(self.webimg),
     "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
     "tools_html": self.show_tools_mode2(idx),
     "date_html": self.show_date_mode2(idx),
     "alias_html": self.show_alias_mode2(idx)
     }

        return text

    def show_tools_mode1(self, idx):
        if self.show_tools == '1':
            text = "<tr><td align=""center""%(style)s>%(tools)s </td></tr>" % {
                "style":self.td_style,
                "tools":self.tools_html(idx)}
        else:
            text = ''
        return text

    def show_date_mode1(self, idx):
       if self.show_date == '1':
           return '''
        <TR>
        <td%(style)s>%(this_exif_date)s</td>
    </TR>''' % {
    "style":self.td_style,
    "this_exif_date": self.to_htmltext(self.exif_date[idx])}
       else:
           return ''

    def show_alias_mode1(self, idx):
       if self.show_text == '1':
           return '''
        <TR>
        <td width="%(thumbnail_width)s" %(style)s> %(this_alias)s</td>
    </TR>''' % {
    "thumbnail_width": self.thumbnail_width,
    "style": ' align="left" style="padding:0em; margin:2px 2px; border-style:none"',
    "this_alias": self.description[idx]}
       else:
           return ''

    def mode1_html(self, idx):
        text = '''
    <table width="%(thumbnail_width)s" align="center" valign="center"%(style)s>
    <TR align="center" valign="center">
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
            <td align="center" valign="middle" width="%(thumbnail_width)s"
            %(tdstyle)s>
                <input type="hidden" name="action" value="gallery2image">
                <input type="hidden" name="do" value="VS">
                <input type="hidden" name="full" value='%(full)s'>
                <input type="hidden" name="alias" value='%(description)s'>
                <input type="hidden" name="exif_date" value='%(exif_date)s'>
                <input type="hidden" name="target" value='%(target)s'>
                <input type="image" value="submit" src="%(thumbnail)s" >
            </td>
        </form>
    </TR>
      %(alias_html)s
      %(date_html)s
      %(tools_html)s
</table>'''%       {
     "tdstyle": self.td_style,
     "style": self.inner_table_style,
     "baseurl": self.request.getScriptname(),
     "pagename": self.quoted_pagename,
     "full": self.full[idx] + ',' + ','.join(self.full),
     "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
     "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
                                  ','.join(self.exif_date)),
     "target": self.webimg[idx] + ',' + ','.join(self.webimg),
     "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
     "thumbnail_width": self.thumbnail_width,
     "tools_html": self.show_tools_mode1(idx),
     "date_html": self.show_date_mode1(idx),
     "alias_html": self.show_alias_mode1(idx)
     }

        return text

    def get_files(self, path, files, quotes):
        self.web = []
        self.full = []
        self.thumb = []
        self.exif_date = []
        self.imgtype = []
        self.description = []

        ddict = {}
        n = len(quotes['image'])
        if n > 0:
            i = 0
            for txt in quotes['image']:
                ddict[txt] = quotes['alias'][i]
                i += 1

        self.video_type = 'swf'
        self.source_type = ''
        for attfile in files:
            # only files not thumb or webnails
            if not attfile.startswith('tmp.') and attfile.find('thumbnail_') == -1 and attfile.find('webnail_') == -1:
            #previous naming left for compatibility
                # only images
                if wikiutil.isPicture(attfile):
                    self.description.append(ddict.get(attfile, attfile))
                    self.full.append(attfile)

                    fname, ext = os.path.splitext(attfile)
                    if ext in ('.gif', '.png'):
                        self.imgtype.append('PNG')
                        webnail = 'tmp.webnail_%s.png' % fname
                        thumbfile = 'tmp.thumbnail_%s.png' % fname
                        video_type = 'swf'
                        source_type = ext[1:]
                    else:
                        self.imgtype.append("JPEG")
                        webnail = 'tmp.webnail_%s.jpg' % fname
                        thumbfile = 'tmp.thumbnail_%s.jpg' % fname
                        video_type = 'swf'
                        source_type = 'jpg'

                    infile = os.path.join(path, attfile)
                    if os.path.exists(infile):
                         self.web.append(webnail)
                         self.thumb.append(thumbfile)


                    f = open(infile, 'rb')
                    tags = EXIF.process_file(f, 'DateTimeOriginal')
                    f.close()
                    if tags.has_key('EXIF DateTimeOriginal'):
                        date = str(tags['EXIF DateTimeOriginal'])
                        date = date.replace(':', '-', 2)
                    else:
                        date = '--'

                    self.exif_date.append(date)


    def to_htmltext(self, text):
        if text.find ("'"):
            text = text.split("'")
            text = '&#39;'.join(text)
        return text

    def to_wikiname(self, formatter, text):
        ##taken from MiniPage
        out = StringIO.StringIO()
        self.request.redirect(out)
        wikiizer = text_moin_wiki.Parser(text.strip(), self.request)
        wikiizer.format(formatter)
        result = out.getvalue()
        self.request.redirect()
        del out

        result = result.replace('<a id="line-1"></a>', '')
        result = result.replace('<p>', '')
        result = result.replace('</p>', '')
        result = result.strip()
        return result


    def get_quotes(self, formatter):
        quotes = self.raw.split('\n')
        quotes = [quote.strip() for quote in quotes]
        quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]

        image = []
        text = []

        for line in quotes:
            im, na = line[1:-1].split(' ', 1)
            na = na.strip()
            na = self.to_htmltext(na)
            na = self.to_wikiname(formatter, na)
            text.append(na)
            image.append(im.strip())

        return {
            'alias': text,
            'image': image,
        }

    def print_help(self):
        self.request.write('''
<br>
{{{<br>
#!Gallery2 [columns=columns],[filter=filter],[mode=mode],<br>
           [show_text=show_text],[show_date=show_date], [show_tools=show_tools],<br>
           [sort_by_name=sort_by_name],[sort_by_date=sort_by_date],[sort_by_alias=sort_by_alias]<br>
           [reverse_sort=reverse_sort],<br>
           [only_items=only_items],[template_itemlist=template_itemlist],<br>
           [album=album],[album_name=album_name],[front_image=front_image],<br>
           [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],<br>
           [image_for_webnail=image_for_webnail],<br>
           [sequence_name=sequence_name],[sequence_fps=sequence_fps]<br>
           [border_thick=border_thick],[renew=renew],[help=help]<br>
 * [image1.jpg alias]<br>
 * [image2.jpg alias]<br>
}}}<br>''')

    def format(self, formatter):
        if self.help == '1':
            self.print_help()
            return
        Dict = {}
        quotes = self.get_quotes(formatter)
        current_pagename = formatter.page.page_name
        self.pagename = current_pagename
        self.quoted_pagename = wikiutil.quoteWikinameURL(self.pagename)
        attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)

        if hasattr(self.request.cfg, 'document_root'):

            self.static_path = "%(dir)s/tmp/Gallery2%(wiki_name)s/%(pagename)s" % {
                 "wiki_name": self.request.getScriptname(),
                 "pagename": self.pagename,
                 "dir": self.request.cfg.document_root,
                 }
            if os.path.exists(self.static_path) == 0:
                 os.makedirs(self.static_path)

            self.static_url = "%(prefix)s/tmp/Gallery2%(wiki_name)s/%(pagename)s/" % {
                 "prefix": self.request.cfg.url_prefix,
                 "wiki_name": self.request.getScriptname(),
                 "pagename": self.pagename,
                 }
        else:
            self.static_path = attachment_path
            self.static_url = AttachFile.getAttachUrl(self.pagename, '', self.request)


        if self.only_items == '1':
            all_files = quotes['image']
            result = []
            for attfile in all_files:
                infile = os.path.join(attachment_path, attfile)
                if os.path.exists(infile):
                   result.append(attfile)
            all_files = result

            if self.sort_by_alias == '1':
                new_ordered_files = []
                alias_text = quotes['alias']

                i = 0
                for attfile in all_files:
                    infile = os.path.join(attachment_path, attfile)
                    Dict[alias_text[i]] = attfile
                    i += 1

                keys = Dict.keys()
                keys.sort()
                for txt in keys:
                    new_ordered_files.append(Dict[txt])

                all_files = new_ordered_files
                Dict.clear()

        else:
            all_files = os.listdir(attachment_path)


        if self.filter != '.':
            result = []
            for test in all_files:
                if re.match(self.filter, test):
                  result.append(test)

            all_files = result

        if not all_files:
            self.request.write("<br><br><h1>No matching image file found!</h1>")
            return

        if self.sort_by_name == '1' and self.only_items == '0':
            all_files.sort()

        if self.sort_by_date == '1':
           for attfile in all_files:
               infile = os.path.join(attachment_path, attfile)
               ft_file = "%s%s" % (str(os.path.getmtime(infile)), str(randint(0, 65535)))
               Dict[ft_file] = attfile

           keys = Dict.keys()
           keys.sort()
           file_mdate = []
           for txt in keys:
               file_mdate.append(Dict[txt])
           all_files = file_mdate
           Dict.clear()

        if self.reverse_sort == '1':
             all_files.reverse()

        cells = []
        cell_name = []
        img = []

        self.get_files(attachment_path, all_files, quotes)

        if self.template_itemlist == '1':
            self.request.write('Copy the following listitems into the script. Replace alias with the label you want. Afterwards disable template_itemlist by setting it to 0:<BR>')
            for attfile in self.full:
                self.request.write(' * [%(attfile)s %(date)s]<br>\n' % {
                                   'attfile': attfile,
                                   'date': 'alias'
                                    })

        i = 0
        z = 1
        cols = int(self.columns)

        n = len(self.full)
        if  self.album == '0':
            self.request.write("<table%s>" % self.outer_table_style)
            if self.mode == '1' or cols > 1:
                self.request.write('<TR valign="top">')
                self.request.write('<TD%s>' % self.td_style)


        if self.album == '1':
            if self.front_image == '':
                front_image = self.full[0]
            else:
                front_image = self.front_image
            ii = 0
            for tst in self.full:
                if tst == front_image:
                    break
                ii += 1

        for attfile in self.full:
            if  self.album == '1':
                if tst == front_image:
                   i = ii

            this_description = self.description[i]
            this_exif_date = self.exif_date[i]
            this_webnail = self.web[i]
            this_imgtype = self.imgtype[i]
            this_thumbfile = self.thumb[i]

            thumbf = os.path.join(self.static_path, this_thumbfile)
            webf = os.path.join(self.static_path, this_webnail)

            if self.renew == '1':
                if os.path.exists(thumbf):
                   os.unlink(thumbf)
                if os.path.exists(webf):
                   os.unlink(webf)

            if not os.path.exists(webf) or not os.path.exists(thumbf):
                infile = os.path.join(attachment_path, attfile)
                im = Image.open(infile)

                if not os.path.exists(webf):
                    im.thumbnail((int(self.webnail_width), int(self.webnail_width)), Image.ANTIALIAS)
                    if self.image_for_webnail == '1':
                       os.link(os.path.join(attachment_path, attfile), webf)
                    else:
                       im.save(webf, this_imgtype)
                if not os.path.exists(thumbf):
                    im.thumbnail(((int(self.thumbnail_width)), ((int(self.thumbnail_width)))),
                                   Image.ANTIALIAS)
                    im.save(thumbf, this_imgtype)

            if self.image_for_webnail == '1':
                 this_webnailimg = attfile
                 self.webimg = self.full
            else:
                 this_webnailimg = this_webnail
                 self.webimg = self.web

            if self.mode == '1':
                text = self.mode1_html(i)
                self.request.write(''.join(text))

            if self.mode == '2':
                text = self.mode2_html(i)
                if cols > 1: self.request.write('<table valign="bottom">')
                self.request.write(''.join(text))
                if cols > 1: self.request.write('</table>')

            if self.mode == '1' or cols > 1:
                if self.album == '0':
                    if  z < cols:
                        self.request.write('</TD>')
                        if z < n and  i < n - 1:
                            self.request.write('<TD%s>' % self.td_style)
                        if i == n - 1:
                            self.request.write('</TR>')
                    else:
                        self.request.write('</TD>')
                        self.request.write('</TR>')
                        if i < n - 1:
                            self.request.write('<TR valign="top">')
                            self.request.write('<TD%s>' % self.td_style)

            i += 1
            z += 1
            if z > cols:
                z = 1

            if self.album == '1':
                self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name": self.album_name})
                break

        if self.album == '0':
            if i < n:
                self.request.write('</TD>')
                self.request.write('</TR>')
            self.request.write('</table>')


        if self.sequence_name != '':
            video_file = "%(file)s.%(ext)s" % {
                 "file": os.path.join(attachment_path, self.sequence_name),
                 "ext": 'swf'}
            if self.renew == '1':
               if os.path.exists(video_file):
                  os.unlink(video_file)

            cmd = ''
            if float(self.sequence_fps) < 1:
                fps = 1
            else:
                fps = round(float(self.sequence_fps))

            f_list = []
            for attfile in self.web:
                file = os.path.join(self.static_path, attfile)
                if os.path.exists(file):
                   f_list.append(file)

            if not os.path.exists(video_file):
                width, height = self.images2swf(f_list, video_file, fps, self.description, self.exif_date)
            else:
                swf = SWF.load(video_file)
                for tag in swf.tags:
                    if tag.isImage():
                       width, height = tag.image.size
                       break

            if os.path.exists(video_file):
                  dict = {}
                  dict['src'] = AttachFile.getAttachUrl(current_pagename, '%(file)s.%(videotype)s'  % {
                     'file': self.sequence_name,
                     'videotype': 'swf',
                     }, self.request)

                  image_link = '%(file)s.%(videotype)s' % {'file':self.sequence_name, 'videotype': 'swf'}
                  if  self.eo_info == '1':
                      eo = "Or embed it into your wiki page by [[EmbedObject(%(file)s,width=%(width)s,height=%(height)s)]]." % {
                           'file': image_link,
                           'width': str(width),
                           'height': str(height)}
                  else:
                      eo = ''

                  self.request.write('<P>')
                  text = formatter.url(1, dict['src'] ) + image_link + formatter.url(0)
                  self.request.write('Download this image sequence %(text)s for your archive. %(EO)s' % {
                       'text': text,
                       'EO': eo
                       })
                  self.request.write('</P>')
