import sys
import gdbm
import mailarch
import urllib
import cgi
import SimpleHTTPServer
import BaseHTTPServer
import rfc822
import StringIO
import string

__version__ = "0.2"

DBNAME = "annobase"

EXPLANATION = """
<UL>
<LI>To see a message in full, click on its subject.
<LI>To select all messages by an author, click on the address.
<LI>To see the referenced document, click on its URL.
</UL>
"""

NO_HITS = """
Your query found no matching entries in the annotation database.
Try giving a less selective query pattern.
"""


class MyArchive(mailarch.Archive):

    indices = mailarch.Archive.indices + ['keywords', 'link']

    def __init__(self, mode='c', dir='.', name='annobase'):
	mailarch.Archive.__init__(self, mode, dir, name)



class MyServer(BaseHTTPServer.HTTPServer):

    def __init__(self, server_address, RequestHandlerClass):
	BaseHTTPServer.HTTPServer.__init__(
	    self, server_address, RequestHandlerClass)
	self.db = MyArchive()


class AnnotationRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):

    dbname = DBNAME

    server_version = "Annotation/" + __version__

    explanation = EXPLANATION

    no_hits = NO_HITS

    def do_POST(self):
	id = self.server.db.append(self.rfile)
	url = "http://%s:%d/?message=%s" % (self.server.server_name,
					 self.server.server_port,
					 id)
	self.send_response(201, url)
	self.end_headers()

    def do_GET(self):
	o = self.wfile
	basepath, query = urllib.splitquery(self.path)
	if not query:
	    self.send_error(501, "no query specified")
	    return
	dict = cgi.parse_qs(query or '')
	if not dict:
	    self.send_error(501, "empty query")
	    return
	if dict.has_key('message'):
	    if len(dict) > 1:
		self.send_error(501, "message key should occur alone")
		return
	    ids = dict['message']
	    if len(ids) != 1:
		self.send_error(501, "please request exactly one message")
		return
	    id = ids[0]
	    try:
		text = self.server.db.get(id)
	    except KeyError:
		self.send_error(404, "message id not in database")
		return
	    self.send_response(200)
	    self.send_header("Content-type", "text/html")
	    self.end_headers()
	    self.format_message(text, id)
	    return
	for key in dict.keys():
	    if key not in self.server.db.indices:
		self.send_error(501, "unrecognized query key %s" % `key`)
		return
	results = None
	for key in dict.keys():
	    tmp = {}
	    for value in dict[key]:
		tmp = union(tmp, self.server.db.select(key, value))
	    if results is None:
		results = tmp
	    else:
		results = intersection(results, tmp)
	    if not results:
		break
	self.send_response(200)
	self.send_header("Content-type", "text/html")
	self.end_headers()
	if not results:
	    o.write(self.no_hits)
	    return
	o.write('Got %d hits.\n' % len(results))
	o.write(self.explanation)
	o.write('<UL>\n')
	infolist = []
	for id in results.keys():
	    text = self.server.db.get(id)
	    m = rfc822.Message(StringIO.StringIO(text))
	    subject, fromm, date, link = getinfo(m)
	    infolist.append((subject, fromm, date, link, id))
	infolist.sort()
	for (subject, fromm, date, link, id) in infolist:
	    qid = urllib.quote(id)
	    o.write('<LI>Subject: <A HREF="?message=%s">' % qid)
	    o.write('<B>%s</B>' % cgi.escape(subject))
	    o.write('</A>\n')
	    qfromm = urllib.quote(fromm)
	    efromm = cgi.escape(fromm)
	    o.write('<BR>From: <A HREF="?from=%s">%s</A>\n' %
		    (qfromm, efromm))
	    o.write('<BR>Date: %s\n' % cgi.escape(date))
	    elink = cgi.escape(link)
	    o.write('<BR>Link: <A HREF="%s">%s</A>\n' % (elink, elink))
	    o.write('<P>\n')
	o.write('</UL>\n')

    def format_message(self, text, id):
	o = self.wfile
	f = StringIO.StringIO(text)
	m = rfc822.Message(f)
	bodytext = f.read()
	subject, fromm, date, link = getinfo(m)
	o.write('Subject: <B>%s</B><BR>\n' % cgi.escape(subject))
	o.write('From: %s<BR>\n' % cgi.escape(fromm))
	o.write('Date: %s<BR>\n' % cgi.escape(date))
	o.write('Link: <A HREF="%s">%s</A><BR>\n' %
		(link, cgi.escape(link)))
	o.write('<PRE>\n')
	o.write(cgi.escape(bodytext))
	o.write('</PRE>\n')

def getinfo(m):
    if m.has_key('subject'):
	subject = m['subject']
    else:
	subject = ''
    if m.has_key('from'):
	fromm = m['from']
    else:
	fromm = ''
    if m.has_key('date'):
	date = m['date']
    else:
	date = ''
    if m.has_key('link'):
	link = m['link']
    else:
	link = ''
    return subject, fromm, date, link

def union(a, b):
    c = {}
    for k in a.keys() + b.keys():
	c[k] = k
    return c

def intersection(a, b):
    c = {}
    for k in a.keys():
	if b.has_key(k):
	    c[k] = k
    return c


def test(HandlerClass = AnnotationRequestHandler,
	 ServerClass = MyServer):
    import sys
    if sys.argv[1:2] == ['-r']:
	db = MyArchive()
	db.regenindices()
	return
    SimpleHTTPServer.test(HandlerClass, ServerClass)


if __name__ == '__main__':
    test()
