# IMPORTANT NOTICE! This copy of D'Lanor's Dynamic Book Template
# has been modified to accept an optional responder, in place of the
# avatar_behaviour+timer coupling of the original script.
# That responder must notify this script, to greenlight the link.
# Take this into account, if you use it or change anything.

#PLEASE DO NOT REMOVE THE COMMENTS! It makes it easier to make changes to the
#books, as well as identify the version of the script in use. Thanks, Rize.

###########################################
#                                         #
#  Dynamic Book Template v4.1 by D'Lanor  #
#                                         #
###########################################

# Change each occurrence of *YourAge* to the actual name of your age.
# Do the same with the file names.

from Plasma import *
from PlasmaTypes import *
from PlasmaKITypes import *
from PlasmaNetConstants import *
import xLinkingBookDefs
actClickableObject = ptAttribActivator(1, 'Act: Clickable Object')
strObject = ptAttribString(2, 'Object String')
bookResponder = ptAttribResponder(3, 'Avatar link animation, etc responder (optional)')

### DO NOT CHANGE THESE VARIABLES/CONSTANTS! ###
ourBook = None
bkLinks = []
ageLinkStruct = None
kLinkID = 1
publicAges = []
kPublicAgeLink = 6
kPublicAgesMOUL = ['city',
'Neighborhood',
'Neighborhood02',
'GreatTreePub',
'GuildPub-Cartographers',
'GuildPub-Greeters',
'GuildPub-Maintainers',
'GuildPub-Messengers',
'GuildPub-Writers',
'philRelto',
'Kveer']

### CHANGE THE GLOBAL CONSTANTS BELOW TO FIT YOUR AGE ######################################
#                                                                                          #
# modPageDefs: Replace *YourAge*PageDefs with the name of the module that contains your    #
#              page definitions.                                                           #
# ageBooks     These are your clickable objects. They must be defined in *YourAge*PageDefs #
#              in the AgeBooks Dictionary Section by the same name(s).                     #
# bookPages    Names in bookPages must be defined in the *YourAge*PageDefs file under      #
#              BookPages. An ageBook can have multiple bookPages as long as they are       #
#              enclosed together between the same square brackets.                         #
#              Always keep the nesting structure [[double square brackets]] intact!        #
# parentAge    If you are using the kChildAgeBook linking rule you can set a parent age.   #
#              Child ages are only useful for ages which have multiple owners (currently   #
#              only Neighborhood!). All parent age owners share the same instance of the   #
#              child age. Using any other parent age than Neighborhood makes no sense.     #
# kLinkDelay   Delay for the optional avatar link animation to finish. You may have to     #
#              tweak it since 3.5 is an estimate.                                          #
# vOpenSource  For future Uru Open Source support. For now keep this set to false.         #
#                                                                                          #
# If there are multiple books in an age the code will find the right one automagically.    #
# You can add as many books as you like. Just define them in the global variables ageBooks #
# and bookPages. The order is important here. The first book will be matched to the first  #
# page list, the second book to the second page list etc.                                  #
############################################################################################

modPageDefs = 'relltooPageDefs'
ageBooks = ['VisitorBook', 'JamesJournal', 'NexusLinkBook', 'FTLinkBook']
bookPages = [['relltooJournal'], ['relltooJamesJournalpages'], ['NexusLinkPage'], ['FTLinkPage']]
parentAge = 'Neighborhood'
kLinkDelay = 3.5
vOpenSource = false

class relltooBookGUI(ptModifier,):

    def __init__(self):
        ptModifier.__init__(self)
        self.version = '4.1'
        self.me = self.__class__.__name__
        self.PageDefs = __import__(modPageDefs)
        print ('__init__%s v.%s' % (self.me, self.version))



    def OnNotify(self, state, id, events):
        if ((id == actClickableObject.id) and state):
            print ('%s: OnNotify: Someone clicked on object %s' % (self.me, strObject.value))
            if PtWasLocallyNotified(self.key):
                print 'It was you'
                for (a, b,) in zip(ageBooks, bookPages):
                    print ('Trying book %s with page(s) %s' % (a, b))
                    if (strObject.value == a):
                        print 'Match found! Start opening book...'
                        self.IOpenBook(a, b)
                        break
                    else:
                        print 'No match'
