function RosterGroup(name,r_orgid,parno) {
  this.name = htmlEnc(name);
  this.r_orgid = r_orgid;
  this.parno = parno;
  this.users = new Array();
  this.onlUserCount = 0;
  this.messagesPending = 0;
  this.subGroup = 0;
}

function RosterUserAdd2Group(group) {
  this.groups = this.groups.concat(group);
}

function RosterUser(jid,subscription,groups,name) {

  this.fulljid = jid;
  this.jid = cutResource(jid) || 'unknown';
  this.jid = this.jid.toLowerCase(); // jids are case insensitive

  this.subscription = subscription || 'none';
  this.groups = groups || [new RosterGroup('临时好友','','')];

  if (name)
    this.name = name;
  else if (this.jid == UMWEBSERVER)
    this.name = "系统";
  else if ((this.jid.indexOf('@') != -1) && 
           this.jid.substring(this.jid.indexOf('@')+1) == UMWEBSERVER) // we found a local user
    this.name = this.jid.substring(0,jid.indexOf('@'));
  else
    this.name = this.jid;

	for(var i=0; i<apperceive_users.length;i++){
		if(apperceive_users[i][1] + "@" +UMWEBSERVER == this.jid && typeof apperceive_users[i].displayName != "undefined" && apperceive_users[i].displayName != ""){
			this.name = apperceive_users[i].displayName;
		}
	}
  this.name = htmlEnc(this.name);

  // initialise defaults
  this.status = (this.subscription == 'from' || this.subscription == 'none') ? 'stalker' : 'unavailable';
  this.statusMsg = "[留言]";
  this.mind = null;
  this.lastsrc = null;
  this.messages = new Array();
  this.chatmsgs = new Array();
  this.fileMsg = "";
  this.cFrame = null; // chat window
  this.oldStatus = "";
  this.msgid = 0;
  this.windowId = "";

  // methods
  this.add2Group = RosterUserAdd2Group;

}

function getElFromArrByProp(arr,prop,str) {
  for (var i=0; i<arr.length; i++) {
    if (arr[i][prop] == str)
      return arr[i];
  }
  return null;
}

function getRosterGroupByName(groupName) {
  return getElFromArrByProp(this.groups,"name",groupName);
}

function getRosterUserByJID(jid) {
  return getElFromArrByProp(this.users,"jid",jid.toLowerCase());
}

function RosterUpdateStyleIE() {
  if(!is.ie)
    return;
  this.rosterW.getElementById("roster").style.width = this.rosterW.body.clientWidth;
}

function RosterGetUserIcons(from) {
  var images = new Array();
  
  for (var i=0; i<this.groups.length; i++) {
    var img = this.rosterW.images[from+"/"+this.groups[i].name];
    if (img) {
      images = images.concat(img);
      continue; // skip this group
    }
  }
  return images;
}

function RosterToggleHide() {
  this.usersHidden = !this.usersHidden;
  this.print();
  return;
}
	
function RosterToggleGrp(name) {
  var el = this.rosterW.getElementById(name);
  if (el.className == 'hidden') {
    el.className = 'rosterGroup';
    this.hiddenGroups[name] = false;
    this.rosterW.images[name+"Img"].src = grp_open_img.src;
  } else {
    el.className = 'hidden';
    this.hiddenGroups[name] = true;
    this.rosterW.images[name+"Img"].src = grp_close_img.src;
  }
  this.updateStyleIE();
}

function RosterOpenMessage(jid) {
  var user = this.getUserByJID(jid);
  var wName = makeWindowName(user.jid); 

  if (user.messages.length > 0 && (!user.mW || user.mW.closed)) // display messages
    user.mW = open('/umservice/message.html?jid='+escape(jid),
                   "mw"+wName,
                   'width=360,height=270,dependent=yes,resizable=yes');
  else if (!user.sW || user.sW.closed) // open send dialog
    user.sW = open("http://" + hostPath + "/umservice/send.html?jid="+escape(jid),
                   "sw"+wName,
                   'width=320,height=200,dependent=yes,resizable=yes');
  return false;
}

function RosterOpenChat(jid) {

  var user = this.getUserByJID(jid);

  if (!user)
    return;

  /*if (user.messages.length > 0 && (!user.mW || user.mW.closed)) // display messages
    this.openMessage(jid);*/
    if(arguments.length == 2){
    	startChat(jid,user,arguments[1]);
    }else{
  		startChat(jid,user);
    }
}

