from Globals import DTMLFile
from Acquisition import Implicit
from Globals import Persistent
from AccessControl.Role import RoleManager
from OFS.SimpleItem import Item
from AccessControl import ClassSecurityInfo
import AccessControl
from hash import skeylike
import time

#from pyPgSQL import PgSQL as pg
import psycopg as pg
import string

import ppcode
pp = ppcode.PPDecode()

manage_addnewsForm = DTMLFile('www/addForm', globals())

def manage_addnewsAction(context, id='news', dsn='', title='News', desc='JIHI News System', topurl='', recentN=5, REQUEST=None, container_head='standard_html_header', container_tail='standard_html_footer',lang='en-US'):
    "Instantiate a new JIHI news system."
    context._setObject(id, News(id, title, desc, topurl, dsn, recentN, container_head, container_tail, lang))
    if REQUEST is not None:
        return context.manage_main(context, REQUEST)

class News(Implicit, Persistent, RoleManager, Item):
    "News Connection"

    security = ClassSecurityInfo()

    security.setPermissionDefault("Modify News", ("Manager",))
    security.declareProtected("Modify News", "DelComment")
    security.declareProtected("Modify News", "DelNews")
    security.declareProtected("Modify News", "DelNewsReally")
    security.declareProtected("Modify News", "EditNews")
    security.declareProtected("Modify News", "newsedit")

    security.setPermissionDefault("Create News", ("Manager",))
    security.declareProtected("Create News", "NewNews")
    security.declareProtected("Create News", "newssubmit")

    security.setPermissionDefault("Create Comments", ("Anonymous",))
    security.declareProtected("Create Comments", "NewNewsComment")
    security.declareProtected("Create Comments", "newscommentsubmit")

    security.setPermissionDefault("View News", ("Anonymous",))
    security.declareProtected("View News", "viewAllNews")
    security.declareProtected("View News", "viewNewsItem")
    security.declareProtected("View News", "viewNewsItemTag")
    security.declareProtected("View News", "viewRecentFeed")
    security.declareProtected("View News", "viewRecentNews")
    security.declareProtected("View News", "viewTagCloud")

    meta_type = "JIHI News"
    manage_options = (
        { 'label' : 'Properties', 'action' : 'manage_editForm'},
        { 'label' : 'View', 'action' : 'index_html' },
        ) + RoleManager.manage_options + Item.manage_options

    def __init__(self, id, title, description, topurl, dsn, recentN, container_head, container_tail, lang):
        "init."
        self.id = id
        self.dsn = dsn
        self.title = title
        self.description = description
        self.lang = lang
        self.topurl = topurl
        self.recentN = recentN


        self._v_connection = None

        self.container_head = container_head
        self.container_tail = container_tail

    def maybe_get_cursor(self):
        try:
            cursor = self._v_connection.cursor()
        except:
            try:
                self._v_connection = pg.connect(self.dsn)
            except Exception, inst:
                return False, inst
            try:
                cursor = self._v_connection.cursor()
            except Exception, inst:
                return None, inst
        return True, cursor

    def commit(self, cursor):
        cursor.close()
        self._v_connection.commit()
        return None

    def encode_html(self, text):
        return text.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;")

    def getPermMap(self):
        sm = AccessControl.getSecurityManager()
        permmap = {'view':sm.checkPermission("View News", self),'create':sm.checkPermission("Create News", self),'reply':sm.checkPermission("Create Comments",self),'modify':sm.checkPermission("Modify News",self)}
        return permmap

    manage_editForm = DTMLFile('www/editForm', globals())
    def manage_editAction(self, dsn, title, desc, topurl, lang, recentN, container_head, container_tail, force=False, RESPONSE=None):
        "Edit the News system."
        p_changed = False
        if dsn != self.dsn:
            self.dsn = dsn
            p_changed = True

        if title != self.title:
            self.title = title
            p_changed = True

        if desc != self.description:
            self.description = desc
            p_changed = True

        if topurl != self.topurl:
            self.topurl = topurl
            p_changed = True

        if lang != self.lang:
            self.lang = lang
            p_changed = True

        if recentN != self.recentN:
            self.recentN = recentN 
            p_changed = True

        if container_head != self.container_head:
            self.container_head = container_head
            p_changed = True
            
        if container_tail != self.container_tail:
            self.container_tail = container_tail
            p_changed = True

        if force:
            p_changed = True

        if p_changed:
            self._p_changed = 1
            self._v_connection = None

        RESPONSE.redirect('manage_editForm')

    newsitems_format_form = DTMLFile('www/newsitems', globals())
    tagcloud = DTMLFile('www/tagcloud', globals())

    def newsitems_format(self, **kw):
        kw['perms'] = self.getPermMap()
        return self.newsitems_format_form(**kw)
        
    norecords = DTMLFile('www/norecords', globals())
    newnewscomment = DTMLFile('www/newnewscomment', globals())

    def index_html(self,**kw):
        "the default view is viewRecentNews"
        return self.viewRecentNews(**kw)

    def DelComment(self, REQUEST=None, RESPONSE=None, **kw):
        """Delete a comment specified by id."""
        try:
            id = REQUEST.form['id']
        except:
            id = -1
        try:
            idredir = REQUEST.form['idredir']
        except:
            idredir = -1
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        curs.execute("""DELETE FROM comments WHERE id = %s""", (id,))
        curs = self.commit(curs)
        return RESPONSE.redirect('viewNewsItem?id=%s' % idredir)

    DelNews = DTMLFile('www/delnews',globals())
 
    def DelNewsReally(self, REQUEST=None, RESPONSE=None, **kw):
        """Finish deleting."""
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        try:
            id = REQUEST.form['id']
        except:
            id = -1

        curs.execute("""DELETE FROM tags WHERE id = %s""", (id,))
        curs.execute("""DELETE FROM comments WHERE newsitem = %s""", (id,))
        curs.execute("""DELETE FROM newsItems WHERE id = %s""", (id,))

        curs = self.commit(curs)
        return RESPONSE.redirect('/')

    editnews_form = DTMLFile('www/editnews', globals())
    def EditNews(self, REQUEST=None, **kw):
        """Edit some news aight."""
        try:
            id = REQUEST.form['id']
        except:
            id = -1

        recs = self.somenews(id=id)

        if len(recs) > 0:
            return self.editnews_form(recs=recs)
        else:
            return """<html><body>Uhhh</body></html>"""

    NewNews = DTMLFile('www/newnews',globals())

    def NewNewsComment(self, REQUEST=None, **kw):
        """Show a form to submit a new news comment."""
        try:
            id = REQUEST.form['id'].strip()
            recs = self.somenews(id=id)
            if len(recs) <= 0:
                raise Exception("What.")
        except:
            return """<html><body>Uhhh</body></html>"""

        return self.newsitems_format(title="New News Comment", recs=recs, showComments=True, noControls=True, extra=self.newnewscomment(nid=id, REQUEST=REQUEST, **kw),REQUEST=REQUEST, **kw)
        
    def somenews(self, count=-1, id=-1, tag=None, pageN=None, pageCount=None):
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))
        q = ''
        q2 = ''
        params = list()
        if pageN != None:
            perpage = pageCount
            page = pageN
            q = ' LIMIT %s OFFSET %s '
            params.append(perpage)
            params.append(int(page) * int(perpage))
        elif int(count) > 0:
            q = ' LIMIT %s '
            params.append(count)
        if tag != None:
            q2 = ' WHERE id in (SELECT id FROM tags WHERE tag = %s)'
            params.insert(0, tag)
        if int(id) >= 0:
            q2 = q2 + ' WHERE id = %s'
            params.insert(0,id)
        curs.execute("""SELECT * FROM newsItems """+q2+""" ORDER BY date DESC"""+q+';',params)
        out = list()
        items = curs.fetchall()
        descs = curs.description
        for i in items:
            item = dict(zip([x[0] for x in descs], i))
            item['comments'] = self.newscomments(item['id'])
            item['tags'] = self.newstags(item['id'])
            item['tags_formatted'] = string.join(item['tags'], ',');
            out.append(item)

        curs = self.commit(curs)
        return out

    def getPageInfo(self, pageCount, pageNumber, tag):
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))
        q = ''
        params = list()
        if tag != None:
            q = ' WHERE id in (SELECT id FROM tags WHERE tag = %s)'
            params.append(tag)
        curs.execute("""SELECT count(id) FROM newsItems"""+q+';',params)
        count = curs.fetchone()[0]
        outpginfo = list()
        maxpage = int(count / pageCount) - 1
        pagePrev = None
        pageNext = None
        pageOf = maxpage
        
        if (pageNumber != 0):
            pagePrev = str(pageNumber - 1)
        if (pageNumber < maxpage):
            pageNext = str(pageNumber + 1)

        return pagePrev, pageNext, pageOf

    def newscomments(self, id=0):
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        curs.execute("""SELECT * FROM comments WHERE newsitem = %s""", (id,))
        items = curs.fetchall()
        out = list()
        for i in items:
            out.append(dict(zip([x[0] for x in curs.description], i)))
        curs = self.commit(curs)
        return out

    def newstags(self, id=0):
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        curs.execute("""SELECT tag FROM tags WHERE id = %s""", (id,))
        items = curs.fetchall()
        out = list()
        for i in items:
            out.append(i[0])
        curs = self.commit(curs)
        return out

    def newscommentsubmit(self,REQUEST=None,RESPONSE=None,**kw):
        """Actually insert a new comment into the database."""
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        u = AccessControl.getSecurityManager().getUser()

        # unpack form data
        try:
            bod = REQUEST.form['body'].strip()
            post = REQUEST.form['poster'].strip()
            id = REQUEST.form['id'].strip()
            key = REQUEST.form['key'].strip()
            emal = REQUEST.form['email'].strip()
            bod2 = REQUEST.form['body2'].strip()
        except KeyError:
            return "<html><body>There was an error processing your submission.</body></html>"

        if (bod2 != ''):
            # filter out some spammers
            return "<html><body>You stinker!</body></html>"
        
        tripkey = ''
        if u.has_role('Anonymous'):
            if post != '':
                tripkey = skeylike(post+':'+key)
            else:
                return "<html><body>At least tell me who you are.</body></html>"
        else:
            tripkey = "actually"
            post = u.getUserName()

        # first convert comment from bbcode
        bodhtm = pp.decode(bod)
        # call it, passing arguments
        curs.execute("""INSERT INTO comments (body, body_bb, poster, email, date, newsitem, tripkey) VALUES (%s, %s, %s, %s, 'now', %s, %s)""", (bodhtm, bod, post, emal, id, tripkey))
        curs = self.commit(curs)

        # return a confirmation page
        return RESPONSE.redirect('viewNewsItem?id=%s' % id)
    
    def newssubmit(self, REQUEST=None, RESPONSE=None, **kw):
        """Submit news."""
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        u = AccessControl.getSecurityManager().getUser()
        
        # unpack form data
        try:
            subj = REQUEST.form['subject'].strip()
            bod = REQUEST.form['body'].strip()
            tags = REQUEST.form['tags'].strip()
        except:
            return "<html><body>There was an error processing your submission.</body></html>"


        # get id
        curs.execute("""SELECT nextval('newsItem_seq')""")
        id = curs.fetchall()[0][0]
        curs.execute("""INSERT INTO newsItems (body, poster, subject, date, id) VALUES (%s, %s, %s, 'now', %s)""", (bod, u.getUserName(), subj, id))
        for i in tags.split(','):
            if i.strip() != '':
                curs.execute("""INSERT INTO tags (id, tag) VALUES (%s, %s);""", (id, i.strip().lower()))

        curs = self.commit(curs)

        return RESPONSE.redirect('index_html')
            

    def taginfo(self):
        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        curs.execute("""SELECT tag, count(*) FROM tags GROUP BY tag;""");
        taginfo = dict()
        for res in curs.fetchall():
            taginfo[res[0]] = res[1]
        return taginfo

        
    def newsedit(self, REQUEST=None, RESPONSE=None, **kw):
        """Submit edits."""
        u = AccessControl.getSecurityManager().getUser()

        res, curs = self.maybe_get_cursor()
        if not res or res is None:
            raise Exception("Can't aquire cursor: %s." % str(curs))

        # unpack form data
        try:
            subj = REQUEST.form['subject']
            bod = REQUEST.form['body']
            id = REQUEST.form['id']
            tags = REQUEST.form['tags']
        except:
            return "<html><body>There was an error processing your submission.</body></html>"

        mark = 0
        try:
            mark = REQUEST.form['mark']
        except:
            mark = 0
            
        # call it, passing arguments
        if mark:
            bod += '<br /><br /><small><em>edited %s by %s</em></small>' % (time.strftime('%d %b %Y'), u.getUserName())
            
        curs.execute("""UPDATE newsitems SET subject = %s, body = %s WHERE id = %s;""", (subj, bod, id))

        curs.execute("""SELECT tag FROM tags WHERE id = %s""", (id,))
        curr = [x[0].lower() for x in curs.fetchall()]
        tags = [x.strip().lower() for x in tags.split(',')]
        for tag in tags:
            if (not tag in curr) and (tag != ''):
                curs.execute("""INSERT INTO tags (id, tag) VALUES (%s, %s);""", (id, tag))
        for cur in curr:
            if not cur in tags:
                curs.execute("""DELETE FROM tags WHERE id=%s AND tag=%s;""", (id, cur))

        curs = self.commit(curs)

        return RESPONSE.redirect('viewNewsItem?id=%s' % id)

    def viewAllNews(self, page=0, tag=None, **kw):
        """View all the news in the database (with comments)"""
        try:
            page = int(page)
        except:
            page = 0
            
        recs = self.somenews(pageCount=5, pageN=int(page), tag=tag)
        if recs:
            pagePrev, pageNext, pageCount = self.getPageInfo(5, page, tag)
            return self.newsitems_format(recs=recs, showComments=True, tag=tag, pageN=page, pagePrev=pagePrev, pageNext=pageNext, pageOf=pageCount)
        else:
            return self.norecords(**kw)
        
    def viewNewsItem(self,REQUEST=None,**kw):
        """View just one news item specified by id argument."""
        try:
            id = REQUEST.form['id']
        except:
            id = -1
        recs = self.somenews(id=id)
        if recs:
            return self.newsitems_format(recs=recs, showComments=True, REQUEST=REQUEST, **kw)
        else:
            return self.norecords(REQUEST=REQUEST, **kw)

    def viewNewsItemTag(self, REQUEST=None, **kw):
        """View news item by specified tag."""
        try:
            tag = REQUEST.form['tag']
        except:
            tag = ''

        recs = self.somenews(tag=tag)
        if recs:
            return self.newsitems_format(recs=recs, showComments=True, REQUEST=REQUEST, **kw)
        else:
            return self.norecords(REQUEST=REQUEST, **kw)

    rssfeed = DTMLFile('www/rssfeed',globals())
    atomfeed = DTMLFile('www/atomfeed',globals())
    
    def viewRecentFeed(self, REQUEST=None, RESPONSE=None, **kw):
        """Output an XML newsfeed."""
        isAtom = False
        try:
            isAtom = bool(int(REQUEST.form['atom']))
        except:
            None

        recs = self.somenews(count=self.recentN)
        
        if isAtom:
            RESPONSE.setHeader('Content-Type','application/atom+xml; charset=utf-8')
        else:
            RESPONSE.setHeader('Content-Type','application/rss+xml; charset=utf-8')

        if isAtom:
            return self.atomfeed(recs=recs)
        return self.rssfeed(recs=recs)

    def viewRecentNews(self, noContainer=False, count=0, tag=None, **kw):
        """View just the recent N news items."""
	if (not count):
		count = self.recentN
        recs = self.somenews(count=count, tag=tag)
        if recs:
            return self.newsitems_format(recs=recs, noContainer=noContainer, **kw)
        else:
            return self.norecords(noContainer=noContainer, **kw)

    def viewTagCloud(self, noContainer=False, **kw):
        """View teh Tag Cloud"""
        tags = self.taginfo()
        mn = None
        mx = 0
        
        for i in tags.keys():
            if mn is None:
                mn = tags[i]
            elif (tags[i] <= mn):
                mn = tags[i]
            if tags[i] >= mx:
                mx = tags[i]

        for i in tags.keys():
            tags[i] = (tags[i], 100+((tags[i] * 100.0) / mx))
        
        return self.tagcloud(tags=tags, noContainer=noContainer, **kw)

