"""A Trac syntax highlighting module for Lisp.
"""

from __future__ import generators

import sys

import re

from trac.core import *
from trac.mimeview.api import IHTMLPreviewRenderer
from trac.web.chrome import add_stylesheet

from xmlrpclib import *

__all__ = ['LispRenderer']

types = [
  'text/x-lisp'
  ]


COLORIZER_URL = "http://localhost:8080/RPC2"
CACHE_SIZE = 50


class LRUCache:
    """
    Implementation of a length-limited O(1) LRU queue.
    Built for and used by PyPE:
    http://pype.sourceforge.net
    Copyright 2003 Josiah Carlson.
    From http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252524
    """

    class Node:
        def __init__(self, prev, me):
            self.prev = prev
            self.me = me
            self.next = None

    def __init__(self, count, pairs=[]):
        self.count = max(count, 1)
        self.d = {}
        self.first = None
        self.last = None
        for key, value in pairs:
            self[key] = value

    def __contains__(self, obj):
        return obj in self.d

    def __getitem__(self, obj):
        a = self.d[obj].me
        self[a[0]] = a[1]
        return a[1]

    def __setitem__(self, obj, val):
        if obj in self.d:
            del self[obj]
        nobj = self.Node(self.last, (obj, val))
        if self.first is None:
            self.first = nobj
        if self.last:
            self.last.next = nobj
        self.last = nobj
        self.d[obj] = nobj
        if len(self.d) > self.count:
            if self.first == self.last:
                self.first = None
                self.last = None
                return
            a = self.first
            a.next.prev = None
            self.first = a.next
            a.next = None
            del self.d[a.me[0]]
            del a

    def __delitem__(self, obj):
        nobj = self.d[obj]
        if nobj.prev:
            nobj.prev.next = nobj.next
        else:
            self.first = nobj.next
        if nobj.next:
            nobj.next.prev = nobj.prev
        else:
            self.last = nobj.prev
        del self.d[obj]

    def __iter__(self):
        cur = self.first
        while cur != None:
            cur2 = cur.next
            yield cur.me[1]
            cur = cur2

    def iteritems(self):
        cur = self.first
        while cur != None:
            cur2 = cur.next
            yield cur.me
            cur = cur2

    def iterkeys(self):
        return iter(self.d)

    def itervalues(self):
        for i,j in self.iteritems():
            yield j

    def keys(self):
        return self.d.keys()


def testCache():
  cache = LRUCache(3)
  cache[0] = True
  cache[1] = True
  cache[2] = True
  print 0 in cache
  print 1 in cache
  print 2 in cache
  print not (3 in cache)
  print cache[0]
  print cache[1]
  print cache[2]
  cache[3] = True
  print not (0 in cache)
  


class LispRenderer(Component):
    """Syntax highlighting for Lisp."""

    implements(IHTMLPreviewRenderer)

    cache = LRUCache(CACHE_SIZE)
    cache_hits = 0
    cache_misses = 0
    
    def get_quality_ratio(self, mimetype):
        #sys.stderr.write("Considering %s\n" % (mimetype,))
        if mimetype in types:
            #sys.stderr.write("It's lisp!\n")
            return 4
        return 0

    def render(self, req, mimetype, content, filename=None, rev=None):
        #sys.stderr.write("Rendering lisp\n")
        cache_key = content
        try:
            add_stylesheet(req, 'common/css/lisp.css')
            if not (cache_key in self.cache):
                colorizer = ServerProxy(COLORIZER_URL)
                html = colorizer.colorize("lisp", content, 0)
                html = html.replace("\n", "")
                html = html.replace("<br>", "\n")
                html = html.splitlines()
                self.cache[cache_key] = html
                self.cache_misses = self.cache_misses + 1
                sys.stderr.write("Lisp rendering cache hits: %s  misses: %s\n" % (self.cache_hits, self.cache_misses))
                return html
            else:
                self.cache_hits = self.cache_hits + 1
                html = self.cache[cache_key]
                sys.stderr.write("Lisp rendering cache hits: %s  misses: %s\n" % (self.cache_hits, self.cache_misses))
                return html
        except Exception, e:
            sys.stderr.write("Got exception: %s" % (e,))
            raise e