function RosterCleanUp() {
  for (var i=0; i<this.users.length; i++) {
    if (this.users[i].roster)
      this.users[i].roster.cleanUp();
    if (this.users[i].sW)
      this.users[i].sW.close();
    if (this.users[i].mW)
      this.users[i].mW.close();
    if (this.users[i].histW)
      this.users[i].histW.close();
  }
}

function RosterUpdateGroupForUser(user) {
  for (var j=0; j<user.groups.length; j++) {
    if (user.groups.length > 1 && user.groups[j].name == '临时好友')
      continue;
    var groupName = user.groups[j].name;
    var group = this.getGroupByName(groupName);
    if(group == null) {
      group = user.groups[j];
      group.users = new Array();
      this.groups = this.groups.concat(group);
    }
    group.users = group.users.concat(user);
  }
}
	
function RosterUpdateGroups() {
  var oldGroups = this.groups;
  this.groups = new Array();
  for (var i=0; i<this.users.length; i++)
    this.updateGroupsForUser(this.users[i]);
  // remove elements for groups that don't exist anymore
  for (var i=0; i<oldGroups.length; i++) {
    var remove = true;
    for (var j=0; j<this.groups.length; j++) {
      if (oldGroups[i].name == this.groups[j].name) {
        remove = false;
        break;
}
    }
    if (remove) {
      var rosterEl = this.rosterW.getElementById('roster');
      var groupHeaderEl = this.rosterW.getElementById(oldGroups[i].name+'Head');
      var groupEl = this.rosterW.getElementById(oldGroups[i].name);
      rosterEl.removeChild(groupHeaderEl);
      rosterEl.removeChild(groupEl);
    }
  }
}

function RosterUserAdd(user) {
  this.users = this.users.concat(user);
	
  // add to groups
  this.updateGroupsForUser(user);
  return user;
}

function RosterRemoveUser(user) {
  var uLen = this.users.length;
  for (var i=0; i<uLen; i++) {
    if (user == this.users[i]) {
      this.users = this.users.slice(0,i).concat(this.users.slice(i+1,uLen));
      // remove user element
      for (var j=0; j < user.groups.length; j++) {
        var groupName = user.groups[j].name;
        var groupEl = this.rosterW.getElementById(groupName);
        var userEl = this.rosterW.getElementById(getUserElementId(user, user.groups[j]));
        if (groupEl && userEl) { groupEl.removeChild(userEl); }
      }
      break;
    }
  }
  this.updateGroups();
}

function RosterGetGroupchats() {
  var groupchats = new Array();
  for (var i=0; i<this.users.length; i++)
    if (this.users[i].roster)
      groupchats[groupchats.length] = this.users[i].jid+'/'+this.users[i].roster.nick;
  return groupchats;
}
	
