# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - findandreplace action

    @copyright: 2006 Richard Flieger
    @contact: < e DASH mail AT rf DASH mmx DOT de >
    @license: GNU GPL, see COPYING for details.
    
    Description:
        This action allows users to search words and
        sentenses on the current wiki-page and replace
        the results by another text.
        
    Feathers:
        * regulare expressions
        * wildcard character
        * fixed strings
        * show results
        * show context
        * highlight in page
        * show raw-text
        * toggle highlightning
        * replace selected
        * replace all
        * preview
        * custumend comment
        * trivial change or not
        * language support
    
    History:
        2007/03/11 0.1b: Beta, dirty hack
        
"""

from MoinMoin.Page import Page
from MoinMoin import PageEditor
from MoinMoin.widget.dialog import Dialog
from re import *
import re
import shutil
import time

class FindAndReplaceAction:

    def __init__(self, request, referrer):
        self.request = request
        self.referrer = referrer
        self._ = request.getText

    def render( self ):
        
        self.form = self.request.form
        
        self.currentusername = self.request.page.page_name
        
        if not self.request.user.may.read(self.currentusername) or self.form.has_key(u'cancel_button'):
            query = {'action': 'show'}
            url = Page(self.request, self.referrer).url(self.request, query, 0)
            self.request.http_redirect(url)
        
        self.find = self.form.get('find', [None] )[0]
        self.replace = self.form.get('replace', [""] )[0]
        self.methode = self.form.get('methode', ["text"])[0]
        self.casesensitive = self.form.get( 'casesensitive', [0])[0]
        self.word = self.form.get('word', [None])[0]
        self.context = self.form.get('context', [0])[0]
        self.selected = self.form.get('selected', [])
        self.comment = self.form.get('comment', [""] )[0]
        self.highlight = self.form.get( 'highlight',[""] )[0]
        self.multiline = self.form.get( "multiline", [""])[0]
        self.searchonly = self.form.get( "searchonly", [""])[0]
        self.trivial = self.form.get( "trivial", [0] )[0]
        self.showraw = self.form.get( "showraw", [0] )[0]
        
        if not self.request.user.may.write(self.currentusername):
            self.showraw = 0
        self.contextsize = 20
        
        if not self.context:
            self.contextsize = 0
            
        self.userhelp = self._("""
= Help =
 
== Regulare expressions ==

 alternation:: A vertical bar separates alternatives. For example, "gray|grey", which could be shortened to the equivalent "gr(a|e)y", can match "gray" or "grey".
 grouping:: Parentheses are used to define the scope and precedence of the operators. For example, "gray|grey" and "gr(a|e)y" are different patterns, but they both describe the set containing gray and grey.
 quantification:: [[BR]]A quantifier after a character or group specifies how often that preceding expression is allowed to occur. The most common quantifiers are ?, *, and +:[[BR]]'''?''' The question mark indicates there is 0 or 1 of the previous expression. For example, "colou?r" matches both color and colour.[[BR]]'''*''' The asterisk indicates there are 0, 1 or any number of the previous expression. For example, "go*gle" matches ggle, gogle, google, gooogle, etc.[[BR]]'''+''' The plus sign indicates that there is at least 1 of the previous expression. For example, "go+gle" matches gogle, google, gooogle, etc. (but not ggle).