#
#   CHANGE: This new section does what OnTimer kLinkDelay used to
#           (and still does, if no responder is provided)
#
        elif (id == bookResponder.id):
            if (type(ageLinkStruct) != type(None)):
                print ('%s: Callback from responder: Really linking now...' % self.me)
                linkMgr = ptNetLinkingMgr()
                linkMgr.linkToAge(ageLinkStruct)
#   CHANGE end

        else:
            for event in events:
                if ((event[0] == PtEventType.kBook) and PtWasLocallyNotified(self.key)):
                    if (event[1] == PtBookEventTypes.kNotifyImageLink):
                        print ('BookNotify: Linking panel id=%d, event=%d' % (event[2], event[1]))
                        ourBook.hide()
                        if (event[2] == 0):
                            print 'Warning: No link id, define proper link destination or use non-clickable image'
                        elif (event[2] >= xLinkingBookDefs.kFirstLinkPanelID):
                            for i in range(0, len(bkLinks)):
                                if (event[2] == bkLinks[i][0]):
                                    try:
                                        self.IlinkToAge(bkLinks[i][1], bkLinks[i][2], bkLinks[i][3], bkLinks[i][4], bkLinks[i][5])
                                    except Exception, detail:
                                        print ('ERROR: Unable to initialize link - %s' % detail)
                                    break

                    elif (event[1] == PtBookEventTypes.kNotifyShow):
                        print ('BookNotify: Show book, event=%d' % event[1])
                        PtToggleAvatarClickability(0)
                    elif (event[1] == PtBookEventTypes.kNotifyHide):
                        print ('BookNotify: Hide book, event=%d' % event[1])
                        PtToggleAvatarClickability(1)
                    elif (event[1] == PtBookEventTypes.kNotifyNextPage):
                        print ('BookNotify: To next page %d, event=%d' % (ourBook.getCurrentPage(), event[1]))
                    elif (event[1] == PtBookEventTypes.kNotifyPreviousPage):
                        print ('BookNotify: To previous page %d, event=%d' % (ourBook.getCurrentPage(), event[1]))
                    elif (event[1] == PtBookEventTypes.kNotifyCheckUnchecked):
                        print ('BookNotify: Relto page toggle, event=%d' % event[1])
                    elif (event[1] == PtBookEventTypes.kNotifyClose):
                        print ('BookNotify: Close book, event=%d' % event[1])
                elif (event[0] == kVariableEvent):
                    AvatarID = int(event[3])
                    actingAvatar = ptSceneobject(PtGetAvatarKeyFromClientID(AvatarID), self.key)
                    print ('Notify: Avatar %d started to link, run responder' % AvatarID)
                    bookResponder.run(self.key, avatar=actingAvatar, fastforward=0)




    def OnTimer(self, id):
        if (id == kLinkID):
            if (type(ageLinkStruct) != type(None)):
                print ('%s: OnTimer: Really linking now...' % self.me)
                linkMgr = ptNetLinkingMgr()
                linkMgr.linkToAge(ageLinkStruct)



    def gotPublicAgeList(self, ages):
        global publicAges
        try:
            for age in ages:
                publicAges.append(age[0])

        except IndexError:
            pass


    def IOpenBook(self, ageBook, bkPages = None):
        global ourBook
        global bkLinks
        print ('%s: IOpenBook: Page(s) requested %s' % (self.me, bkPages))
        if (type(bkPages) == type(None)):
            print 'ERROR: no pages defined'
            return
        if (not (ageBook in self.PageDefs.AgeBooks)):
            print ('ERROR: Definition %s does not exist in AgeBooks' % ageBook)
            return
        bkParams = self.PageDefs.AgeBooks[ageBook]
        (bkCover, bkFont, startOpen, forceOwned, bookGUI, width, height,) = bkParams
        PageDef = (bkCover + bkFont)
        if (not startOpen):
            if (not self.IsThereACover(PageDef)):
                print 'Warning: Missing cover, forcing book open'
                startOpen = 1
        PageCount = xLinkingBookDefs.kFirstLinkPanelID
        bkLinks = []
        for bkPage in bkPages:
            if (not (bkPage in self.PageDefs.LinkDestinations)):
                print ('Warning: %s skipped, definition does not exist in LinkDestinations' % bkPage)
                continue
            pgParams = self.PageDefs.LinkDestinations[bkPage]
            (bkAge, spawnPoint, spTitle, linkRule,) = pgParams
            alink = 1
            if ((type(bkAge) != type(None)) and forceOwned):
                print ('Ownership check for %s book' % bkAge)
                vault = ptVault()
                ainfo = ptAgeInfoStruct()
                ainfo.setAgeFilename(bkAge)
                alink = vault.getOwnedAgeLink(ainfo)
            if alink:
                print ('Showing %s, link destination %s' % (bkPage, bkAge))
                if (type(bkAge) != type(None)):
                    t = (PageCount, bkPage, bkAge, spawnPoint, spTitle, linkRule)
                    bkLinks.append(t)
                    PageDef = ((PageDef + (self.PageDefs.BookPages[bkPage] % PageCount)) + '<pb>')
                else:
                    PageDef = ((PageDef + self.PageDefs.BookPages[bkPage]) + '<pb>')
                PageCount = (PageCount + 1)
            else:
                print ('No owner of age %s so we are not showing %s' % (bkAge, bkPage))

        if (PageCount == xLinkingBookDefs.kFirstLinkPanelID):
            print 'No pages created...'
            return
        else:
            TotalCount = (PageCount - xLinkingBookDefs.kFirstLinkPanelID)
        print ('%d item(s) created, linking page(s): %d' % (TotalCount, len(bkLinks)))
        PageDef = PageDef[:-4]
        ourBook = ptBook(PageDef, self.key)
        ourBook.setSize(width, height)
        ourBook.setGUI(bookGUI)
        ourBook.show(startOpen)
        if len(bkLinks):
            ageList = []
            for i in range(0, len(bkLinks)):
                if (bkLinks[i][5] == kPublicAgeLink):
                    ageList.append(bkLinks[i][2])

            if len(ageList):
                self.IGetPublicAges(ageList)



    def IsThereACover(self, bookHtml):
        idx = bookHtml.find('<cover')
        if (idx >= 0):
            return 1
        return 0



    def IlinkToAge(self, bookPage, ageName, spawnPoint, spTitle, linkRule = PtLinkingRules.kBasicLink):
        global ageLinkStruct
        print ('%s: ILinkToAge: Link request from page %s to age %s' % (self.me, bookPage, ageName))
        if ((type(ageName) == type(None)) or (len(ageName) == 0)):
            print 'ERROR: Cannot link to age without name'
            return
        if ((type(spawnPoint) == type(None)) or (len(spawnPoint) == 0)):
            print 'No spawnpoint defined, checking special actions...'
            self.IDoSpecialAction(bookPage)
            return
        als = ptAgeLinkStruct()
        ainfo = ptAgeInfoStruct()
        ainfo.setAgeFilename(ageName)
        ainfo.setAgeInstanceName(self.IConvertAgeInstanceName(ageName))
        als.setAgeInfo(ainfo)
        if ((type(spTitle) == type(None)) or (len(spTitle) == 0)):
            if ((linkRule == PtLinkingRules.kOriginalBook) or PtIsSinglePlayerMode()):
                  #################################################################################
                  # Linkingrule kOriginalBook writes spawnpoint and title to the agelink node,    #
                  # so we must make absolutely sure that a proper title is given!                 #
                  # In singleplayer mode all linkingrules behave like kOriginalBook, no matter    #
                  # which linkingrule is set in the definition.                                   #
                  #################################################################################
                if (spawnPoint == 'LinkInPointDefault'):
                    spTitle = 'Default'
                  #################################################################################
                  # We did not define a spawnpoint title, but since the spawnpoint is the default #
                  # it is safe to continue and write it to the agelink node with default title.   #
                  #################################################################################
                else:
                    print 'Warning: Empty spawnpoint title not allowed, check your link destinations!'
                    return
            else:
                print 'Empty spawnpoint title allowed, continue linking'
                spTitle = ''
        if (linkRule == PtLinkingRules.kChildAgeBook):
            als.setParentAgeFilename(parentAge)
        elif (linkRule == kPublicAgeLink):
            if (not PtIsSinglePlayerMode()):
                if (not len(publicAges)):
                    print 'No public ages found, link aborted'
                    return
                # remove and completely replace the current age link structure
                als = None
                # make new list without any other ages
                ageInstances = []
                for i in range(0, len(publicAges)):
                    if (publicAges[i].getAgeFilename() == ageName):
                        ageInstances.append(publicAges[i])

                # get age link structure from remaining age instance(s)
                if len(ageInstances):
                    als = self.IGetPublicLink(ageInstances)
                if (type(als) == type(None)):
                    print 'Missing age link structure, link aborted'
                    return
            # put back the proper linking rule: never pass kPublicAgeLink to the server!
            linkRule = PtLinkingRules.kBasicLink
        als.setLinkingRules(linkRule)
        spPoint = ptSpawnPointInfo(spTitle, spawnPoint)
        als.setSpawnPoint(spPoint)
        ageLinkStruct = als
        print ('Linking to age %s, spawnpoint %s with title %s, using linkingrule %d' % (ageName, spawnPoint, spTitle, linkRule))
        if (bookResponder.value):   # CHANGE: Used to be a type check
            # workaround... why doesn't netForce work here?
            myID = PtGetClientIDFromAvatarKey(PtGetLocalAvatar().getKey())
            note = ptNotify(self.key)
            note.clearReceivers()
            note.addReceiver(self.key)
            note.setActivate(1)
            note.addVarNumber('Avatar', myID)
            note.send()