function Roster(items,targetW) {
  this.users = new Array();
  this.groups = new Array();
  this.hiddenGroups = new Array();
  this.name = 'Roster';

  this.rosterW = targetW;
  this.lastUserSelected = null; // moved into Roster from iRoster.html and groupchat_iroster.html - sam

  /* object's methods */
  this.print = printRoster;
  this.update = updateRoster;
  this.childGroup = childGroupCount;
  this.pool = poolPrint;
  this.getGroupByName = getRosterGroupByName;
  this.getUserByJID = getRosterUserByJID;
  this.addUser = RosterUserAdd;
  this.removeUser = RosterRemoveUser;
  this.updateGroupsForUser = RosterUpdateGroupForUser;
  this.updateGroups = RosterUpdateGroups;
  this.toggleGrp = RosterToggleGrp;
  this.updateStyleIE = RosterUpdateStyleIE;
  this.toggleHide = RosterToggleHide;
  this.getUserIcons = RosterGetUserIcons;
  this.openMessage = RosterOpenMessage;
  this.openChat = RosterOpenChat;
  this.cleanUp = RosterCleanUp;
  this.getGroupchats = RosterGetGroupchats;
  this.selectUser = RosterSelectUser; // moved into Roster from iRoster.html and groupchat_iroster.html - sam
  this.userClicked = RosterUserClicked;

  /* setup groups */
  if (!items)
    return;
  for (var i=0;i<items.length;i++) {
    if(items.item(i).nodeName == 'item'){
	    /* if (items[i].jid.indexOf("@") == -1) */ // no user - must be a transport
	    if (typeof(items.item(i).getAttribute('jid')) == 'undefined')
	      continue;
		if(this.getUserByJID(cutResource(items.item(i).getAttribute('jid')))){
			var user = this.getUserByJID(cutResource(items.item(i).getAttribute('jid')));
		    for (var j=0;j<items.item(i).childNodes.length;j++)
				if (items.item(i).childNodes.item(j).nodeName == 'group' && items.item(i).childNodes.item(j).firstChild){
					var r_orgid = "";
					var parno = "";
					var groupName = items.item(i).childNodes.item(j).firstChild.nodeValue;
					var group = this.getGroupByName(groupName);
					if(group == null){
						if(items.item(i).childNodes.item(j).getAttribute('orgid'))
							r_orgid = items.item(i).childNodes.item(j).getAttribute('orgid');
						if(items.item(i).childNodes.item(j).getAttribute('parno'))
							parno = items.item(i).childNodes.item(j).getAttribute('parno');
						group=new RosterGroup(groupName,r_orgid,parno);
						this.groups = this.groups.concat(group);
					}
					group.users = group.users.concat(user);
					user.add2Group(group);
				}
		}else{
		    var name = items.item(i).getAttribute('name') || cutResource(items.item(i).getAttribute('jid'));
		    var groups = new Array(new RosterGroup('临时好友','',''));
		    for (var j=0;j<items.item(i).childNodes.length;j++)
				if (items.item(i).childNodes.item(j).nodeName == 'group' && items.item(i).childNodes.item(j).firstChild){
					var r_orgid = "";
					var parno = "";
					var groupName = items.item(i).childNodes.item(j).firstChild.nodeValue;
					if(items.item(i).childNodes.item(j).getAttribute('orgid'))
						r_orgid = items.item(i).childNodes.item(j).getAttribute('orgid');
					if(items.item(i).childNodes.item(j).getAttribute('parno'))
						parno = items.item(i).childNodes.item(j).getAttribute('parno');
					groups = groups.concat(new RosterGroup(groupName,r_orgid,parno));
				}
		    this.addUser(new RosterUser(items.item(i).getAttribute('jid'),items.item(i).getAttribute('subscription'),groups,name));
	    }
	  }else{
	  	for(var j = 0;j<items.item(i).childNodes.length;j++){
	  		var r_orgid = "";
			var parno = "";
			var groupName = items.item(i).childNodes.item(j).getElementsByTagName("orgname").item(0).firstChild.nodeValue;
			var group = this.getGroupByName(groupName);
			if(group == null){
				r_orgid = items.item(i).childNodes.item(j).getElementsByTagName("orgid").item(0).firstChild.nodeValue;
				parno = items.item(i).childNodes.item(j).getElementsByTagName("parno").item(0).firstChild ? items.item(i).childNodes.item(j).getElementsByTagName("parno").item(0).firstChild.nodeValue : "";
				group=new RosterGroup(groupName,r_orgid,parno);
				this.groups = this.groups.concat(group);
			}
	  	}
	  }
  }
}

function rosterSort(a,b) {
	if(typeof a.jid == "undefined"){
		return (a.name.toLowerCase()<b.name.toLowerCase())?-1:1;
	}else{
		if(a.status != b.status){
			if(a.status == "stalker" || (a.status == "unavailable" && b.status != "stalker")){
				return 1;
			}else{
				return 0;
			}
		}else{
			return 0;
		}
	}
}