''for detailt look at: [http://en.wikipedia.org/wiki/Regular_Expressions Wikipedia]''
== Wildcard character ==
 The asterisk (*) usually substitutes as a wildcard character for any zero or more characters, and the question mark (?) usually substitutes as a wildcard character for any one character

''for detailt look at: [http://en.wikipedia.org/wiki/Wildcard_character Wikipedia]''
""")
        
        self.lang_dict = {
                          ##Headlines
                          u"title_searchtext_text" : self._('''Search Text'''),
                          u"title_findandreplace_text" : self._( '''find and replace''' ),
                          
                          ##Menu Text
                          u"text_raw_text" : self._('''Raw'''),
                          u"text_method_text" : self._('''Methode:'''),
                          u"text_option_text" : self._('''Options:'''),
                          u"text_context_text" : self._('''Display context of search results'''),
                          u"text_search_text" : self._( '''Find what''' ),
                          u"text_replace_text" : self._( '''Replace with''' ),
                          u"text_text_text" : self._( '''Fixed string''' ),
                          u"text_word_text" : self._( '''Whole words''' ),
                          u"text_wildcards_text" : self._( '''Wildcard character''' ),
                          u"text_casesensitive_text" : self._( '''Case-sensitive''' ),
                          u"text_regularexpression_text" : self._( '''Regular expressions'''),
                          u"text_Wrap search_text" : self._('''Wrap search'''),
                          u"text_comment_text" : self._('''Comment'''),
                          u"text_multiline_text" : self._('''Multiline'''),
                          u"text_searchonly_text" : self._('''Search only'''),
                          u"text_notsaved_text" : self._('''Your changes are not saved!'''),
                          u"text_saved_text" : self._('''Thank you for your changes. Your attention to detail is appreciated.'''),
                          u"text_trivial_text" : self._('''Trivial change'''),
                          u"text_langcomment_text" : self._('''"%s" replaced by "%s"'''),
                          u"text_showraw_text" : self._('''Show raw Text'''),

                          u"text_match_text" : self._('''%(matchcount)d %(matches)s for "%(title)s"'''),
                          
                          ##Buttons
                          u"highlight_button" : self._( '''Highlight on/off''' ),
                          u"search_button" : self._( '''Search''' ),
                          u"cancel_button" : self._( '''Cancel''' ),
                          u"preview_button" : self._( '''Preview''' ),
                          u"replaceall_button" : self._( '''Replace all''' ),
                          u"replaceselected_button" : self._( '''Replace selected''' ),
                          u"help_button" : self._('''help'''),
                          u"about_button" : self._('''about''' )
                          }
        
        self.regex_dict = { u'%3F' : u'?',
                      }
        
        self.wildcard_dict = { u'''?''' : u'''.''',
                          u'''*''' : u'''.*?''' }
        
        self.normal_dict = { ##u'''\\''' : u'''\\\\''',
                        u'''.''' : u'''\\.''',
                        u'''*''' : u'''\\*''',
                        u'''[''' : u'''\\[''',
                        u''']''' : u'''\\]''',
                        u'''(''' : u'''\\(''',
                        u''')''' : u'''\\)''' }
        
        if self.form.has_key(u"help_button" ):
            self.generateHelpMessage()
            
        if self.form.has_key(u"about_button" ):
            self.generateAboutMessage()

        ##Search Action
        if not self.find and not self.replace:
            msg = self.generateSearchDialog()
            page = Page(self.request, self.referrer )
            page.send_page(self.request, msg=msg )
            return ''

        if self.form.has_key(u"highlight_button") or self.form.has_key(u"search_button") or self.form.has_key(u"selected_button") or self.form.has_key(u"preview_button") or self.form.has_key(u"all_button"):
            
            if self.request.user.may.read(self.currentusername):
                self.getFindRegex()
                
                if self.form.has_key(u"highlight_button") or self.form.has_key(u"search_button"):
                
                    oldtext = self.getPageText( self.referrer)
                    results = self.findallResults( oldtext )
                    if not results:    
                        msg = self.generateNoResultMessage()
                        page = Page(self.request, self.referrer )
                        page.send_page(self.request, msg=msg )
                        return ''
                    else:
                        p = Page(self.request, self.referrer)
                        rev = p.get_real_rev()
                        msg = self.generateReplaceDialog( rev, results )
                        
                        page = Page(self.request, self.referrer )
                        page.send_page(self.request, msg=msg )
                        return u""
    
                if not self.comment:
                    self.comment = (u'''%(text_langcomment_text)s''' % self.lang_dict) % ( self.find, self.replace )
                
                p = Page(self.request, self.referrer)
                newrev = p.get_real_rev()
                
                rev = int(self.form.get( u"rev", 0 )[0])
                
                if rev == newrev:
                    self.oldtext = self.getPageText(self.referrer)
                else:
                    query = {'action': 'findandreplace'}
                    url = Page(self.request, self.referrer).url(self.request, query, 0)
                    self.request.http_redirect(url)
                
                newtext = 0
                
                if self.form.has_key( u"all_button" ):
                    newtext = self.replaceAll()
                
                elif self.form.has_key( u"selected_button" ):
                    if self.selected:
                        newtext = self.replaceSelected()                    
                else:
                    return 0
    
                if newtext == 0 or newtext == self.oldtext: 
                    query = {'action': 'show'}
                    url = Page(self.request, self.referrer).url(self.request, query, 0)
                    self.request.http_redirect(url)
                
            page = PageEditor.PageEditor(self.request, self.referrer, do_editor_backup=0)  
            newtext = page.normalizeText(newtext)           
            p = Page(self.request, self.referrer)
            print rev
            rev = int(newrev )
            print rev
            try:
                page.saveText(newtext, rev, comment=self.comment, trivial=self.trivial)
                msg = "%(text_saved_text)s" % self.lang_dict
            except:
                msg = "%(text_notsaved_text)s" % self.lang_dict
            page = Page(self.request, self.referrer )
            page.send_page(self.request, msg=msg )
    
        return ''
    
    def getFindRegex(self):

        self.findregex = self.find
        if self.methode == "regex":
            for entry in self.regex_dict:
                self.findregex = self.findregex.replace( entry, self.regex_dict[entry] )
                
        elif self.methode == "wildcards":
            for entry in self.wildcard_dict:
                self.findregex = self.findregex.replace( entry, self.wildcard_dict[entry] )
                
        else:
            for entry in self.normal_dict:
                self.findregex = self.findregex.replace( entry, self.normal_dict[entry] )
        if self.word == "1":
            self.findregex = u'\\b%s\\b' % self.findregex
            
        if not self.casesensitive:
            ignorcase = "i"
        else:
            ignorcase = ""
            
        if self.multiline:
            multiline = u"sm"
        else:
            multiline = u""
        
        if multiline or ignorcase:
            pattern = u"(?%(m)s%(i)s)" % {u"i" : ignorcase,
                                             u"m" : multiline }
        else:
            pattern = ""
            
        self.findregex = u"%(p)s%(f)s" % { u"p" : pattern, u"f" : self.findregex}
    
    def getPageText(self, pagename ):
        oldtext = PageEditor.PageEditor(self.request, pagename , do_editor_backup=0)
        return oldtext.get_raw_body()
    
    def replaceSelected(self):
        pattern = re.compile( self.findregex)
        resultlist = pattern.findall( self.oldtext)#, self.casesensitive )
        index = 0
        newtext = self.oldtext
        pos1 = newtext.find(resultlist[0])
        for result in resultlist:
            pos2 = newtext[pos1:].find(result)
            pos2 = pos1 + len(result)
            if str(index) in self.selected:               
                newtext = newtext[:pos1] + self.replace + newtext[pos2:]
            pos1 = pos2 + newtext[pos2:].find(result)
            index += 1
        return newtext
    
    def replaceAll(self):
        newtext=re.sub(self.findregex, self.form.get(u"replace",[u""])[0], self.oldtext )
        return newtext  
      
    def parsText( regex, source ):
        variable = re.search( regex, source )
        regex = regex.replace('\+|\.', '.')
        if variable != None:
            variable = variable.group( 1 )
            value = variable.decode("iso-8859-1")
        else:
            value = u"N/A"
        return value
    
    def findallResults(self, text ):
        pattern = re.compile( self.findregex)#, self.casesensitive )
        resultList = pattern.findall( text)
        pos = 0
        newresultList = []
        for result in resultList:
            pos = text.find(result,pos)
            if pos > self.contextsize:
                pos1 = pos - self.contextsize
            else:
                pos1 = 0
            pos2 = pos + len(result) + self.contextsize
            newresultList.append( (text[pos1:pos], result,text[pos+len(result):pos2]) ) 
            pos += len(result) +1
        return newresultList
        
    def generateReplaceDialog( self, rev, list ):
        html =[]
        if len(list) > 1:
            matches = self._("""matches""")
        else:
            matches = self._("""match""")
        html.append(( u'<b>"%(text_match_text)s</b><br><br>' % self.lang_dict) % { u"title" : self.find, u"matchcount" : len( list ), u"matches" : matches } )
        html.append(u'<form method="post" action="">')
        index = 0
        for entry in list:
            html.append('''<p>''')
            if not self.searchonly:
                html.append( u'<input type="checkbox" name="selected" value="%(index)s">' % { u"index" : index } )
            html.append( u'...%s<strong class="highlight">%s</strong>%s ...</p>' % ( entry[0], entry[1], entry[2] ) )
            index += 1
            
            
        if self.showraw:
            pagetext = self.getPageText(self.referrer)
            html.append("""<b>%(text_raw_text)s</b></br>""" % self.lang_dict)
            html.append("""<pre>\n%s\n</pre>""" % pagetext )
            
        if not self.searchonly:
            html.append( '''<p>%(text_replace_text)s''' % self.lang_dict )
            html.append( '''<input type="text" name="replace" size="20" value="%(replace)s"></p>''' % { u"replace" : self.replace })
        
        print self.trivial
        if self.trivial:
            trivialchecked = u"checked=checked"
            
        else:
            trivialchecked = u""
        
        html.append( '''%(text_comment_text)s <input type="text" size="20" name="comment" value="%(comment)s">
        %(text_trivial_text)s <input type="checkbox" name="trivial" value="1" %(trivialchecked)s>''' % { 
                                                                                      u"trivialchecked" : trivialchecked,
                                                                                      u"comment" : self.comment,
                                                                                      u"text_comment_text" : self.lang_dict[u"text_comment_text"],
                                                                                      u"text_trivial_text" : self.lang_dict[u"text_trivial_text"]  } )
        
        html.append( '''<input type="hidden" name="replace" value="%(replace)s"> 
        <input type="hidden" name="rev" value="%(rev)d">
        <input type="hidden" name="find" value="%(find)s">
        <input type="hidden" name="word" value="%(word)s"> 
        <input type="hidden" name="methode" value="%(methode)s">
        <input type="hidden" name="highlight" value="%(findregex)s">
        <input type="hidden" name="showraw" value="%(showraw)s">
        <input type="hidden" name="multiline" value="%(multiline)s">
        <input type="hidden" name="searchonly" value="%(searchonly)s">
        </p>''' % {             u"replace" : self.replace,
                                u"rev" : rev,
                                u"find" : self.find,
                                u"word" : self.word,
                                u"methode" : self.methode,
                                u"context" : self.context,
                                u"findregex" : self.highlight,
                                u"multiline" : self.multiline,
                                u"searchonly" : self.searchonly,
                                u"showraw" : self.showraw,
                                } )
        html.append('''<p>''')
        
        if not self.searchonly:
            html.append( '''<input type="hidden" name="action" value="findandreplace">
            <input type="submit" name="preview_button" value="%(preview_button)s">''' % self.lang_dict)
            
            html.append( '''<input type="submit" name="selected_button" value="%(replaceselected_button)s">
            <input type="submit" name="all_button" value="%(replaceall_button)s">''' % self.lang_dict )
            
        html.append( '''<input type="submit" name="cancel_button" value="%(cancel_button)s"></p>
            ''' % self.lang_dict)
        
        html.append( '''</div></form>''')
        
        if not self.highlight:
            self.highlight = self.findregex
        else:
            self.highlight = u""        
        
        html.append( '''<form method="post" action="">
        <input type="hidden" name="replace" value="%(replace)s"> 
        <input type="hidden" name="rev" value="%(rev)d">
        <input type="hidden" name="find" value="%(find)s">
        <input type="hidden" name="word" value="%(word)s"> 
        <input type="hidden" name="methode" value="%(methode)s">
        <input type="hidden" name="highlight" value="%(findregex)s">
        <input type="hidden" name="comment" value="%(comment)s">
        <input type="hidden" name="multiline" value="%(multiline)s">
        <input type="hidden" name="searchonly" value="%(searchonly)s">
        <input type="hidden" name="showraw" value="%(showraw)s">
        </p>''' % {             u"replace" : self.replace,
                                u"rev" : rev,
                                u"find" : self.find,
                                u"word" : self.word,
                                u"methode" : self.methode,
                                u"comment" : self.comment,
                                u"context" : self.context,
                                u"findregex" : self.highlight,
                                u"multiline" : self.multiline,
                                u"searchonly" : self.searchonly,
                                u"showraw" : self.showraw
                                } )
        if self.trivial:
            html.append( """<input type="hidden" name="trivial" value="1">"""  )
                         
        if self.casesensitive:
            html.append( '''<input type="hidden" name="casesensitive" value="%(casesensitive)s">''' % {u"casesensitive" : self.casesensitive,}   )
        
        if self.context:
            html.append( '''<input type="hidden" name="context" value="%(context)s">''' % {u"context" : self.context, } )
        
        html.append( '''<input type="hidden" name="action" value="findandreplace">
        <input type="submit" name="highlight_button" value="%(highlight_button)s"></form>
        ''' % self.lang_dict)
        return Dialog (self.request, content=u"\n".join( html ) )
    
    def generateNoResultMessage( self ):
        return self._(u'''Nothing found for "%s"!''') %(self.find)
    
    def generateSearchDialog(self):
        
        html =  u'''<b>%(title_findandreplace_text)s</b><br/>
            %(title_searchtext_text)s<br/>
            <form method="get" action=""><div>
            <input type="hidden" name="action" value="findandreplace">
            <table border=0px>
            <tr>
            <td align="right" valign="middle">
                %(text_search_text)s: <input type="text" name="find" size="20"><br/>
                %(text_replace_text)s: <input type="text" name="replace" size="20"><br/>
                %(text_comment_text)s: <input type="text" name="comment" size="20">
            </td>
             <td align="left" valign="middle">
             <p>%(text_option_text)s</p>
             <input type="checkbox" name="word" value="1">
             %(text_word_text)s<br/>
              <input type="checkbox" name="multiline" value="1">
             %(text_multiline_text)s<br/>
             <input type="checkbox" name="casesensitive" value="1">
             %(text_casesensitive_text)s<br/>
             <input type="checkbox" name="context" value="1">
             %(text_context_text)s<br/>
             <input type="checkbox" name="showraw" value="1">
             %(text_showraw_text)s<br/>
             <input type="checkbox" name="trivial" value="1">
             %(text_trivial_text)s<br/>
             </td>
             <td>
             <p>%(text_method_text)s</p>
             <input type="radio" name="methode" value="none" checked="checked">
             %(text_text_text)s<br/>
             <input type="radio" name="methode" value="wildcards">
             %(text_wildcards_text)s<br/>
             <input type="radio" name="methode" value="regex">
             %(text_regularexpression_text)s<br/>
             </td>
             </tr>
             <tr>
             <td valign="bottom">
             <p><input type="checkbox" name="searchonly" value="1"> %(text_searchonly_text)s</p>
             <input type="submit" name="search_button" value="%(search_button)s">
             <input type="submit" name="cancel_button" value="%(cancel_button)s">
             
             <input type="submit" name="help_button" value="%(help_button)s">
             <input type="submit" name="about_button" value="%(about_button)s">
             </td>
             </tr>
             </table>
            </div></form><br>
            ''' % self.lang_dict
        
        return Dialog (self.request, content=html)
    
    def generateHelpMessage(self):
        msg = self.userhelp
        page = Page(self.request, self.referrer )
        page.send_page(self.request, msg=msg )
        
    def generateAboutMessage(self):
        msg = "<pre>%s</pre>" % __doc__
        page = Page(self.request, self.referrer )
        page.send_page(self.request, msg=msg )

        
def execute( pagename, request ):
    return FindAndReplaceAction( request, pagename ).render()