function buildAnchorForTopic(text,target,topicid,lastid){
	var lastid=lastid||''
	var str

	str='<a href="javascript:opener.launchTopicPage(\''
	str+=topicid+'\',\''+lastid+'\')" '
	if (target){
		str+='target="'+target+'"'
	}
	str+='>'+text+'</a>\n'

	return str
}

var pageCache = {}
var instanceIndex = {}

function BuildTopicDisplayPage(topicid,last_topic){
	var last_topic=last_topic||'tt-urtype'
	var page=[], page_head=[]
	var str
	var t, theTopic,topics, Topic
	var name, label
	var o,occurs,Occur,oc
	var Type, typeid,typename,hreftypes,datatypes
	var resource,href,datum,data,hrefs,d,h
	var a,assocs,assoc
	var s,scopes,Scope,scopetopic,scopename,scopenames
	var i,inst,instance,instances=[]
	var instance_name,instance_id,hasinstance
	var instance_namelist={}

	var assocIndex,associd
	var assoctype, assoctype_name, assoctype_label
	var t
	var m,member,members
	var r,role,roles,roleid,rolename,rolelabel,roletopic
	var p,player,players
	var playername,playerlabel,playerid,playernames=[]
	var player_index={}
	var classes,c,classlabel,classid

	var n
	var yesno={}
	yesno[false]=', ';yesno[true]=''

	if (!topicid){
		return ''
	}

	function Yesno(bool,str){
		return bool?'':str

	}
	
	instanceIndex = top.tm1.getTopicTypesIndex()

	var head="<html><head><title>Topic Details</title>\n\
<style type='text/css'>\n\
    body {background-color:ivory}\n\
	body{font-family:verdana,arial,sans-serif;\n\
		font-size:80%}\n\
	h3 {font-size:110%}\n\
	h4 {font-size:100%}\n\
	h2.compress,h3.compress {margin-bottom:.3em}\n\
	h3,h4 {margin-top:.3em;margin-bottom:.3em}\n\
	.list {margin-top:1;margin-bottom:1}\n\
	.subsidiary-info {font-size:90%}\n\
	.subsidiary-info {margin-bottom:0.3em}\n\
	a:hover {background:cyan}\n\
</style>\n\
</head>"
	
	page_head.push(head)
	page_head.push('<body>\n')

	// ==== Get topic with this id ====
	theTopic=top.tm1.getTopicById(topicid)

	// ==== Page Navigation ====
	str=buildAnchorForTopic('(Last Topic)','_showtopic',last_topic)

	Topic=tm1.getTopicById('tt-urtype')
	if (Topic){
		str+=buildAnchorForTopic('(Base Types)','_showtopic','tt-urtype',topicid)
	}
	page_head.push('<div class="subsidiary-info">'+str+'</div>\n')

	page = pageCache[topicid]
	if (page){
		return page_head.join('\n') + page.join('\n')
	}

	page = []


	// ==== Section for topic name =====
	if (!theTopic.getNamesFiltered){return ''}
	name=theTopic.getNamesFiltered()[0].name
	page.push('<h2 class="compress">'+name+'</h2>\n')


	// ==== Get type, if any ====
	instance=top.tm1.getTopicById(topicid).instanceOf
	if (instance){
		label=getTopicLabelById(tm1,instance)
		str=buildAnchorForTopic(label,'',instance,topicid)
		if (str){
			page.push('<div class="subsidiary-info"><b>Type: </b>'+str+'</div>')
		}
	}

	// ==== Topic Subject =============
	var subject = theTopic.getIdentity()
	if (subject){
		var uri = subject.getResourceRef()
		if (uri){
			page.push('<div class="subsidiary-info"><b>Subject Identity Reference: </b>'+uri+'</div>') 
		}
		var indicators=subject.getSubjectIndicators()
		if (indicators && indicators.length){
			page.push('<div class="subsidiary-info"><b>Subject Indicators: </b><br>')
			for (var i in indicators){
				uri=indicators[i]
					page.push(uri + '<br>') 
			} 
				page.push('</div>')
		}
	}

	// Get superclass chain
	classes=getAncestorList(tm1,theTopic)
	if (classes.length){
		page.push('<div class="subsidiary-info"><b>Classes: </b>')
		for (c in classes){
			classid=classes[c].id
			classlabel=classes[c].getNamesFiltered()[0].name
			classlabel=buildAnchorForTopic(classlabel,'',classid,theTopic.id)
			classlabel=Yesno(c==0,'/')+classlabel
			page.push(classlabel)
		}
		page.push('\n</div>')
	}

	//showPerspectiveAncestors(theTopic,page)
	//formatPerspectives(theTopic,page)

	formatInstances(theTopic,page)
	formatOccurs(theTopic, page)
	formatAssociations(theTopic,page)
	formatScopes(theTopic,page)
	formatSubclasses(theTopic,page)

	// ===== Close out and cache the page=====
	page.push('</body></html>')

	pageCache[topicid]=page
	return page_head.join('\n') + page.join('\n')

}