function printRoster() {
	
	/* update user count for groups */
	for (var i=0; i<this.groups.length; i++) {
		this.groups[i].onlUserCount = 0;
		this.groups[i].messagesPending = 0;
		this.groups[i].subGroup = 0;
		if(this.groups[i].r_orgid != "" && this.groups[i].parno == ""){
			this.childGroup(this.groups[i]);
		}
		for (var j=0; j<this.groups[i].users.length; j++) {
		  if (this.groups[i].users[j].status != 'unavailable' && this.groups[i].users[j].status != 'stalker')
		    this.groups[i].onlUserCount++;
		  if (this.groups[i].users[j].lastsrc)
		    this.groups[i].messagesPending++;
		}
	}
	//this.groups = this.groups.sort(rosterSort);

	if (this.rosterW.getElementById('roster').innerHTML.search(/\S/) > -1) {
	  this.update(); // update dom, rather than redrawing roster
	  return;
	}

	var A = new Array();

	/* ***
	 * loop rostergroups 
	 */
  	for (var i=0; i<this.groups.length; i++) {
    	if(this.groups[i].r_orgid!="" && this.groups[i].parno == ""){
    		this.pool(A,this.groups[i]);
    	}
	}
  	for (var i=0; i<this.groups.length; i++) {
    	if(this.groups[i].r_orgid =="" && this.groups[i].parno == ""){
    		this.pool(A,this.groups[i]);
    	}
	}
	this.rosterW.getElementById("roster").innerHTML = A.join('');
	this.updateStyleIE();
}
function childGroupCount(group){
	for(var i = 0; i<this.groups.length; i++){
		if(this.groups[i].parno == group.r_orgid){
			group.subGroup++;
			this.childGroup(this.groups[i]);
		}
	}
}
function poolPrint(A,group){
	var rosterGroupHeadClass = getRosterGroupHeaderClass(this.usersHidden,group);
  	A[A.length] = "<div id='";
	A[A.length] = group.name;
	A[A.length] = "Head' class='";
	A[A.length] = rosterGroupHeadClass;
	A[A.length] = "' onClick='toggleGrp(\"";
	A[A.length] = group.name;
	A[A.length] = "\");'><nobr>";
    var toggleImg = (this.hiddenGroups[group.name])?basePath + 'images/group_close.gif':basePath + 'images/group_open.gif';
    A[A.length] = "<img src='";
	A[A.length] = toggleImg;
	A[A.length] ="' name='";
	A[A.length] = group.name;
	A[A.length] = "Img'> ";
   	A[A.length] = group.name;
	A[A.length] = " (<span id='";
	A[A.length] = group.name;
	A[A.length] = "On'>";
	A[A.length] = group.onlUserCount;
	A[A.length] = "</span>/<span id='";// put total number in span - sam
    A[A.length] = group.name;
    A[A.length] = "All'>";
	A[A.length] = group.users.length;
	A[A.length] = "</span>)";
	A[A.length] = "</nobr></div>";
	var rosterGroupClass = ((this.usersHidden && group.onlUserCount == 0 && group.messagesPending == 0 && 
		     group.name != "网关") || this.hiddenGroups[group.name] || (group.r_orgid != "" && group.users.length == 0))
	? 'hidden':'rosterGroup';
	A[A.length] =  "<div id='";
	A[A.length] = group.name;
	A[A.length] = "' class='";
	A[A.length] = rosterGroupClass;
	A[A.length] = "'>";
	group.users = group.users.sort(rosterSort);

	/* ***
	 * loop users in rostergroup 
	 */
    for (var j=0; j<group.users.length; j++) {
		var user = group.users[j];
		if(document.getElementsByName(user.jid+"apperceive").length>0){
			apperceive_content(user);
        }
		var rosterUserClass = getRosterUserClass(this.usersHidden, user, group);
		A[A.length] = "<div id=\"";
		A[A.length] = htmlEnc(user.jid);
		A[A.length] = "/";
		A[A.length] = group.name;
		A[A.length] = "Entry\" class=\"";
		A[A.length] = rosterUserClass;
		A[A.length] = "\" onClick=\"selectUser(this);\" ondblclick=\"return userClicked(this,'";
		A[A.length] = htmlEnc(user.jid);
		A[A.length] = "');\" title=\"";
		A[A.length] = getUserElementTitle(user);
		A[A.length] = "\">";
		var userImg = (user.lastsrc) ? messageImg : eval(user.status + "Led");
		A[A.length] = "<nobr><img src=\"";
		A[A.length] = userImg.src;
		A[A.length] = "\" name=\"";
		A[A.length] = htmlEnc(user.jid);
		A[A.length] = "/";
		A[A.length] = group.name;
		A[A.length] = "\" width='16' height='16' border='0' align='left'>";
		A[A.length] = "<span class=\"nickName\">";
		A[A.length] = user.name;
		A[A.length] = "</span><span class=\"statusMsg\">";

		if (user.mind) {
	        A[A.length] = "(";
			A[A.length] = htmlEnc(user.mind);
			A[A.length] = ")";
		}else if(user.statusMsg){
			A[A.length] = htmlEnc(user.statusMsg);
		}
	    A[A.length] =  "</span></nobr></div>";
	} /* END inner loop */
    A[A.length] =  "</div>";
	for (var i=0; i<this.groups.length; i++) {
    	if(this.groups[i].parno!="" && this.groups[i].parno == group.r_orgid){
    		this.pool(A,this.groups[i]);
    	}
	}
}
function getUserElementId(user, group) {
  var groupName = group.name || '临时好友';
  return htmlEnc(user.jid)+"/"+groupName+"Entry";
}

