##############################################################################  
#   
# This software is released under the Zope Public License (ZPL) Version 1.0
#
# Copyright (c) Digital Creations.  All rights reserved.  
# Portions Copyright (c) 1999 by Butch Landingin.
# Portions Copyright (c) 2000-2001 by Chris Withers.
#   
##############################################################################  
     
__version__='$Revision: 1.35 $'[11:-2]     
from Globals import Persistent     
from Globals import HTMLFile
import Globals
from BTrees.IIBTree import IISet
from Squishfile import Squishfile     
from Acquisition import Implicit
from time import time, localtime, strftime, gmtime
from string import strip,split,join
from string import lower,atoi
from urllib import quote, unquote
from Utility import CRLF, tagRegex, doAddPosting, getitem
from SquishPermissions import ModeratePostings,AddPostings,View
from stripogram import html2safehtml
from DateTime import DateTime
from OFS.Traversable import Traversable

from AccessControl import ClassSecurityInfo

class Posting(Persistent, Implicit, Traversable):     
    """Squishdot Posting"""
    
    security = ClassSecurityInfo()

    security.setDefaultAccess("allow")
    
    meta_type='Posting'     
    icon   ='misc_/Squishdot/posting_img'     
    root=0
    
    # Default encoding for old postings
    encoding = 'HTML'
    # fields in this type of posting
    _fields=[]
    
    manage_editForm=HTMLFile('editPostingForm', globals())
    
    security.declareProtected(ModeratePostings, 'manage_editForm')
    if hasattr(manage_editForm,'_setName'):
        manage_editForm._setName('manage_editForm')
    
    # Aliases for manage_editForm
    manage         =manage_editForm     
    manage_main    =manage_editForm

    security.declarePrivate('__init__')
    def __init__(self, id, thread,level,reviewed):     
        self.id      =str(id)     
        self.ids     =IISet()     
        self.thread  =thread
        self.created =id     
        self.modified=id     
        self.level =level
        self.revsub  =0     
        self.reply_cnt =0
        self.reviewed=reviewed
     
    security.declarePrivate('index')
    def index(self):
        # index this posting is the Squishdot site that contains it.
        self.catalog_object(self,join(self.getPhysicalPath(),'/'))

        # recatalog all the postings in our thread path
        if self.thread:
            self.aq_parent.index()
        
    security.declareProtected(View, 'getFields')
    def getFields(self):
        """Return a list of fields that this posting has"""
        return self._fields

    security.declareProtected(View, 'getThread')
    def getThread(self, index):
        """A better abstaction rather than accessing the list directly"""
        return self.thread[index]

    security.declarePublic('__len__')
    def __len__(self): return 1     
     
    security.declareProtected(View, '__getitem__')
    __getitem__ = getitem     
     
    security.declarePrivate('setItem')
    def setItem(self,id,obj,index=1):     
        # Make sure the object we store is not wrapped with     
        # an acquisition wrapper, since we will be wrapping     
        # it again manually in __getitem__ when it is needed.
        bobj = getattr(obj,'aq_base',obj)
        self.ids.insert(id)     
        self.data[id]=bobj

        #index the new posting
        if index:
            obj.index()
     
    security.declarePrivate('textToSearch')
    def textToSearch(self):
        # returns the text to search for a ZCatalog
        text=''
        for line in self.body:
            # strip out HTML and append a newline to each line.
            text = text+tagRegex.sub("",line)+'\n'
        return text

    security.declareProtected(View, 'date_posted')
    def date_posted(self,fmstr='%A %B %d, @%I:%M%p'):     
        # """ date when article was posted """     
        ltime = localtime(self.created)         
        return strftime(fmstr,ltime)     
             
    # deprecated methods
    date_created = time_created = date_posted

    security.declareProtected(View, 'date')
    def date(self):
        """return the date of creation for indexing purposes"""
        return DateTime(self.created)
    
    security.declareProtected(View, 'body_len')
    def body_len(self,divisor=None):     
        # """ total body length of text """    
        tlen = 0     
        if not self.body:     
            tlen = 0    
        else:    
            for line in self.body:     
                tlen = tlen + len(line)    
    
        if divisor is None:    
            if tlen == 0:    
                return ''    
            if tlen > 51200:     
                tlen = tlen / 1024     
                return str(tlen) + ' Kb'     
            else:     
                return str(tlen) + ' bytes'     
    
        if divisor < 1:    
            return tlen    
        else:    
            return tlen/divisor    
                    
    security.declareProtected(ModeratePostings, 'postingValues')
    def postingValues(self):     
        # """ return all replies """     
        return self.data_map(self.ids)     
     
    security.declareProtected(View, 'tpId')
    def tpId(self):     
        return self.id     
     
    security.declareProtected(View, 'tpURL')
    def tpURL(self):     
        return self.id     
     
    security.declareProtected(View, 'this')
    def this(self): return self     
         
    security.declareProtected(View, 'has_items')
    def has_items(self):     
        return len(self.ids)     
     
    security.declarePrivate('sub_ids')
    def sub_ids(self,ids):     
        map(ids.insert, self.ids)     
        for item in self.data_map(self.ids):     
            ids=item.sub_ids(ids)     
        return ids     
     
    security.declareProtected(View, 'desc_items')
    def desc_items(self):     
        # """ return latest list of replies """
        items = []
        postings = map(self.__getitem__,self.ids)
        reviewed = filter(lambda p: p.reviewed, postings)
        for item in reviewed:
            items.append(item)
            items.extend(item.desc_items())
        return items
     
    security.declareProtected(View, 'attachment')
    def attachment(self):     
        # """ file attachment """     
        file=self.file
        return file and (file,) or None     
     
    security.declareProtected(AddPostings, 'suggest_title')
    def suggest_title(self):     
        # """ suggested title of reply """     
        t=self.title     
        return (lower(t[:3])=='re:') and t or 'Re: %s' % t     
     
    security.declareProtected(View, 'thread_path')
    def thread_path(self):     
        return join(map(lambda x: '/%s' % x, self.thread), '')     
     
    security.declareProtected(View, 'index_html')
    def index_html(self,REQUEST):     
        """ squishdot article main page (the read more page) """    
        return self.posting_html(self,REQUEST)     
     
    security.declarePrivate('doNotify')
    def doNotify(self, msg, REQUEST):     
        # """ sends mail to notify person being replied to """     
        if self.notify and self.email:
            self.sendEmail(msg,self.email,REQUEST)

    security.declarePublic('cancelNotify')
    def cancelNotify(self, REQUEST):     
        """ cancels email notification of replies """     
        self.notify=''     
        return self.showMessage(self, REQUEST=REQUEST, title='Cancelled Notification',     
                             message='You will no longer be notified of replies to this message',     
                             action=self.absolute_url()     
                            )     
     
    security.declareProtected(AddPostings, 'dummyPosting')
    def dummyPosting(self):
        """ returns a dummy posting for the previewPosting method """
        return Comment(0,[],0,1).__of__(self)

    security.declareProtected(AddPostings, 'addPosting')
    def addPosting(self, file='', REQUEST=None,RESPONSE=None):     
        """ add a Comment """
        return doAddPosting(self,file,REQUEST,RESPONSE,
                            moderated='mod_comment',
                            message  ='Your reply has been posted',
                            klass    =Comment)
     
    def _processReviewed(self,reviewed):
        if self.mod_comment:     
            self.set_reviewed(self,reviewed)     

    security.declareProtected(ModeratePostings, 'edit')
    def edit(self,REQUEST=None,RESPONSE=None,delete_attachment=None,new_attachment='',reviewed=0,index=1):     
        """ edit replies """     
    
        processed,message=self.validatePosting(raw=REQUEST)
        
        if message is not None:
            return self.showError(self, values=processed,title='Data Missing',     
                                  message=message,     
                                  action=self.REQUEST.HTTP_REFERER
                                  )     

        for field in self.getFields():
            value = processed.get(field,'')
            if field in ['body','summary']:
                value=split(CRLF.sub('\n',value),'\n')
            setattr(self,field,value)
            
        self.notify  = processed['notify']
        self.encoding= processed['encoding']

        have_new_file = (hasattr(new_attachment,'filename') and new_attachment.filename)
     
        if delete_attachment or have_new_file:
            # delete the old file
            try:
                delattr(self,self.aq_base.file.file_name())
            except AttributeError:
                pass
            self.file=''

        if have_new_file:
            # store the new file
            file=Squishfile(new_attachment)     
            setattr(self,file.file_name(),file)     
            self.file=file

        self._processReviewed(reviewed)

        # change the created date
        date = REQUEST.get('date')
        if date is not None:
            self.created=int(date.timeTime())
        
        # change the modified value
        self.modified = time()
        
        # re-catalog this posting
        if index:
            self.index()
     
        # should only get here if someone is editing a posting during moderation
        if RESPONSE:     
            RESPONSE.redirect(self.REQUEST.HTTP_REFERER)     
     
    # Used to display the body of the posting with the appropriate formatting    
    security.declareProtected(View, 'showBody')
    def showBody(self):
        return self.render(self.body,self.encoding)
     
    # Return the plain text body of a posting suitable for mailing...
    security.declareProtected(View, 'plain_text')
    def plain_text(self):
        if self.encoding == 'HTML':
            return self.html2text(join(self.body,' '))
        else:
            return join(self.body,'\n')
        
    security.declarePublic('getId')
    def getId(self):
        return self.id

Globals.InitializeClass(Posting)

# Comment has to be in this file to stop import infinite recursion
class Comment(Posting):     
    """ Kindof small, isn't it ;-)"""     
    meta_type  ='Comment'     
    icon       ='misc_/Squishdot/comment_img'
    _fields    =['title','author','body','email']
     
Globals.InitializeClass(Comment)