function launchTopicPage(topicid,last_topic){
	var page,win
	var last_topic=last_topic||''

	if (!topicid){return}
	
	page=BuildTopicDisplayPage(topicid,last_topic)
	if (!page){return}

	// Display the page
	win=window.open('','_showtopic')
	win.document.write(page)
	win.document.close()
	win.focus()
}

function formatOccurs(Topic, result_list){
	var o,occurs,Occur,oc
	var Type, typeid,typename,hreftypes,datatypes
	var resource,href,datum,data,hrefs,d,h
	var href_index=[]
	var n
	var yesno={}
	yesno[false]=', ';yesno[true]=''

	occurs=Topic.getOccursFiltered()
	if (!occurs.length){return}

	result_list.push('<h3>Resources</h3>\n<ul>')
	datatypes={};hreftypes={};typename=''
	data={};hrefs={}
	scopenames={}
	n=0
	for (o in occurs){
		Occur=occurs[o]

		// Get name of the type of this occurrence
		typeid=Occur.instanceOf

		Type=typeid&&tm1.getTopicById(typeid)
		typename=Type&&Type.getNamesFiltered&&Type.getNamesFiltered()[0].name
		typename=getTypeLabelForObject(tm1,Occur)
		if (!typename||typename=='undefined'){
			typename='(not specified)'
		}

		// Get scopes of this occurrence
		scopes=Occur.getScopes()
		scopenames[Occur]=''
		for (s in scopes){
			scopetopic=tm1.getTopicById(scopes[s].topic)
			scopename=scopetopic.getNamesFiltered()[0].name
			scopenames[Occur]+=yesno[scopenames[Occur]=='']+scopename
		}

		datum=Occur.getData()
		if (datum){
			datum=datum.replace(/&/g,'&amp;')
			datum=datum.replace(/</g,'&lt;')
			datum=datum.replace(/\n/g,'<br>')
			data[n]=datum
			datatypes[n]=typename
			if (scopenames[Occur]){
				datatypes[n]+= ' ['+scopenames[Occur]+']'
			}
		}
		else {
			href=Occur.getResource()
			if (href){
				hrefs[n]=href
				hreftypes[n]=typename
				if (scopenames[Occur]){
					hreftypes[n]+=' ['+scopenames[Occur]+']'
				}
	/* Before we sort by name, we need to handle the case of possible 
		duplicate values.  To do that, we build an dictionary keyed by
		the name, whose values are arrays.  Then we index into that
		array to get the actual values after sorting.
	*/	
				if (!href_index[hreftypes[n]]){
					href_index[hreftypes[n]]=[]
				}
				href_index[hreftypes[n]].push(href)
			}
		}
		n++
	}
	
	data=sortArrayByValue(data)
	for (d in data){
		Occur=d
		result_list.push('<li><b>'+datatypes[Occur]+": </b>"+data[d]+'\n')
	}

	hreftypes=sortArrayByValue(hreftypes)
	for (o in hreftypes){
		var hrefs=href_index[hreftypes[o]]
		for (h in hrefs){
			result_list.push('<li><a href="')
			result_list.push(hrefs[h]+'" target="_showResources">')
			result_list.push(hreftypes[o]+'</a>\n')
		}
	}		

	result_list.push('</ul>\n')
}