function getRosterUserClass(usersHidden, user, group) {
  return (usersHidden && (user.status == 'unavailable' || user.status == 'stalker') && !user.lastsrc && group.name != "网关" ?
          "hidden" : "rosterUser");
}

function getRosterGroupHeaderClass(usersHidden, group) {
  return (((usersHidden && group.onlUserCount == 0 && group.messagesPending == 0 && group.name != "网关") || (group.r_orgid != "" && group.users.length == 0)) ?
         'hidden':'rosterGroupHeader');
}

function getUserElementTitle(user) {
	var elTitle = "称呼：" + user.name;
	if (user.realjid) {
		elTitle += "\n账号: ";
		elTitle += htmlEnc(user.realjid);
	} else {
		elTitle += "\n账号: ";
		elTitle += htmlEnc(user.jid);
	}
	elTitle += "\n状态: ";
	elTitle += user.status;
	if (user.mind) {
		elTitle += "\n消息: ";
		elTitle += htmlEnc(user.mind);
	}else if (user.statusMsg) {
		elTitle += "\n消息: ";
		elTitle += htmlEnc(user.statusMsg);
	}
	if ((user.messages.length + user.chatmsgs.length) > 0) {
		elTitle += "\n";
		elTitle += ""+(user.messages.length + user.chatmsgs.length)+" 条消息";
	}
	return elTitle;
}

function getUserInnerHTML(user, group) {
  var userImg = (user.lastsrc) ? messageImg : eval(user.status + "Led");
  var A = new Array();
  A[A.length] = "<nobr><img src=\"";
  A[A.length] = userImg.src;
  A[A.length] = "\" name=\"";
  A[A.length] = htmlEnc(user.jid);
  A[A.length] = "/";
  A[A.length] = group.name;
  A[A.length] = "\" width='16' height='16' border='0' align='left'>";
  A[A.length] = "<span class=\"nickName\">";
  A[A.length] = user.name;
  A[A.length] = "</span><span class=\"statusMsg\">";

  if (user.mind) {
    A[A.length] = "(";
    A[A.length] = htmlEnc(user.mind);
    A[A.length] = ")";
  }else if (user.statusMsg) {
    A[A.length] = htmlEnc(user.statusMsg);
  }
  A[A.length] =  "</span></nobr>";
  return A.join('');
}