#            PtAtTimeCallback(self.key, kLinkDelay, kLinkID)  !CHANGE: This AtTimeCallback is replaced with a responder notification!
        else:
            PtAtTimeCallback(self.key, 0.1, kLinkID)



    def IGetPublicAges(self, ageList):
        global publicAges
        print ('%s: IGetPublicAges: %s' % (self.me, ageList))
        publicAges = []
        if (not self.HasPublicAges()):
            print 'ERROR: Public ages not supported in this Uru version!'
            return
        if vOpenSource:
          ################################################################################
          # Technically only city, Neighborhood02 and GreatTreePub were true public ages #
          # in MOUL (apart from public neighborhoods). The others had hard coded GUIDs!  #
          # These are: GuildPub-Cartographers, GuildPub-Greeters, GuildPub-Maintainers,  #
          # GuildPub-Messengers, GuildPub-Writers, philRelto and Kveer.                  #
          # GUIDs are normally generated by the vault. This means that for Open Source   #
          # the hard coded stuff will have to be ditched in favor of public ages.        #
          #                                                                              #
          # Kveer and city also had child age instances. Use the kChildAgeBook rule to   #
          # link to a child age.                                                         #
          ################################################################################
            for age in ageList:
                PtGetPublicAgeList(age, self)
                if (age not in kPublicAgesMOUL):
                    print ('Warning: Age %s is usually not public in MOUL Open Source' % age)
        else:
            for age in ageList:
                PtGetPublicAgeList(age, self)
                if ((age != 'city') and (age != 'Neighborhood')):
                    print ('Warning: Age %s is usually not public in UU' % age)



    def IGetPublicLink(self, instances, highest = 0):
      ############################################################################
      # If there are multiple public instances get the one with the lowest GUID! #
      # This is important to make everyone end up in the same instance.          #
      # In UU for example the city had 5 public instances. The lowest was the    #
      # Nexus city instance. Most ages have a single public instance though.     #                                             
      # This function can also get the highest GUID but we won't use that here.  #
      ############################################################################
        curGUID = instances[0].getAgeInstanceGuid()
        curInstance = 0
        if (not highest):
            for i in range(0, len(instances)):
                if (instances[i].getAgeInstanceGuid() < curGUID):
                    curGUID = instances[i].getAgeInstanceGuid()
                    curInstance = i

        else:
            for i in range(0, len(instances)):
                if (instances[i].getAgeInstanceGuid() > curGUID):
                    curGUID = instances[i].getAgeInstanceGuid()
                    curInstance = i

        try:
            als = ptAgeLinkStruct()
            als.getAgeInfo().copyFrom(instances[curInstance])
            print ('%s: IGetPublicLink: Age link structure found' % self.me)
            return als
        except Exception, detail:
            print ('%s: IGetPublicLink: Age link structure not found - %s' % (self.me, detail))
            return None



    def IConvertAgeInstanceName(self, ageName):
      ###############################################################################
      # Optional: You can add a friendly name to this list for the age you link to. #
      # This is the name that shows up in the KI. Most Cyan age names are converted #
      # to friendly names in the KI but we cannot expect the KI to do that for user #
      # ages.                                                                       #
      # Beware: Age instance names are written to the vault if the kOriginalBook    #
      # rule is used. That will happen whether you set a name here or not. And it   #
      # would happen regardless of this function.                                   #
      # By default the age instance name is the age name. However, an age instance  #
      # name does not have to be unique (Ae'gura).                                  #
      # If you plan to link to Cyan ages you must at least keep the age instance    #
      # names provided under ABM and TPOTS!                                         #
      ###############################################################################
        # ABM (UU)
        if (ageName == 'Personal'):
            return 'Relto'
        if (ageName == 'Cleft'):
            return "D'ni-Riltagamin"
        if (ageName == 'BahroCave'):
            return "D'ni-Rudenna"
        if (ageName == 'BaronCityOffice'):
            return "Ae'gura"
        if (ageName == 'city'):
            return "Ae'gura"
        if (ageName == 'Garden'):
            return 'Eder Kemo'
        if (ageName == 'Gira'):
            return 'Eder Gira'
        if (ageName == 'Garrison'):
            return 'Gahreesen'
        # TPOTS (Alcugs)
        if (ageName == 'Neighborhood02'):
            return 'DRC Neighborhood'
        if (ageName == 'RestorationGuild'):
            return "Watcher's Guild"
        if (ageName == 'AhnySphere01'):
            return 'Sphere 1'
        if (ageName == 'AhnySphere02'):
            return 'Sphere 2'
        if (ageName == 'AhnySphere03'):
            return 'Sphere 3'
        if (ageName == 'AhnySphere04'):
            return 'Sphere 4'
        # The KI always tried to convert this incorrectly from "Shaft"
        if (ageName == 'Descent'):
            return "D'ni-Tiwah"
        # missing KI conversions (probably better to add this in the KI)
        if (ageName == 'EderDelin'):
            return 'Eder Delin'
        if (ageName == 'EderTsogal'):
            return 'Eder Tsogal'
        if (ageName == 'GreatTreePub'):
            return "The Watcher's Pub"
        if (ageName == 'Ercana'):
            return "Er'cana"
        # fan ages examples
        if (ageName == 'Pahts'):
            return 'Ahra Pahts'
        if (ageName == 'Andy_Nexus'):
            return "Andy's Nexus"
        if (ageName == 'Dots_Office'):
            return "Dot's Office"
        if (ageName == 'The_Company_Nexus'):
            return 'The Company Nexus'
        # Drizzle examples
        if (ageName == 'KveerMOUL'):
            return "K'veer"
        if (ageName == 'KirelMOUL'):
            return 'Kirel'
        if (ageName == 'AhnonayMOUL'):
            return 'Ahnonay'
        if (ageName == 'MystMystV'):
            return 'Myst'
        if (ageName == 'MarshScene'):
            return 'Great Marsh'
        if (ageName == 'MountainScene'):
            return 'Rowan Green'
        return ageName



    def HasPublicAges(self):
        if vOpenSource:
            print 'HasPublicAges: Open Source = true'
            return true
        if PtIsSinglePlayerMode():
            print 'HasPublicAges: Offline = false'
            return false
        try:
            PtForceCursorShown()
        except:
            print 'HasPublicAges: UU = true'
            return true
        print 'HasPublicAges: Alcugs = false'
        return false



    def IDoSpecialAction(self, bookPage):
      ###########################################################
      # Replace 'CleftSpecial' with your bookPage that contains #
      # the clickable image triggering the special action.      #
      ###########################################################
        if (bookPage == 'CleftSpecial'):
            print ('Special action found for %s' % bookPage)
            # Do some special action here
        else:
            print ('No special action for %s' % bookPage)

            