function formatAssociations(theTopic,result_list){
	var a,assocs,assoc,associd
	var assoctype,assoclabel
	var assoc_namelist={}
	var m,member,members
	var r,role,roles,roleid,rolename,rolelabel,roletopic
	var p,player,players
	var playername,playerlabel,playerid,playernames=[]
	var player_index={}
	var t,a,n
	var v,value,values
	var inverselist
	var name,names,n

	t=theTopic.id
	assocIndex=tm1.getAssocIndex()
	assocs=assocIndex[t]
	if (!assocs){return}

	for (a in assocs){
		result_list.push('<h3 class="compress">Relationships</h3>\n')
		break
	}

	// Build a list of association names (the basenames of their
	// types, if any), keyed by association id.
	for (a in assocs){
		associd=assocs[a]
		assoc=tm1.getAssocByID(associd)
		if (!assoc){continue}
		
		assoctype=assoc.instanceOf

		// Don't list subclass associations - they are done separately
		if (assoctype=='at-subclassof'){continue}		
		
		if (assoctype){
			assoclabel=getTypeLabelForObject(tm1,assoc)
		}
		else {
			assoclabel='(unnamed association)'
		}
		assoc_namelist[associd]=assoclabel
	}

	// Do iterations sorted by name - first we need a dictionary
	// keyed by the names - each value must be a list in case of duplicates
	inverselist=inverseKeys(assoc_namelist)

	// Next, we need a distinct list of the names
	names=[]
	for (v in inverselist){ // v is a name
		names.push(v)  // list of distinct names
	}

	names.sort()

	if (names.length){
		result_list.push('<ul>\n')
	}

	for (n in names) { // n=0,1,2,...
		assoctype_label=names[n]
		idlist=inverselist[assoctype_label]
		for (a in idlist){		
			associd=idlist[a]
			assoc=tm1.getAssocByID(associd)
			result_list.push('<li><h4 class="list"><b>'+assoctype_label+': </b>')
			result_list.push('</h4>\n<ul class="list">\n')

			members=assoc.getMembers()
			for (m in members){
				member=members[m]

				// Get id,name of role
				roleid=member.roleSpec
				rolelabel=getTopicLabelById(tm1,roleid)

				players=member.getPlayers()
				playernames=[]
				player_index={}
				for (p in players){
					player=players[p]
					if (!player){continue}
					playername=player.getNamesFiltered()
					playername = playername && playername[0]
					playerlabel=(playername && playername.name) || '[unnamed role player]'
					playerid=player.id
					playernames.push(playerlabel)
					player_index[playerlabel]=playerid
				}
				playernames.sort()

				if (playernames.length){
					for (p in playernames){
						playerid=player_index[playernames[p]]

						if (playerid==t){
							result_list.push('<li><b>'+rolelabel+': </b>(This topic)\n')
							continue
						}
						
						str=buildAnchorForTopic(playernames[p],
							'_showtopic',playerid,t)
						result_list.push('<li><b>'+rolelabel+': </b>'+str+'\n')
					}
				}
			}
			result_list.push('</ul>\n')
		}
	}
	if (names.length){
		result_list.push('</ul>\n')
	}

}

function formatInstances(theTopic,result_list){
	var t,Topic,topics,topicid
	var i,inst,instance,instances=[]
	var instance_name,instance_id,hasinstance
	var assocs,assocIndex,a,assoc
	var assocs_by_id={},assocnames=[],associd
	var hasinstance,hasassocs,flag
	var oc

	topicid=theTopic.id
	topics = top.tm1.getTopicsByType(topicid)
	for (t=0; t < topics.length; t++){
		instances.push(topics[t].id)
	}

	if (! instances.length){
		return
	}
	
	result_list.push('<h3>Instances</h3>\n')

	// Do some extra work to sort the instances by name
	var instance_namelist={}

	for (i=0; i <instances.length; i++){
		instance_id=instances[i]
		instance=tm1.getTopicById(instance_id)
		instance_name=instance.getNamesFiltered()[0]
		instance_name=instance_name&&instance_name.name
		instance_namelist[instance_id]=instance_name
	}

	instance_namelist=sortArrayByValue(instance_namelist)

	for (i in instance_namelist){
		instance=tm1.getTopicById(i)
		instance_name=instance_namelist[i]//instance.getNamesFiltered()[0].name
		instance_id=instance.id

		// Check if this instance topic has instances,
		// occurrences or associations.  If so, flag it visibly.		
		oc=instance.getOccursFiltered && instance.getOccursFiltered()
		if (!oc){
			oc=[]
		}
		hasassocs=hasAssociation(instance,tm1)
		hasinstance = instanceIndex[instance_id]

		flag=hasinstance||oc.length||hasassocs
		if (flag){
			instance_name='<b>'+instance_name+'</b>'
		}
		str=buildAnchorForTopic(instance_name,'_showtopic',instance_id,topicid)
		result_list.push(str+'<br>\n')
	}

	// If this is some kind of association topic, then list all
	// associations of that type
	if (theTopic.instanceOf=='tt-assoc'){
		assocs=tm1.getAssocByType(topicid)
		for (a in assocs){
			result_list.push('<h3>Instances</h3>\n')
			break
		}

		for (a in assocs){
			assoc=assocs[a]
			if (!assoc){continue}
			assocs_by_id[assoc.id]=assoc
			assocnames.push(assoc.id)
		}
		assocnames.sort()

		for (a in assocnames){
			associd=assocnames[a]
			assoc=assocs_by_id[associd]
			result_list.push(associd+'<br>\n')
			formatSingleAssoc(assoc,tm1,result_list)
		}
		
	}
}

