#! /usr/bin/python

import sys
from socket import *
import BaseHTTPServer
import libxml2
import libxslt
import re
import urllib

class myHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    def query(self,q):

        style  = createStylesheet(q)
        doc = libxml2.parseFile( blogfile )

        try:
            result = style.applyStylesheet(doc, None)
            strResult = style.saveResultToString(result)
        except:
            page = "bad query: %s" % q

        if ( page != None ):

            css = getCss()
            script = getScript()
            preamble = getPreamble(q)

            page = """
    <html><head><title>XPath query of Jon's Radio</title><style>%s</style>
    <script>%s</script></head><body>%s %s</body></html>
    """ % (css, script, preamble, strResult)

            style.freeStylesheet()
            doc.freeDoc()
            result.freeDoc()

            return page

    def do_GET(self):
        xhtml = self.send_head()
        self.wfile.write(xhtml)

    def send_head(self):
        q = self.requestline.split()[1]
        q = re.sub('^/\?','',q)
        q = urllib.unquote(q)
        xhtml = self.query(q)

        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", len(xhtml))
        self.end_headers()

        if ( len (xhtml) < maxchars ):
            return xhtml
        else:
	    return "query returned more than %d characters" % maxchars

def getXsltTemplate():
    return '''<?xml version="1.0"?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
<div>Results:
<xsl:value-of select="count(__QUERY__)"/>
</div>
<xsl:apply-templates />
</xsl:template>

<xsl:template match="__QUERY__" >
<p><b>
<a>
<xsl:attribute name="href">
http://weblog.infoworld.com/udell/<xsl:value-of select="ancestor::item/date" />.html#<xsl:value-of select="ancestor::item/@num"/>
</xsl:attribute>
<xsl:value-of select="ancestor::item/title" />
</a> (<xsl:value-of select="ancestor::item/date" />)
</b>
<div>
<xsl:copy-of select="."/>
<xsl:if test="local-name(.)='blockquote' and @cite != ''">
Source: <xsl:value-of select="@cite"/>
</xsl:if>
</div>
<hr align="left" width="20%" />
</p>
</xsl:template>

<xsl:template match="text()"/>

</xsl:stylesheet>
'''

def getPreamble(q):
    preamble =  '''
<table>
<tr>
<td>choose xpath query from list, modify/reenter below</td>
<td width="5%"></td>
<td>all paragraphs containing phrase</td>
</tr>
<tr>
<td align="left" valign="top">
<form name="queryList" method="post">
<select name="q" onChange="javascript:transform(document.queryList.q.value)">
<option value="/">------------------------------------ choose your query -------------------------------</option>
<option value="//blockquote[@cite]">quotes</option>
<option value="//table[count(.//tr)>5]">tabular data</option>
<option value="//a[contains(@href,'amazon.com') or contains(@href,'allconsuming')]">books</a>
<option value="//blockquote[@cite='Ward Cunningham']">Ward Cunningham quotes</option>
<option value="//dl[@class='definition']">definitions</option>
<option value="//*[@class='minireview']">minireviews</option>
<option value="//*[@class='tip']">tips</option>
<option value="//p/a[contains(@href,'.mov')]">QuickTime movies</option>
<option value="//*[@class='code' and @lang='python']">python snippets</option>
<option value="//*[@class='code' and @lang='javascript']">javascript snippets</option>
<option value="//*[@class='code' and @lang='xquery']">xquery snippets</option>
<option value="//*[@class='code' and @lang='xslt']">xslt snippets</option>
<option value="//*[@class='code' and @lang='usertalk']">usertalk snippets</option>
<option value="//*[@class='code' and @lang='xslt' and contains( ., 'xsl:copy')]">xslt snippets that contain 'xsl:copy'</option>
<option value="//body//a[contains(@href , 'bray')]">links with URL containing 'bray'</option>
<option value="//body//a[contains(./text() , 'bray')]">links with text containing 'bray'</option>
<option value="//body//a[contains(  translate ( text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'bray')]">links with text containing 'bray', case-insensitive</option>
<option value="//body[contains ( . , 'XPath search' )]">complete entries containing the phrase 'XPath search'</option>
<option value="//body//img[contains(@src, 'zope')]">image references containing 'zope'</option>
</select>
</form>
<form name="queryBox" method="post" action="javascript:transform(document.queryBox.q.value)">
<input name="q" size="65" value="__QUERY__">
</form>
</td>
<td></td>
<td align="left" valign="top">
<form name="queryAny" method="post" action="javascript:transform('//body//p[contains ( . , \\'' +  document.queryAny.q.value +  '\\')]') "> 
<input name="q" size="20" >
</form>
</td></tr></table>'''
    preamble = preamble.replace('__QUERY__', q)
    option = '<option value="%s">' % q
    optionSelected = '<option value="%s" selected>' % q
    preamble = preamble.replace(option, optionSelected)
    return preamble

def getCss():
    return '''
p.tip {
margin-left: 50px;
margin-right: 50px;
font-size: 80%;
}
p.tip:before {
font-weight: bold;
content: "TIP: ";
}
pre {
white-space: pre;
}
.minireview {  
font-weight: bold;  
}
.minireview:before {
font-weight: bold;
content: "MINI-REVIEW: ";
}
blockquote {
font-style: italic;
}
td, p {
font-family: verdana,arial,sans-serif;
font-size: 12px;
}
body {
font-family: verdana,arial,sans-serif;
font-size: 12px;
margin-left: 5%;
margin-right: 5%;
}
dl { 
border-style: solid;
border-width: thin;
padding: 10px;
}
.term { font-weight: bold }
dt:before {
font-style: italic;
content: "term:
}
'''

def getScript():
    return '''
function transform(query) {
document.queryBox.q.value = query;
location  = "http://%s:%s/?" + query;
}  
''' % (externalhost, port) 

def createStylesheet(q):
    styledoc = libxml2.parseDoc( getXsltTemplate() )
    ctxt = styledoc.xpathNewContext()
    ctxt.xpathRegisterNs('xsl','http://www.w3.org/1999/XSL/Transform')

    xpath = "//xsl:template//xsl:value-of[@select='count(__QUERY__)']"
    nodelist = ctxt.xpathEval(xpath)
    nodelist[0].setProp('select', 'count(%s)' % q)

    xpath = "//xsl:template[@match='__QUERY__']"
    nodelist = ctxt.xpathEval(xpath)
    nodelist[0].setProp('match', q)

    style = libxslt.parseStylesheetDoc(styledoc)

    ctxt.xpathRegisteredNsCleanup()
    ctxt.xpathFreeContext()

    return style

def run(port,HandlerClass = myHTTPRequestHandler, 
        ServerClass = BaseHTTPServer.HTTPServer, protocol="HTTP/1.1"):

    server_address = ('', port)
    HandlerClass.protocol_version = protocol
    httpd = ServerClass(server_address, HandlerClass)

    sa = httpd.socket.getsockname()
    print "Serving HTTP on", sa[0], "port", sa[1], "..."
    httpd.serve_forever()

if __name__ == '__main__':
    maxchars = 250000
    if sys.argv[1:]:
        externalhost = sys.argv[1]
    else:
        externalhost = 'localhost'
    if sys.argv[2:]:
        port = int(sys.argv[2])
    else:
        port = 8000
    if sys.argv[3:]:
        blogfile = sys.argv[3]
    else:
        blogfile = '/radio/www/gems/blog.xml'

    run(port)

