# ResourceInformation.py
# $Id: ResourceInformation.py,v 1.6 2001/07/05 17:16:53 s2mdalle Exp $
# Written by David Allen <mda@idatar.com>
# Released under the terms of the GNU General Public License
#
# When dealing with a Gopher+ server, information about a document can be
# fetched by sending the request:
# some_locator\t!\r\n
#
# This module handles the parsing and storing of that information.
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
############################################################################

from string import *
from Tkinter import *
import Pmw
import os
import re
import ContentFrame
from gopher         import *
import GopherResource
import GopherResponse

class ResourceInformation:
    verbose = None
    def __init__(self, data=None):
        self.blockdict = {}

        self.data = data
        
        if self.data != None:
            self.setData(self.data)

        return None
    def __str__(self):
        return self.toString()
    def toString(self):
        def fn(key, obj=self):
            return "%s:\n%s\n" % (upper(key), obj.getBlock(key))
        
        return join(map(fn, self.getBlockNames()), "") + "\n"
    
    def setData(self, data):
        self.data = data
        self.data = re.sub("\r\n", "\n", self.data)

        lastindex = -1
        blocks = []

        try:
            while 1:
                # This will throw ValueError if not found.
                newindex = index(self.data, "\n+",
                                 (lastindex + 1), len(self.data))
                blocks.append(self.data[lastindex+1:newindex])
                lastindex = newindex
        except ValueError:  # When no more "\n+" are found.
            # The remaining block is what's left...
            blocks.append(self.data[lastindex+1:len(self.data)])

        # What we're going to do is hash each data block in by its block
        # 'title'.  This way, when we're done hashing all of the data, we
        # can just go through and pick out what we want.  So this type of
        # data:
        # +ADMIN:
        #  Grendel The Evil <grendel@nowhere.com>
        #  Some more admin information
        # Gets hashed in like this essentially:
        # hash['admin'] = "Grendel The Evil <grendel@nowhere.com>\n..."
        self.blockdict = {}

        # We now have a list of blocks.
        for block in blocks:
            lines = split(block, "\n")
            blocklabel = lines[0]

            front = find(blocklabel, "+")   # This defines the start of a block
            back  = find(blocklabel, ":")   # This may not be present

            if front != -1:
                if back == -1:
                    back = len(blocklabel)  # End of string if not present

                # Get the name, which is like this: "+ADMIN:" => 'ADMIN'
                blockname = blocklabel[front+1:back]
                key = lower(blockname) # Lowercase so it hashes nicely.  :)
                
                # strip the leading space.  This is because in gopher+
                # when it responds to info queries, each response line that
                # isn't a block header is indented by one space.
                data = re.sub("\n ", "\n", join(lines[1:], "\n"))

                # Get the first space in the data.
                if self.verbose:
                    print "Data is %s" % data

                # Watch out for the case when data is ''.  This could be in
                # particular if the server sends us a size packet like this:
                # +-1\r\n
                # Which would have a '' data segment.
                if data != '' and data[0] == ' ':
                    data = data[1:]

                # Assign it into the hash.
                if self.verbose:
                    print "Assigned data to key %s" % key

                if data != '' and not data is None:
                    # No sense in assigning nothing into a key.  The getBlock()
                    # handles when there is no data and returns ''
                    self.blockdict[key] = data
            else:
                print "BLOCK ERROR: cannot find blockname in %s" % blocklabel

        if self.verbose:
            k = self.blockdict.keys()
            print "Available block titles are:\n%s" % join(k, "\n")

        print "Keys are ", self.blockdict.keys()
        return self

    # Simple accessors/mutators.
    # Sure, I could just monkey around with the data in an object from outside,
    # but in some cultures, people are executed for such offenses against the
    # OOP paradigm.  :)
    def setBlock(self, blockname, blockval):
        self.blockdict[lower(blockname)] = blockval
        return self.getBlock(lower(blockname))
    def setInfo(self, newinfo):
        self.blockdict['info'] = newinfo
        return self.getInfo()
    def setAdmin(self, newadmin):
        self.blockdict['admin'] = newadmin
        return self.getAdmin()
    def setViews(self, newviews):
        self.blockdict['views'] = newviews
        return self.getViews()
    def setAbstract(self, newabstract):
        self.blockdict['abstract'] = newabstract
        return self.getAbstract()
    def getAbstract(self):
        return self.blockdict['abstract']
    def getViews(self):
        return self.blockdict['views']
    def getInfo(self):
        return self.blockdict['info']
    def getAdmin(self):
        return self.blockdict['admin']
    def getBlockNames(self):
        return self.blockdict.keys()
    def getBlock(self, blockname):
        try:
            return self.blockdict[lower(blockname)]
        except KeyError:
            return ''

class GUIResourceInformation(Pmw.TextDialog):
    def __init__(self, resource_info_object):
        Pmw.TextDialog.__init__(self, title="Resource Information")
        self.insert('end', resource_info_object.toString())
        return None
    
        