glue_cl = None
glue_inst = None
glue_params = None
glue_paramKeys = None
try:
    x = glue_verbose
except NameError:
    glue_verbose = 0

def glue_getClass():
    global glue_cl
    if (glue_cl == None):
        try:
            cl = eval(glue_name)
            if issubclass(cl, ptModifier):
                glue_cl = cl
            elif glue_verbose:
                print ('Class %s is not derived from modifier' % cl.__name__)
        except NameError:
            if glue_verbose:
                try:
                    print ('Could not find class %s' % glue_name)
                except NameError:
                    print 'Filename/classname not set!'
    return glue_cl



def glue_getInst():
    global glue_inst
    if (type(glue_inst) == type(None)):
        cl = glue_getClass()
        if (cl != None):
            glue_inst = cl()
    return glue_inst



def glue_delInst():
    global glue_inst
    global glue_cl
    global glue_paramKeys
    global glue_params
    if (type(glue_inst) != type(None)):
        del glue_inst
    glue_cl = None
    glue_params = None
    glue_paramKeys = None



def glue_getVersion():
    inst = glue_getInst()
    ver = inst.version
    glue_delInst()
    return ver



def glue_findAndAddAttribs(obj, glue_params):
    if isinstance(obj, ptAttribute):
        if glue_params.has_key(obj.id):
            if glue_verbose:
                print 'WARNING: Duplicate attribute ids!'
                print ('%s has id %d which is already defined in %s' % (obj.name,
                 obj.id,
                 glue_params[obj.id].name,))
        else:
            glue_params[obj.id] = obj
    elif (type(obj) == type([])):
        for o in obj:
            glue_findAndAddAttribs(o, glue_params)

    elif (type(obj) == type({})):
        for o in obj.values():
            glue_findAndAddAttribs(o, glue_params)

    elif (type(obj) == type(())):
        for o in obj:
            glue_findAndAddAttribs(o, glue_params)