function updateRoster() {
  Debug.log('updating roster',2);
  for (var i=0; i<this.groups.length; i++) {
    var group = this.groups[i];
    group.users.sort(rosterSort);
    var groupEl = this.rosterW.getElementById(group.name);
    if (groupEl) { // update group
      var A = new Array();
      for (var j=0; j<group.users.length; j++) {
        var user = group.users[j];
		if(document.getElementsByName(user.jid+"apperceive").length>0){
			apperceive_content(user);
        }
        A[A.length] = "<div id=\"";
        A[A.length] = htmlEnc(user.jid);
        A[A.length] = "/";
        A[A.length] = group.name;
        A[A.length] = "Entry\" class=\"";
        A[A.length] = getRosterUserClass(this.usersHidden, user, group);
        A[A.length] = "\" onClick=\"selectUser(this);\" ondblclick=\"return userClicked(this,'";
        A[A.length] = htmlEnc(user.jid);
        A[A.length] = "');\" title=\"";
        A[A.length] = getUserElementTitle(user);
        A[A.length] = "\">";
        A[A.length] = getUserInnerHTML(user, group);
        A[A.length] =  "</div>";
      } /* END inner loop */
      groupEl.innerHTML = A.join(''); // done with users
      
      var groupHeaderEl = this.rosterW.getElementById(group.name+'Head');
      if (groupHeaderEl) {
        groupHeaderEl.className = getRosterGroupHeaderClass(this.usersHidden, group);

        if (this.rosterW.getElementById(group.name+'On')) 
          this.rosterW.getElementById(group.name+'On').innerHTML = group.onlUserCount;
        if (this.rosterW.getElementById(group.name+'All'))
          this.rosterW.getElementById(group.name+'All').innerHTML = group.users.length;
      }
    } else { // add group
      var groupHeaderEl = this.rosterW.createElement('div');
      groupHeaderEl.id = group.name+"Head";
      groupHeaderEl.className = getRosterGroupHeaderClass(this.usersHidden, group);
      var onclickHandler = function(group) {
        var groupName = group.name;
        var toggler = function() { parent.top.roster ? parent.top.roster.toggleGrp(groupName) : (parent.roster ?  parent.roster.toggleGrp(groupName) : roster.toggleGrp(groupName)); };
        return toggler;
      }
      groupHeaderEl.onclick = onclickHandler(group);
      var A = new Array();
      A[A.length] = "<nobr>";
      var toggleImg = (this.hiddenGroups[group.name])?basePath + 'images/group_close.gif':basePath + 'images/group_open.gif';
      A[A.length] = "<img src='";
      A[A.length] = toggleImg;
      A[A.length] ="' name='";
      A[A.length] = group.name;
      A[A.length] = "Img'> ";
      A[A.length] = group.name;
      A[A.length] = " (<span id='";
      A[A.length] = group.name;
      A[A.length] = "On'>";
      A[A.length] = group.onlUserCount;
      A[A.length] = "</span>/<span id='";// put total number in span, also - sam
      A[A.length] = group.name;
      A[A.length] = "All'>";
      A[A.length] = group.users.length;
      A[A.length] = "</span>)";
      A[A.length] = "</nobr>";
      groupHeaderEl.innerHTML = A.join('');

      groupEl = this.rosterW.createElement('div');
      groupEl.id = group.name;
      var rosterGroupClass = ((this.usersHidden && group.onlUserCount == 0 && group.messagesPending == 0 &&
             group.name != "网关") || this.hiddenGroups[group.name] || (group.r_orgid != "" && group.users.length == 0))
        ? 'hidden':'rosterGroup';
      groupEl.className = rosterGroupClass;

      A = new Array();
      for (var j=0; j<group.users.length; j++) {
        var user = group.users[j];
		if(document.getElementsByName(user.jid+"apperceive").length>0){
			apperceive_content(user);
        }
        A[A.length] = "<div id=\"";
        A[A.length] = htmlEnc(user.jid);
        A[A.length] = "/";
        A[A.length] = group.name;
        A[A.length] = "Entry\" class=\"";
        A[A.length] = getRosterUserClass(this.usersHidden, user, group);
        A[A.length] = "\" onClick=\"selectUser(this);\" ondblclick=\"return userClicked(this,'";
        A[A.length] = htmlEnc(user.jid);
        A[A.length] = "');\" title=\"";
        A[A.length] = getUserElementTitle(user);
        A[A.length] = "\">";
        A[A.length] = getUserInnerHTML(user, group);
        A[A.length] =  "</div>";
      } /* END inner loop */
      groupEl.innerHTML = A.join('');

      var siblingEl;
      var j = i + 1;
      while (!siblingEl && j < this.groups.length) {
      	if(this.groups[j].parno == ""){
        	siblingEl = this.rosterW.getElementById(this.groups[j].name+'Head');
        }
        j++;
      }
      var rosterEl = this.rosterW.getElementById("roster");
      if (!siblingEl) {
        rosterEl.appendChild(groupHeaderEl)
        rosterEl.appendChild(groupEl);
      } else {
        rosterEl.insertBefore(groupHeaderEl, siblingEl);
        rosterEl.insertBefore(groupEl, siblingEl);
      }
    }
  }
}

// moved into Roster from iRoster.html and groupchat_iroster.html - sam
function RosterSelectUser(el) {
  if(this.lastUserSelected)
    this.lastUserSelected.className = "rosterUser";
  el.className = "rosterUserSelected";
  this.lastUserSelected = el;
}