function formatSingleAssoc(assoc,map,result_list){
	var m,member,members
	var r,role,roles,roleid,rolename,rolelabel,roletopic
	var p,player,players
	var playername,playerlabel,playerid,playernames=[]
	var player_index={}
	var t,a,n
	var v,value,values
	var inverselist
	var name,names,n
	var membernames=[],member_index={}
	members=assoc.getMembers()
	for (m in members){
		member=members[m]

		// Get id,name of role
		roleid=member.roleSpec
		rolelabel=getTopicLabelById(map,roleid)
		membernames.push(rolelabel)

		if (!member_index[rolelabel]){
			member_index[rolelabel]=[]
		}
		member_index[rolelabel].push(member)
	}
	
	membernames.sort()
	for (r in membernames){
		rolelabel=membernames[r]
		members=member_index[rolelabel] // List of members 
		for (m in members){
			member=members[m]

			players=member.getPlayers()
			playernames=[]
			player_index={}
			for (p in players){
				player=players[p]
				playername=player.getNamesFiltered()[0]
				playerlabel=playername.name
				playerid=player.id
				playernames.push(playerlabel)
				player_index[playerlabel]=playerid
			}
			playernames.sort()

			if (playernames.length){
				result_list.push('<ul class="list">\n')
				for (p in playernames){
					playerid=player_index[playernames[p]]						
					str=buildAnchorForTopic(playernames[p],
						'_showtopic',playerid,t)
					result_list.push('<li><b>'+rolelabel+': </b>'+str+'\n')
				}
				result_list.push('</ul>\n')
			}
		}
	}		
}


function formatScopes(theTopic,result_list){
	var s,scopes,Scope,scopetopic,scopename,scopenames
	var name
	var yesno={}
	yesno[false]=', ';yesno[true]=''

	name=theTopic.getNamesFiltered()[0]
	scopes=name.getScopes()
	scopenames=''
	for (s in scopes){
		scopetopic=tm1.getTopicById(scopes[s].topic)
		scopename=scopetopic.getNamesFiltered&&scopetopic.getNamesFiltered()[0].name
		if (!scopename){
			scopename='All-scopes'
		}
		if (scopename!='All-scopes'){			
			scopenames+=yesno[scopenames=='']+scopename
		}
	}

	if (scopenames){
		result_list.push('<h3>Scopes</h3>\n')
		result_list.push(scopenames)
	}
}

function formatSubclasses(theTopic,result_list){
	var Node=new node(theTopic)
	subclassTree(tm1,Node)
	//hierarchyTree(tm1,Node,'at-subclassof','rt-superclass','rt-subclass')

	var str=walkHierarchySort(tm1,Node,buildList)
	if (str){
		result_list.push('<div><h3>Subclasses</h3>')
		result_list.push(str)
		result_list.push('</div>')
	}
}

/*function formatPerspectives(theTopic,result_list){
	var Node=new node(theTopic)
	hierarchyTree(tm1,Node,'at-bookmark-perspective','rt-concept','rt-perspective')

	var str=walkHierarchySort(tm1,Node,buildList)
	if (str){
		result_list.push('<div><h3>Bookmarks</h3>')
		result_list.push(str)
		result_list.push('</div>')
	}
}

function showPerspectiveAncestors(theTopic,result_list){
	var Node=new node(theTopic)
	hierarchyAncestorTree(tm1,Node,'at-bookmark-perspective','rt-concept','rt-perspective')
	var kids=Node.getChildren()
	if (kids.length){
		Node = kids[0]
	}
	else {return}

	var str=walkHierarchyReverse(tm1,Node,buildContextList)
	if (str){
		result_list.push('<div><b>Bookmark Context - </b>')
		result_list.push(str)
		result_list.push('</div>')
	}
}
*/

//===============================================
function buildList(map,Node,depth){
	var indentStr='&nbsp;&nbsp;&nbsp;&nbsp;'
	var NL='<br>'
	var Topic=Node.topic
	var str=''
	var label
	var indent=''
	var hasInfo
	for (var i=0;i<depth;i++){indent+=indentStr}

	//Topic=Node.topic
	label=Topic.getNamesFiltered()[0].name
	hasInfo=hasInstance(Topic,tm1)||hasOccurrence(Topic)||hasAssociation(Topic,tm1)
	if (hasInfo){
			label='<b>'+label+'</b>'
	}
	str=indent+buildAnchorForTopic(label,'',Topic.id)+NL
	return str
}


function buildContextList(map,Node,depth){
	var Topic=Node.topic
	var str=''
	var label
	var SEP = ""
	var hasInfo

	if (depth > 0){
		SEP = "::"
	}

	//Topic=Node.topic
	label=Topic.getNamesFiltered()[0].name
	if ( !label){
		return ''
	}
	str=SEP + buildAnchorForTopic(label,'',Topic.id)
	return str

}

//===============================================