def glue_getParamDict():
    global glue_paramKeys
    global glue_params
    if (type(glue_params) == type(None)):
        glue_params = {}
        gd = globals()
        for obj in gd.values():
            glue_findAndAddAttribs(obj, glue_params)

        glue_paramKeys = glue_params.keys()
        glue_paramKeys.sort()
        glue_paramKeys.reverse()
    return glue_params



def glue_getClassName():
    cl = glue_getClass()
    if (cl != None):
        return cl.__name__
    if glue_verbose:
        print ('Class not found in %s.py' % glue_name)
    return None



def glue_getBlockID():
    inst = glue_getInst()
    if (inst != None):
        return inst.id
    if glue_verbose:
        print ('Instance could not be created in %s.py' % glue_name)
    return None



def glue_getNumParams():
    pd = glue_getParamDict()
    if (pd != None):
        return len(pd)
    if glue_verbose:
        print ('No attributes found in %s.py' % glue_name)
    return 0



def glue_getParam(number):
    pd = glue_getParamDict()
    if (pd != None):
        if (type(glue_paramKeys) == type([])):
            if ((number >= 0) and (number < len(glue_paramKeys))):
                return pd[glue_paramKeys[number]].getdef()
            else:
                print ('glue_getParam: Error! %d out of range of attribute list' % number)
        else:
            pl = pd.values()
            if ((number >= 0) and (number < len(pl))):
                return pl[number].getdef()
            elif glue_verbose:
                print ('glue_getParam: Error! %d out of range of attribute list' % number)
    if glue_verbose:
        print 'GLUE: Attribute list error'
    return None