function RosterUserClicked(el,jid) {
	/*var winObj=parent.top.roster ? parent.top : (parent.roster ?  parent : window);
	if (this.name == 'GroupchatRoster') {
		return winObj.user.roster.openChat(jid);
	}*/
	if(l && el.name && el.name.indexOf("apperceive")>0 && (typeof pass == "undefined"  || pass == "")){
		handleLog(window.event,"该用户拒绝和匿名用户对话，请先登录！",getLeft(el),getTop(el)+el.offsetHeight);
		return;
	}
	var hide_div=document.getElementById("hide_div");
    if(hide_div.style.display!="block"){
        hide_div.style.display="block";
        if(flag != 0){
        	dd.elements.service_logo.hide();
        }
    }
	var user = this.getUserByJID(cutResource(jid));
	if (user == null) {// users not in roster (yet)
        user = roster.addUser(new RosterUser(jid));
        roster.print();
    }
    //设置该用户聊天窗口居中
    if(arguments.length==3 && arguments[2]==1){
    	user.position = "center";
    }
		iq = new JSJaCIQ();
	    iq.setIQ(null, "get", "roster_1");
	    iq.appendNode("query", {xmlns:"jabber:iq:webroster"}, [["uins", [["uin",jid.substring(0,jid.indexOf("@"))]]]]);
	    con.send(iq);
	if (user && typeof (user.type) != "undefined" && user.type == "groupchat") {
		return openGroupchat(jid);
	}
	if(user.cFrame){
		this.openChat(jid);
		popMsgs(user);
	}else{
		this.openChat(jid,"1");
	}
	return;
}

function apperceive_content(user){
	var tempStr = "";
	if(typeof thisSiteURL == "undefined"){
           var tempimg = eval(user.status + "Led");
           tempStr = "<nobr><img src=\"" + tempimg.src + "\" width=\"16\" height=\"16\" align=\"absmiddle\" border=\"0\">"
                       + "<span class=\"nickName\">" + user.name + "</span><span class=\"statusMsg\">";
           if (user.mind) {
               tempStr += "(";
               tempStr += htmlEnc(user.mind);
               tempStr += ")";
           }else if(user.statusMsg){
               tempStr += htmlEnc(user.statusMsg);
           }
          	tempStr +=  "</span></nobr>";
          }else{
          	if(user.status == 'unavailable' || user.status == 'stalker'){
          		tempStr = "<nobr><img src=\"" + thisSiteURL + "images\/unavailable.gif\" align=\"absmiddle\" border=\"0\"></nobr>";
          	}else{
          		tempStr = "<nobr><img src=\"" + thisSiteURL + "images\/available.gif\" align=\"absmiddle\" border=\"0\"></nobr>";
          	}
          }
	//tempobj.ondblclick = function(){
		//if(confirm("是否匿名交谈？")){
			//this.userClicked(tempobj,user.jid);
		/*}else{
			showWindowItem("login");
			windowMaximizeZ("login");
		}*/
	//}
	for(var k=0; k<document.getElementsByName(user.jid+"apperceive").length; k++){
           var tempobj = document.getElementsByName(user.jid+"apperceive")[k];
           tempobj.innerHTML = tempStr;
      	}
}

/***********************************************************************
 * GROUPCHAT ROSTER
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 */
function GCRosterSort(a,b) {
  return (a.name.toLowerCase()<b.name.toLowerCase())?-1:1;
}

