"""
Simple commenting middleware for WSGI applications.

wsgiComment wraps responses to upstream WSGI requests in its own
iterator, and then returns formatted comments at the end of the
downstream response.  Comments are presumed to be stored with
reference to PATH_INFO, i.e. the tail end of the URL after it's
been passed into WSGI.

See comments_config for the machinery to load and format individual
comments.

Future refactoring will probably push the 'format_comments'
functionality into another file.  @CTB
"""

import comments_config
import urllib

class _commentIter:
    """
    Iterator class to wrap downstream responses with comments.
    """
    def __init__(self, result, path, comments, flag):
        if hasattr(result, 'close'):
            self.close = result.close

        self.path = path
        self._next = iter(result).next
        self.finished = False
        self.comments = comments
        self.is_html_flag = flag
        
    def __iter__(self):
        "I am Iter."
        return self

    def next(self):
        """
        Part of the iterator machinery: get the next chunk o' text.
        Once we're done with chunks, add formatted comments to the end
        of the output.
        """
        if not self.finished:
            try:
                return self._next()
            except StopIteration:
                self.finished = True
                return self.format_comments()

        raise StopIteration("finished")

    def format_comments(self):
        """
        Called after each page is sent; adds comments to the bottom.
        """
        if not self.is_html_flag:       # only comment text/html docs.
            return ""

        path = self.path
        if not path:
            return ""

        path = urllib.quote_plus(path)  # escape the path properly.

        #
        # grab all of the comments & format them appropriately.
        #
        
        comments = self.comments
        s = "<hr><hr><center><h2>Reader's Comments</h2></center>"
        if not comments:
            s += "<i>no comments yet</i>"
        else:
            comment_text = [ c.format() for c in comments ]
            s += "<div>" + "</div><div>".join(comment_text) + "</div>"

        s += "<hr>"
        s += """\
<form method=POST action=%s>
<b>Add a comment.</b>
<p>
Your name: <input type=text name=name value="Anonymous"><br>
Web page: <input type=text name=webpage value=""><p>
Comment:<br>
<textarea rows=10 cols=80 name=comment>
</textarea>
<p>
<input type=submit name=submit value='add comment'>
<input type=hidden name=path value=%s>
</form>
""" % (comments_config.post_url, urllib.quote_plus(path),)

        return s

class wsgiComment:
    """
    A simple commenting middleware class for WSGI; wraps a given wsgi app
    & attaches comments grouped by PATH_INFO.

    See _commentIter class & comments_config for more information.
    """
    
    def __init__(self, app):
        """
        Constructor: takes app to wrap.
        """
        self.app = app

    def __call__(self, environ, start_response):
        """
        Called for each request.
        """
        path = environ['PATH_INFO'].lstrip('/')
        inp = environ['wsgi.input']

        # get comments.
        comment_dict = comments_config.load_comments()
        comments = comment_dict.get(path, [])

        # my_start_response:
        #   wraps the given 'start_response' function
        #   to intercept the headers & flag as to whether or not this is
        #   an HTML page ==> suitable for comment appendage.  use
        #   'is_html' as a signal; make it a dict for pass-by-ref
        #   reasons.
        
        is_html = {}
        def my_start_response(code, headers):
            code = int(code.split(' ')[0]) # convert code into integer
	    if code == 200:                # good response!  keep it up.
                for (k, v) in headers:
                    if k.lower() == 'content-type':
                        if v == 'text/html':
                            is_html[0] = True
                        break

            return start_response(code, headers)
        # end my_start_response

        # OK, create an iterator with all this info & return it.
        
        iter = _commentIter(self.app(environ, my_start_response),
                            path, comments, is_html)

        return iter