def glue_setParam(id, value):
    pd = glue_getParamDict()
    if (pd != None):
        if pd.has_key(id):
            try:
                pd[id].__setvalue__(value)
            except AttributeError:
                if isinstance(pd[id], ptAttributeList):
                    try:
                        if (type(pd[id].value) != type([])):
                            pd[id].value = []
                    except AttributeError:
                        pd[id].value = []
                    pd[id].value.append(value)
                else:
                    pd[id].value = value
        elif glue_verbose:
            print "setParam: can't find id=",
            print id
    else:
        print 'setParma: Something terribly has gone wrong. Head for the cover.'



def glue_isNamedAttribute(id):
    pd = glue_getParamDict()
    if (pd != None):
        try:
            if isinstance(pd[id], ptAttribNamedActivator):
                return 1
            if isinstance(pd[id], ptAttribNamedResponder):
                return 2
        except KeyError:
            if glue_verbose:
                print ('Could not find id=%d attribute' % id)
    return 0



def glue_isMultiModifier():
    inst = glue_getInst()
    if isinstance(inst, ptMultiModifier):
        return 1
    return 0



def glue_getVisInfo(number):
    pd = glue_getParamDict()
    if (pd != None):
        if (type(glue_paramKeys) == type([])):
            if ((number >= 0) and (number < len(glue_paramKeys))):
                return pd[glue_paramKeys[number]].getVisInfo()
            else:
                print ('glue_getVisInfo: Error! %d out of range of attribute list' % number)
        else:
            pl = pd.values()
            if ((number >= 0) and (number < len(pl))):
                return pl[number].getVisInfo()
            elif glue_verbose:
                print ('glue_getVisInfo: Error! %d out of range of attribute list' % number)
    if glue_verbose:
        print 'GLUE: Attribute list error'
    return None