function GroupchatRosterPrint() {
  var A = new Array();
  
  this.groups = this.groups.sort(GCRosterSort);

  /* ***
   * loop rostergroups 
   */
  for (var i=0; i<this.groups.length; i++) {
    var rosterGroupHeadClass = (this.groups[i].users.length == 0) ? 'rosterGroupHeaderHidden':'rosterGroupHeader';

    A[A.length] = "<div id='";
		A[A.length] = this.groups[i].name;
		A[A.length] = "Head' class='";
		A[A.length] = rosterGroupHeadClass;
		A[A.length] = "'><nobr>&nbsp;";
    A[A.length] = this.groups[i].users.length;
		A[A.length] = " ";
		A[A.length] = this.groups[i].name;
    A[A.length] = "</nobr></div>";
    A[A.length] = "<div id='";
		A[A.length] = this.groups[i].name;
		A[A.length] = "' class='rosterGroup'>";
    
    this.groups[i].users = this.groups[i].users.sort(rosterSort);

		/* ***
		 * loop users in rostergroup 
		 */
    for (var j=0; j<this.groups[i].users.length; j++) {
      var user = this.groups[i].users[j];
      var rosterUserClass = (this.usersHidden && 
			     (user.status == 'unavailable' || 
			      user.status == 'stalker') && 
			     !user.lastsrc) 
	? "hidden":"rosterUser";
      
      A[A.length] = "<div id=\"";
			A[A.length] = htmlEnc(user.jid);
			A[A.length] = "/";
			A[A.length] = this.groups[i].name;
			A[A.length] = "Entry\" class=\"";
			A[A.length] = rosterUserClass;
			A[A.length] = "\" onClick=\"selectUser(this);\" ondblclick=\"return userClicked(this,'";
			A[A.length] = htmlEnc(user.jid).replace(/\'/g,"\\\'")+"');\" title=\"";
			A[A.length] = user.name;
			if (user.realjid) {
				A[A.length] = "&#10;JID: ";
				A[A.length] = htmlEnc(user.realjid);
			} else {
				A[A.length] = "&#10;JID: ";
				A[A.length] = htmlEnc(user.jid);
			}
			A[A.length] = "&#10;";
			A[A.length] = "状态";
			A[A.length] = ": ";
			A[A.length] = user.status;
	if (user.mind) {
        A[A.length] = "&#10;";
		A[A.length] = "消息";
		A[A.length] = ": ";
		A[A.length] = htmlEnc(user.mind);
	}else if (user.statusMsg) {
        A[A.length] = "&#10;";
		A[A.length] = "消息";
		A[A.length] = ": ";
		A[A.length] = htmlEnc(user.statusMsg);
	}
			if ((user.messages.length + user.chatmsgs.length) > 0) {
				A[A.length] = "&#10;";
				A[A.length] = ""+(user.messages.length + user.chatmsgs.length)+" 条消息";
			}
      A[A.length] = "\"><nobr>";
      var userImg = (user.lastsrc) ? messageImg : eval(user.status + "Led");
      A[A.length] = "<img src=\"";
			A[A.length] = userImg.src;
			A[A.length] = "\" name=\"";
			A[A.length] = htmlEnc(user.jid);
			A[A.length] = "/";
			A[A.length] = this.groups[i].name;
			A[A.length] = "\" width=16 height=16 border=0 align=\"left\">";
      A[A.length] = "<div><span class=\"nickName\">";
			A[A.length] = user.name;
			A[A.length] = "</span>";
	if (user.mind) {
        A[A.length] = "<nobr style=\"padding-left:5px;\"><span class=\"statusMsg\">(";
		A[A.length] = htmlEnc(user.mind);
		A[A.length] = ")</span></nobr>";
	}else if (user.statusMsg) {
        A[A.length] = "<nobr style=\"padding-left:5px;\"><span class=\"statusMsg\">";
		A[A.length] = htmlEnc(user.statusMsg);
		A[A.length] = "</span></nobr>";
	}
      A[A.length] = "</div></nobr></div>";
    } /* END inner loop */
    A[A.length] = "</div>";
  }

  this.rosterW.getElementById("roster").innerHTML = A.join('');
  this.updateStyleIE();
}

function GroupchatRosterUserAdd2Group(group) {
  this.groups = [group];
}

function GroupchatRosterUser(jid,name) {
  this.base = RosterUser;
  this.base(jid,'',[''],name);
	this.jid = this.fulljid; // always use fulljid
  this.affiliation = 'none';
  this.role = 'none';

  this.add2Group = GroupchatRosterUserAdd2Group;
}

GroupchatRosterUser.prototype = new RosterUser;

function getRosterGetRealJIDByNick(nick) {
  for (var i=0; i<this.users.length; i++)
    if (this.users[i].name == nick)
      return this.users[i].realjid;
  return null;
}

function getRosterGetFullJIDByNick(nick) {
  for (var i=0; i<this.users.length; i++)
    if (this.users[i].name == nick)
      return this.users[i].fulljid;
  return null;
}
			
function getGroupchatRosterUserByJID(jid) {
  // need to search fulljid here
  return getElFromArrByProp(this.users,"fulljid",jid);
}

function GroupchatRoster(targetW) {

  this.base = Roster;
  this.base(null);
  this.usersHidden = true;

  this.targetW = targetW.frames.groupchatRoster;

  this.rosterW = this.targetW.groupchatIRoster.document;

  this.name = 'GroupchatRoster';

  this.print = GroupchatRosterPrint;
  this.getUserByJID = getGroupchatRosterUserByJID;
  this.getRealJIDByNick = getRosterGetRealJIDByNick;
  this.getFullJIDByNick = getRosterGetFullJIDByNick;
}

GroupchatRoster.prototype = new Roster();

// some images - no idea why they are defined here

var messageImg = new Image();
messageImg.src = basePath + "images/message.gif";
var grp_open_img = new Image();
grp_open_img.src = basePath + 'images/group_open.gif';
var grp_close_img = new Image();
grp_close_img.src = basePath + 'images/group_close.gif';
var arrow_right_blinking = new Image();
arrow_right_blinking.src = basePath + 'images/arrow_right_blinking.gif';

