// library of functions used to join a session

// <!-- ==================
// join this session -- get sessionNode, and then call joinSession(). Sets the sessName and sessionNode globals

function joinSession0(useme) {
    sessName=useme.replace(/\..*/,'');                  // sessname is global
    var toget=getSessionDescriptorURL+sessName ;
    Get_xmlFile(toget,'sessionNode','retrieving xml session file ','joinSession',1) ;
    return 0;
}


// ==============================================================
// ==== This is called when the first "click to join session" button is pushed (the"select which session" step)
function joinSession(ido) {

var toget,getContact,getNickName,icc,imain1,tdiv,ttext,tinput,reJoinAllowed,askId,gooID,gooMessage;
var pname;
if (arguments.length<1) ido=1 ;
if (ido==1) {                           // get this sessions descriptor file
    var toget=getSessionDescriptorURL+sessName ;
    Get_xmlFile(toget,'sessionNode','retrieving xml session file ','joinSession',2) ;
    return 0;
}

if (ido==2) {                   // got session instrument.
//lookup parameters that control joining (such as username and rejoin)
    getContact=lookupNodeVar(sessionNode,'get_Contact','');              // if 1, then include a "contact info" field
    getNickName=lookupNodeVar(sessionNode,'get_NickName','');              // if 1, then include a "nickname" field

    gooID=lookupNodeVar(sessionNode,'ID_WHICH','0');              // where to get client id from
    gooID=parseAt(gooID,','); getID=strip(gooID[0]); gooMessage=gooID[1];

    gPassword=lookupNodeVar(sessionNode,'use_password','');              // if not '' then include a password field, and compare it to aPassword. Or, compare to pwd in username:pwd
    reJoinAllowed=lookupNodeVar(sessionNode,'rejoin','0');
    if (reJoinAllowed==1) {                     // rejoin requires namecheck to be enabled
        nameCheck=lookupNodeVar(sessionNode,'name_check','0');
        if (nameCheck!=1) {
            alert('Join error: reJoin is selected, but name_check has not been enabled (both variables are set in the instrument descriptor file).');
            return 1 ;
        }
    }

// make a form
    icc=document.getElementById('choseDiv'); 
    pname=makeProjName(sessName)
    icc.innerHTML='<b>Joining session: </b> <span style="font-size:120%;font-family:courier;font-variant:small-caps">'+pname+'</em><p/>';

    imain1=document.getElementById('main1');
    imain1.style.display='block';
    imain1.innerHTML='' ;

    if (getID==2) {                          // id was entered by participant
        tdiv=document.createElement('div'); tdiv.style.border='1px green solid';
        ttext=document.createTextNode('Your (unique) ID: ');
        tinput=document.createElement('input');
        tinput.value=' ';
        tinput.setAttribute('id','enteredID');
        tdiv.appendChild(ttext );     tdiv.appendChild(tinput);

        tinput=document.createElement('div'); tinput.style.fontStyle='italic';
        ttext=document.createTextNode(gooMessage);
        tinput.appendChild(ttext );     tdiv.appendChild(tinput);

        imain1.appendChild(tdiv);
    }

    tdiv=document.createElement('div'); tdiv.style.border='1px gray solid';
    ttext=document.createTextNode('Your name: ');
    tinput=document.createElement('input');
    tinput.value=' ';
    tinput.setAttribute('id','myNAME');
     tdiv.appendChild(ttext );     tdiv.appendChild(tinput);
     imain1.appendChild(tdiv);

   if (getContact==1) {
     tdiv=document.createElement('div'); tdiv.style.border='1px blue solid';
     ttext=document.createTextNode('Contact information: ');
     tinput=document.createElement('input');
     tinput.value=' ';
     tinput.setAttribute('id','myContact');
     tdiv.appendChild(ttext );     tdiv.appendChild(tinput);
     imain1.appendChild(tdiv);
   }

   if (getNickName==1) {
     tdiv=document.createElement('div'); tdiv.style.border='1px blue solid';
     ttext=document.createTextNode('Your nickname: ');
     tinput=document.createElement('input');
     tinput.value=' ';
     tinput.setAttribute('id','myNickName');
     tdiv.appendChild(ttext );     tdiv.appendChild(tinput);
     imain1.appendChild(tdiv);
   }

   if (gPassword!='' && gPassword!=0) {                          // password needed. So ask for one
     tdiv=document.createElement('div'); tdiv.style.border='1px yellow solid';
     ttext=document.createTextNode('Please enter your password: ');
     tinput=document.createElement('input');
     tinput.value=' ';
     tinput.setAttribute('id','myPassword');
     tinput.setAttribute('title','To join this session, you must have a valid password');

     tdiv.appendChild(ttext );     tdiv.appendChild(tinput);
     imain1.appendChild(tdiv);
   }

   tinput=document.createElement('p');
   imain1.appendChild(tinput);

  if (reJoinAllowed==1) {
     tdiv=document.createElement('div');

     tinput=document.createElement('input');
     tinput.setAttribute('type','checkbox');
     tinput.setAttribute('checked',0);
     tinput.checked=0;
     tinput.setAttribute('achecked',0);

     tinput.setAttribute('onClick',"changeReJoin(this)");
     tdiv.appendChild(tinput);

     ttext=document.createTextNode('Are you reJoining the session? ');
     tdiv.appendChild(ttext);

     tdiv.appendChild(ttext );     tdiv.appendChild(tinput);
     imain1.appendChild(tdiv);

   }

   tdiv=document.createElement('div');
   tinput=document.createElement('input');
   tinput.style.marginLeft="43%" ; tinput.id='saveButton'; tinput.type='button';
   tinput.value= value="Click to join session" ;
   tinput.setAttribute('id','joinButton');
   tinput.setAttribute('isRejoin','0');                         // this can be set to 1 IF rejoinAllowed (and checkbox is checked)
   tinput.setAttribute('onClick','joinSession2()')
   tdiv.appendChild(tinput);
   imain1.appendChild(tdiv);
   return 1 ;
}                       // ido=2

alert(' bad id '+ido+' in joinSession ');
return 0;

}

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

// ===================================================================================
// ==== This is called when the 2nd "click to join session" button is pushed (the "submit name, etc for selected session" step
// note use of myNAME, myID, myRefID, and myNICKNAME and myCONTACT globals

function joinSession2(ido) {

   var tmp,lpassword,iname,eName,nameok,vnames,m,aword,aname,aid,toSubmit;
   var aok,popts,getID,gooID,zoob,goowin,allowedUsers,aword,askRejoin='' ;
   var vlist,aref,nn,apwd,im,useNameList=0,ann;
   var imain1,pname;

  if (arguments.length<1 ) ido=1 ;
  if (ido==1 || ido==11 )  {                         // form submitted. Check for username and other basic stuff, and check on valid id (if required)

     gooID=lookupNodeVar(sessionNode,'ID_WHICH','0');           
     gooID=parseAt(gooID,','); getID=strip(gooID[0]);

     if (ido==11 )  {                         // got allowedUsers; create useNameList (from allowedUsers file retrieved from server)
           useNameList='';
           vlist=E2_getNodes(allowedNode,'user  client participant ');
           for (var im=0;im<vlist.length;im++) {  

              ann=strip(E2_getNodes(vlist[im],'name username  ',''));
                  if (ann.length==0) continue ;                 // bad records, skip
                  aword=strip(E2_getNodeText(ann[0],''));
                  if (getWord(aword).length!=1) continue ;    // bad records, skip
                  nn=aword ;

              ann=strip(E2_getNodes(vlist[im],'pwd password ',''));
                  if (ann.length!=0) {                  // password specified
                     aword=strip(E2_getNodeText(ann[0],''));
                     if (getWord(aword).length>1) continue ;    // bad records, skip
                     if (aword==='') aword='1' ;
                     nn=nn+':'+aword;                        //  <password></password> is same as NOT specifying <password>. It means "use default password". Note that <password>0</password> means "no password needed for this user"
                  }

              ann=strip(E2_getNodes(vlist[im],'refid ref reference ',''));
                  if (ann.length!=0) {
                      nn=nn+'=' ;
                      aword=strip(E2_getNodeText(ann[0],''));
                      if (getWord(aword).length>1) continue ;    // bad records, skip
                      nn=nn+aword;  
                  }

              useNameList=useNameList+' '+nn ;
          }                                     // vlist
     } else {                   // ido=1 
         useNameList=lookupNodeVar(sessionNode,'ALLOWED_USERS','0'); 
         useNameList=strip(useNameList.toUpperCase()) ;
         if (useNameList.substr(0,5)=='=FILE') {                        // read from xml file
           var toget=getAllowedUsersURL+'session='+sessName ;
           writeJoinStatusMessage('Retrieving list of allowed users ');
           Get_xmlFile(toget,'allowedNode','retrieving allowedUsers file ','joinSession2',11) ;
           return 0 ;
         }
      }                                  // read useNameList from descriptor file, or from allowedUsers.xml

// a useNameList is now created: either from ALLOWED_USERS note in session descriptor file, or read from a user file. Or none! 
     if (getID==2) {                                            // ID is supplied by participant
        iip=document.getElementById('enteredID');           // an ID asked for?
        if (!iip) {
                alert('Error in joinSession2:  no enterID input element ');
                return 0;
        }
        gooID=strip(iip.value);
        if (gooID=='') {
                alert('Error in joinSession2: you must enter an ID ');
                return 0;
        }
     }

     if (doJoinCustom==1) {
        myNAME=joinCustoms['NAME'];
     } else {
        iname=document.getElementById('myNAME');           // does the NAME field have disallowed characters?
        if (!iname) {
           alert('Error in joinSession2: no element with id of myNAME ');
           return 0;
        }
        myNAME=strip(iname.value) ;
     }
     myNAME=myNAME.toUpperCase() ;
     if (checkForBadChars(myNAME,'name',' !=$<>:.,#\'\"')===0) return 0;       // had some bad characters, give up
    
     if (doJoinCustom==1) {
        myCONTACT=joinCustoms['CONTACT'];
     } else {
        iname=document.getElementById('myContact');                        // does the contact field have bad characters?
        if (iname)  myCONTACT=strip(iname.value) ;
     }
     if (checkForBadChars(myCONTACT,'contact','<>\'\"')===0) return 0;       // had some bad characters, give up

     if (doJoinCustom==1) {
        myNickName=joinCustoms['NICKNAME'];
     } else {
        iname=document.getElementById('myNickName');                        // does the nickname field have bad characters?
        if (iname)  myNICKNAME=strip(iname.value) ;
     }
     if (checkForBadChars(myNICKNAME,'nickName','<>#,=\'\"')===0) return 0;       // had some bad characters, give up


// now; check that this is an allowed user. IOW: name check is done here, NOT on server. So not real secure.
     aok=checkUserNames(myNAME,useNameList) ;                                       // is there a namelist? if so, check it (and check password).
     if (aok.substr(0,2)=='ok') {                                                   // problem, display what6 it is
         var aok2=getWord(aok);
         if (aok2.length>1) myRefID=aok2[1];
     } else {
        alert(aok);
        return 1 ;
    }
    if (myRefID=='0') myRefID='';

// if here, okay username, nickname, contact, and possibly password and possibly clientid. And maybe have a refid. So ask if session still accepting new participants?

    toGet=getServerStatusVarURL+'session='+sessName+'&varname=join';
    writeJoinStatusMessage('checking session status .... ','RESET');
    tmp=Math.random() ; tmp=''+tmp;  tmp=tmp.substr(1,10);
    toGet=toGet+'&randoid='+tmp;
    Get_File(toGet,'getStatusVarResults','getting join status var','joinSession2',2) ;
    return 1;
 }

 if (ido==2) {                                         // return from check-if-new-partipcants-allowed request
    if (getStatusVarResults!='1' && getStatusVarResults!='3') {                        // if join, or rejoin only
         var zz=new Date() ; zz=zz.toLocaleTimeString() ;
         var pname=makeProjName(sessName)
         writeJoinStatusMessage('Sorry. At this moment, no new participants are being accepted for the '+pname+' session ('+zz+')','ERROR');
         return 1;
    }

   serverJoinStatus=getStatusVarResults ;                        // save to a global (used below)

// new participants being accepted. To check for maxusers, name_check, or rejoin, a list of current participant names is needed. So get it
     toGet=getServerStatusVarURL+'session='+sessName+'&varname=users';
     writeJoinStatusMessage('checking user status .... ');
     Get_File(toGet,'getStatusVarResults','getting join status var','joinSession2',21) ;
     return 1;
 }

 if (ido==21) {                                         // got list of current participants, so use it
     nowlist=getStatusVarResults.replace(/\n/g,' ');
     nowlist=nowlist.toUpperCase() ;

     gooID=lookupNodeVar(sessionNode,'ID_WHICH','0');              // ID supplied by participant? By server? Auto-generated by client?
     gooID=parseAt(gooID,','); getID=strip(gooID[0]);

     if (getID==2) {                                    // ID must be supplied by participant
        iip=document.getElementById('enteredID');           // an ID asked for?
        gooID=strip(iip.value);                    // entry is name:id=refid
        zoob=nowlist.indexOf(':'+gooID+'=') ;

        if (zoob>-1) {                     // match found
             askRejoin=0;
             if (doJoinCustom==1) {
                askRejoin=joinCustoms['ASKREJOIN'];
             } else {
                 iname=document.getElementById('joinButton');                        
                if (iname)  askRejoin=strip(iname.getAttribute('isRejoin')) ;
             } 

             if (askRejoin!=='1') {
                 var pname=makeProjName(sessName)
                 writeJoinStatusMessage('Sorry. A participant with this ID ('+gooID+') is already enrolled in the '+pname+' session.','ERROR');
                 return 1 ;
            }
        }

        if (zoob>-1) {                // if here, and > -1;  a rejoin. No need to send a join request -- just wait for session to start (thus, do NOT do a maxuser text
          aa=nowlist.substr(zoob);
          aa1=strip(getWord(aa,1));
          myID=getWord(aa1,2,':');                      // this participants ID (saved to the myID global)
          myID=getWord(myID,1,'=');                      //  get rid of refid
          if (aa1.indexOf('=')>-1) myRefID=getWord(aa1,2,'=');                      //  extract refid
          if (doJoinCustom!==1) {
               imain1=document.getElementById('main1'); imain1.style.display='none';
          }
          pname=makeProjName(sessName);

          writeJoinStatusMessage('You have re-enrolled in the '+pname+' session</b> <p /><em>Downloading information for this session, please wait ... </em>','RESET');
          loadme(1);
          return 1 ;
        }
     }                                                                     // getID=2

     nameCheck=lookupNodeVar(sessionNode,'name_check','0');
     if (nameCheck==1) {                          // name check-- if a name, and not rejoin, error. If name and rejoin,  do not sent join request, and goto joinsession3
        nowlist=' '+nowlist+' ';
        var zoob=nowlist.indexOf(' '+myNAME+':')
        if (zoob>-1) {                     // match found
             askRejoin=0;
             if (doJoinCustom==1) {
                askRejoin=joinCustoms['ASKREJOIN'];
             } else {
                iname=document.getElementById('joinButton');                        
                if (iname)  askRejoin=strip(iname.getAttribute('isRejoin')) ;
             } 
             if (askRejoin!=='1') {
                 var pname=makeProjName(sessName)
                 writeJoinStatusMessage('Sorry. A participant with this name ('+myNAME+') is already enrolled in the '+pname+' session.','ERROR');
                 return 1 ;
            }
        }
        if (zoob>-1) {                //  a rejoin. No need to send a join request -- just wait for session to start (thus, do NOT do a maxuser text
          aa=nowlist.substr(zoob);
          aa1=strip(getWord(aa,1));
          myID=getWord(aa1,2,':');                      // this participants ID (saved to the myID global)
          myID=getWord(myID,1,'=');                      //  get rid of refid
          if (aa1.indexOf('=')>-1) myRefID=getWord(aa1,2,'=');                      //  extract refid
          if (doJoinCustom!==1) {
              imain1=document.getElementById('main1'); imain1.style.display='none';
          }
          pname=makeProjName(sessName)
          writeJoinStatusMessage('You have re-enrolled in the '+pname+' session</b> <p /><em>Downloading information for this session, please wait ... </em>','RESET');
          loadme(1);
          return 1 ;
        } 

// if this was a rejoin-request, but no name: error!
        if (zoob==-1) {

             askRejoin=0;
             if (doJoinCustom==1) {
                askRejoin=joinCustoms['ASKREJOIN'];
             } else {
                iname=document.getElementById('joinButton');                        
                if (iname)  askRejoin=strip(iname.getAttribute('isRejoin')) ;
             } 

           if (askRejoin=='1') {
                 var pname=makeProjName(sessName)
                 writeJoinStatusMessage('Sorry. You asked to rejoin, but there is no participant with your name ('+myNAME+') currently enrolled in the '+pname+' session.','ERROR');
                 return 1 ;
           }
        }                                // a rejoin request but no match?

     }                                                   // inamecheck

// check for maxusers (have to do it AFTER checking for rejoin
     curUsers=getWord(nowlist) ;
     maxUsers=lookupNodeVar(sessionNode,'max_users','0') ;
     if (maxUsers<=curUsers.length && maxUsers>0) {
           var pname=makeProjName(sessName)
           writeJoinStatusMessage('Sorry. No more participants are being accepted for the '+pname+' session.','ERROR');
           return 1 ;
     }

// if here, not a rejoin. But maybe only rejoins are being permiteed?
    if (serverJoinStatus==3) {
           var pname=makeProjName(sessName)
           writeJoinStatusMessage('Sorry.  No new participants are being accepted for the '+pname+' session (rejoins are being accepted).','ERROR');
           return 1 ;
     }
        

// if here, it is okay for this participant to join.
// the ClientID
     if (getID==2) {                        // participant directly enteres
        myID=gooID ;                         // use the participanted entered id
        ido=241 ;
     } else {
       if (strip(getID)!='0') {                        // requested from server
          toGet=getClientIdURL+'session='+sessName+'&name='+myNAME;
          writeJoinStatusMessage('getting clientID from server .... ');
          Get_File(toGet,'getClientId','getting  client id','joinSession2',24) ;
       } else {                                                                // randomly generate
          ido=241 ;

//          aid=Math.random() ; aid=''+aid;
//          myID=aid.replace('0.','') ;
            aid=Math.random(); aid=''+aid;
            myID=aid.substr(2,5)+'_'+aid.substr(8,4);
       }
     }
 }                                                                          // ido=21 (checking participant list)

 if (ido==24 || ido==241 ) {                         // got client id, or generated it, or participant entered it
    if (ido==24) myID=getClientId ;                                     // return from sever
    ref_max=lookupNodeVar(sessionNode,'ref_max','0') ;                  // generate refid now?
    if (strip(ref_max).toUpperCase()=='READ') {                 // use the max_record_id 
        if (typeof(getMaxRecordId)=='undefined') {
            toGet=getServerVarURL+'session='+sessName+'&varname=maxrecordid';
            writeJoinStatusMessage('checking maxRecord server variable .... ','RESET');
            Get_File(toGet,'getMaxRecordId','getting maxRecordId','joinSession2',241) ;
            return 1;
        } else {
           ref_max=getMaxRecordId ;
           if (isNaN(ref_max) || strip(ref_max)==='') {
                alert('Bad maxRecordId (perhaps not set using getParams?): '+ref_max);
                return 0;
           }
        }                       // = -1
     }                  // read
     if (strip(ref_max)!='0' && myRefID=='') {                                  // create a refid, and there isnt an explicit one for this user
       howAssign=lookupNodeVar(sessionNode,'how_assign','0') ;
       howAssign=strip(howAssign.toUpperCase());
       if (howAssign=='CYCLE') {
          var tmp=myID % ref_max ;
          myRefID=Math.ceil(tmp+0.1) ;
          writeJoinStatusMessage('refid generated (cycle, with max of '+ref_max+'): '+myRefID);
       } else if (howAssign='RANDOM') {
           myRefID=Math.ceil(Math.random()*ref_max);
           writeJoinStatusMessage('refid generated (random, with max of '+ref_max+'): '+myRefID);
       } else if (howAssign='NONE') {
           myRefID=-1;
           writeJoinStatusMessage('No refid will be generated');
       } else {
         alert('Error in joinSession when assigning REFID -- bad HOW_ASSIGN= ' +howAssign);
         return 1 ;
       }
    }                                       // else use '' default, or value explicitily assigned from ALLOWED_USERS

// ready to "join"
    var xmlLine='<user id="'+myID+'"><name>'+myNAME+'</name><nickname>'+myNICKNAME+'</nickname><contact>'+myCONTACT+'</contact><refid>'+myRefID+'</refid></user>';
    xmlLine=escape(xmlLine);
    var uname=strip(myNAME)+':'+strip(myID)+'='+myRefID;
    toSubmit=submitJoinURL+'session='+sessName+'&username='+uname+'&content='+xmlLine;
    Get_File(toSubmit,'setJoinResults','join a session','joinSession2',3) ;
    return  1 ;
 }                                     // ido=24 or 241

 if (ido==3) {                           // come here after the join request was sent to the server
      if (setJoinResults.substr(0,1)=='-') {
        var pname=makeProjName(sessName)
         writeJoinStatusMessage('Error: problem joining the '+pname+' session</b>:  '+setJoinResults) ;
         return 1;
       }                                // failure to join
       if (doJoinCustom!==1) {
           imain1=document.getElementById('main1'); imain1.style.display='none';
        }

     goowin=lookupNodeVar(sessionNode,'WINDOW','0');   
       if (strip(goowin)=='0') {
           var pname=makeProjName(sessName)
          writeJoinStatusMessage('You have joined the '+pname+' session</b> <p /><em>Downloading information for this session, please wait ... </em>','RESET'); 
       } else {
          var closeMe='<div style="background-color:#fefaee"> You might want to close this window (the one you looking at right now), since it will not be used by the survey session.</div> \n ';
           var pname=makeProjName(sessName)
          writeJoinStatusMessage(goowin+' A <b>new window</b> has been opened, and you have joined the '+pname+' session</b> <p />  <em>Downloading information for this session, please wait ... </em> \n '+closeMe,'RESET');  
       }
       var tmp=getWord(setJoinResults,2,'');
       myID=getWord(tmp,2,':');
       loadme(1);



// while waiting, are ther files to upload (into xmlFileCache?)

      return 1 ;
  }                              // todo=2 (join info successfully sent

}



// ===================================================================================
// toggle the set field between 0 (no) and 1 (yes). This is typically called on a click (via an onClick event handler)
function changeReJoin(athis) {
  var a1,i1,i2 ;

  i1=document.getElementById('joinButton');

  a1=athis.getAttribute('achecked');

  if (a1==0) {
        athis.setAttribute('achecked',1);
        athis.setAttribute('checked',1);
        i1.value='Click to ReJoin session ';
        i1.setAttribute('isRejoin','1');
   } else {
        athis.setAttribute('achecked',0);
        athis.setAttribute('checked',0);
        i1.value='Click to join session ';
        i1.setAttribute('isRejoin','0');
   }        

   return 1 ;
}

// ===================================================================================
// make sure a filed info has no illegal characters. Return 0 if NOT good (if bad chars found)
function checkForBadChars(aval,fieldName,badChars,noStrip) {

var isbad=0;

if (arguments.length<4) noStrip=0;
if (arguments.length<3) badChars='<>&$#';
if (arguments.length<2) fieldName='';

if (noStrip!=1) aval=strip(aval);
for (var m=0;m<badChars.length;m++) {
  achar=badChars[m];
  var i1=aval.indexOf(achar);
  if (i1>-1) {;
    alert('Error: '+fieldName.toUpperCase()+' information must NOT contain a ( '+achar+' ) character. Please re-enter your '+fieldName.toUpperCase()+' information.');
    return 0;
  }
}
return 1 ;
}


// ==================================================================================
//=========== is a namelist specified. If it is, is user on it, with right password? If so, return 'ok'. Otherwise, return an error message
// note use of globals: gPassword (non-0 if a password is needed)

function checkUserNames(myname,useNameList) {
  var vnames,m,aword,aname,gotname=0,lPassword,iname,ipwd ;
  var ePassword,lRefId=''; 
  var toget ;
  var nn,aref,apwd;
  if (strip(useNameList)==='0') gotname=1 ;

  if (myname==''|| myname==0)   return 'Error:  no name was specified ';                // name field is  required

  lPassword=gPassword ;                         // global password may be overridden on a user specific basis
  if (lPassword==='') lPassword=0;

  useNameList=strip(useNameList);    
  myname=strip(myname.toUpperCase()) ; useNameList=strip(useNameList.toUpperCase()) ;
  if (gotname==0) {                                     // need to find name (useNameList is specified
    vnames=getWord(useNameList);
    for (var m=0;m<vnames.length;m++) {
       aword=strip(vnames[m]);
       aname=aword.replace(/:.*/g,'');   aname=aname.replace(/=.*/g,'');                // remove anything after a : and/or an = 
       if (myname==aname) {                         // name okay. Extract password (for use below)
                if (aword.indexOf(':')>-1) {       // password specified? Than use it (instead of the global password
                     lPassword=aword.replace(/.*:/g,'');        // remove anything  before a :, including the :
                     lPassword=lPassword.replace(/=.*/,'') ;   // remove anything after an =, including the =
                     if (lPassword==='') lPassword=0;
                     if (lPassword=='1') lPassword=gPassword ;

                }                                        // Note. A "user:0" or "user:" means "no password required for this user (global password is overridden
                gotname=1;       
                if (aword.indexOf('=')>-1) lRefId=aword.replace(/.*=/g,'');        // extract refid? remove anything  before a =, including the =
                break ;
        }                           // myname=aname
    }                                    // vnames.length

    if (gotname==0) {                   // all names checked. Match found?
            return 'Sorry, your name ('+myname+') is not on the list of allowed participants.'; 
    }

  }                                     // gotname=0

// if here, gotname=1 (name match, or name never required. Check password?
  if (lPassword==0) return 'ok '+lRefId                                // name and pssword are good. Success.

    lPassword=strip(lPassword.toUpperCase()) ;


    if (doJoinCustom==1) {
        ePassword=joinCustoms['PASSWORD'];
     } else {
        ipwd=document.getElementById('myPassword');
        if (!ipwd) return 'Error: no password available ';
        ePassword=strip(ipwd.value) ;
     }
     if (ePassword=='') return 'To join this session, you must enter a password. ';
     ePassword=ePassword.toUpperCase() ;

    if (lPassword!=ePassword) { 
                return ' Your password is incorrect. Please reenter your password.';
    }                                   // lpassword

   return 'ok '+lRefId        ;          // if here, okay!

}


// ==================================================================================
// this is called to load the home page for this session. After this is called, we are done with "spy"

function loadme(aval,isspy) {
  if (aval!=1) return 0 ;                       // failure (error message was shown earlier
   var instname,homepage,specfile,ibase,dd;
   var resubmit,owassign,ispy;

    instname=strip(lookupNodeVar(sessionNode,'instrumentName',''));

    var winuse=strip(lookupNodeVar(sessionNode,'WINDOW','0'));
    if (winuse==='1') winuse="toolbar=0,location=0,directories=0,status=0,toolbar=0,scrollbars=1,resizable=1";
    homepage=strip(lookupNodeVar(sessionNode,'HOME_PAGE','0'));
    if (homepage==='0') homepage=homePageURL.replace(/!INST!/g,instname);                                 // use default home page
          
    resubmit=strip(lookupNodeVar(sessionNode,'RESUBMIT',0));

    owassign=escape(strip(lookupNodeVar(sessionNode,'HOW_ASSIGN',0)));

    dd=1;
    if (typeof(debugMode)!=='undefined') dd=debugMode;          // use javascript variable as default, if it exists
    dd=parseInt(dd);
    if (isNaN(dd))dd=1;
    adebug=strip(lookupNodeVar(sessionNode,'DEBUG_MODE',dd));           // a session descriptor var is used if it extis

    ispy='';
    if (isspy==1)ispy='spy=1&';
    var daUrl=homepage+'?'+ispy+'instrument='+instname+'&sessionName='+sessName+'&myID='+myID+'&myRefID='+myRefID+'&myName='+myNAME ;
    daUrl=daUrl +'&myNickName='+escape(myNICKNAME)+'&myContact='+escape(myCONTACT)+'&resubmitOkay='+resubmit+owassign+'&debug_Mode='+adebug;

    if (winuse==='0') {          // open in current window
       location.href=daUrl ;
    } else {                    // open in new window
        var w1=window.open(daUrl,'session_'+sessName,winuse);                           // nb: daurl='' if modules are going to be used
    } 
} 




// ==================================================================================
// write status message
function writeJoinStatusMessage(amessage,areset) {
 if (arguments.length<2) areset='';
 areset=strip(areset.toUpperCase()) ;
 var goo ;

 goo=document.getElementById('statusMessage');
 if (!goo) {
        alert("writeJoinStatusMessage Error: no statusMessage area ");
        return 0;
  }

  if (areset.indexOf('HIDE')>-1)  {;
    goo.style.display='none';
    return 1 ;
  }

  if (areset.indexOf('RESET')>-1)  goo.innerHTML='';
  goo.style.display='block';

  if (areset.indexOf('ERROR')>-1)  {
        goo.innerHTML='';
       goo.style.backgroundColor='yellow';
  } else {
       goo.style.backgroundColor='lime';
  }
  
   goo.innerHTML=goo.innerHTML+'<br />'+amessage;
   return 1;
}



//============
//=== spy versions of join
// ==============================================================
// ==== This is called when the first "click to join session" button is pushed (the"select which session" step)
function spySession(ido) {
 
var toget,icc,imain1,tdiv,ttext,tinput,reJoinAllowed,askId,gooID,gooMessage;
var pname;
if (arguments.length<1) ido=1 ;
if (ido==1) {                           // get this sessions descriptor file
    var toget=getSessionDescriptorURL+sessName ;
    Get_xmlFile(toget,'sessionNode','retrieving xml session file ','spySession',10) ;
    return 0;
}


if (ido==10) {                           // get this sessions list of participants
   getUsersServer('userListID');
  return 1;
}

if (ido==2) {                   // got session instrument.
//lookup parameters that control joining (such as username and rejoin)

    gooID=lookupNodeVar(sessionNode,'ID_WHICH','0');              // where to get client id from
    gooID=parseAt(gooID,','); getID=strip(gooID[0]); gooMessage=gooID[1];


// make a form
    icc=document.getElementById('choseDiv'); 
    pname=makeProjName(sessName)
    icc.innerHTML='<b>Spying on session: </b> <span style="font-size:120%;font-family:courier;font-variant:small-caps">'+pname+'</em><p/>';

    imain1=document.getElementById('main1');
    imain1.style.display='block';
    imain1.innerHTML='' ;

    tdiv=document.createElement('div'); tdiv.style.border='1px gray solid';
    ttext=document.createTextNode('ID to spy on: ');
    tinput=document.createElement('input');
    tinput.value=' ';
    tinput.setAttribute('id','myNAME1');
     tdiv.appendChild(ttext );     tdiv.appendChild(tinput);
     imain1.appendChild(tdiv);



   tinput=document.createElement('p');
   imain1.appendChild(tinput);


   tdiv=document.createElement('div');
   tinput=document.createElement('input');
   tinput.style.marginLeft="43%" ; tinput.id='saveButton'; tinput.type='button';
   tinput.value= value="Click to spy on the above participant" ;
   tinput.setAttribute('id','joinButton');
   tinput.setAttribute('onClick','spySession2()')
   tdiv.appendChild(tinput);
   imain1.appendChild(tdiv);
   return 1 ;
}                       // ido=2

alert(' bad id '+ido+' in spySession ');
return 0;

}


// ===================================================================================
// ==== This is called when the 2nd "click to spy" button is pushed

function spySession2(ido) {

   var tmp,lpassword,iname,eName,nameok,vnames,m,aword,aname,aid,toSubmit;
   var aok,popts,getID,gooID,zoob,goowin,allowedUsers,aword,askRejoin='' ;
   var vlist,aref,nn,apwd,im,useNameList=0,ann,zoob2;
   var imain1,pname;

  if (arguments.length<1 ) ido=1 ;
  if (ido==1  )  {                         // form submitted. Get list of participants
     iname=document.getElementById('myNAME1');           // does the NAME field have disallowed characters?
     if (!iname) {
           alert('Error in spySession2: no element with id of myNAME1 ');
           return 0;
     }
     myNAME=strip(iname.value) ;
     myNAME=myNAME.toUpperCase() ;
     if (strip(myNAME)=='') {
           alert("You forgot to chose a participant "); 
           return 1;
      }

     if (checkForBadChars(myNAME,'name',' !=$<>:.,#\'\"')===0) {
           alert('Error: there are non-permitted characters in name: '+myNAME);
           return 0;       // had some bad characters, give up
     }
                                        
     toGet=getServerStatusVarURL+'session='+sessName+'&varname=users';
     tmp=Math.random() ; tmp=''+tmp;  tmp=tmp.substr(1,10);
     toGet=toGet+'&randoid='+tmp;
     Get_File(toGet,'getStatusVarResults','getting join status var','spySession2',21) ;
     return 1;
  }

 if (ido==21) {                                         // got list of current participants, so use it
     nowlist=getStatusVarResults.replace(/\n/g,' ');
     nowlist=nowlist.toUpperCase() ;

     gooID=lookupNodeVar(sessionNode,'ID_WHICH','0');              // ID supplied by participant? By server? Auto-generated by client?
     gooID=parseAt(gooID,','); getID=strip(gooID[0]);

     iname=document.getElementById('myNAME1');           // does the NAME field have disallowed characters?
     myNAME=strip(iname.value) ;
     myNAME=myNAME.toUpperCase() ;

     zoob=nowlist.indexOf(myNAME+':') ;

     if (zoob<0) {                     // match found
             writeJoinStatusMessage(' Sorry, no participant with a name of: '+myNAME,'ERROR');
             return 1;
     }

     zoob2=nowlist.indexOf(':',zoob); 
     aa=nowlist.substr(zoob2+1);
     aa=getWord(aa,1);
     tmp=parseAt(aa,'=');
     myID=tmp[0];                      // this participants ID (saved to the myID global)
     myRefID=tmp[1];
     imain1=document.getElementById('main1'); imain1.style.display='none';
     pname=makeProjName(sessName)
     writeJoinStatusMessage('You are spying on '+myNAME+' in the '+pname+' session</b> <p /><em>Downloading information for this session, please wait ... </em>','RESET');
     loadme(1,1);
     return 1 ;

 }

 alert('spysession2 error ');

}

// =========================== 
// obtain current list of users, and display. 
//  Typically, this does NOT save anything... it just displays
//  However, if divid is a -1, then no display.  In this case, the userListNode global points to an XML file with the client info in it:
//
function getUsersServer(divid,ido) {

var am,aname,acontact,m,tt,atable,abody,atd,atr,iid,gnode,agnode,bnode,cnode,m2,varlist;
var ff,ff2;
var anode,am,vv,vv2,idAt,ii;

if (arguments.length<2) ido=1 ;
if (arguments.length<1) divid=actionDiv ;


if (ido==1 ) {
   toGet=getUserListURL+'session='+sessName;
   Get_xmlFile(toGet,'userListNode','retrieving an user list','getUsersServer',divid,2);
   return 1 ;
 }

if (divid==-1) return 1 ;                       // and userListNode can be used


// got user list from server
   iid=document.getElementById(divid);
   if (!iid) {
        alert('Error in getUsers: no such display-div id= '+divid);
        return 1;
   }
   iid.innerHTML='';

  userStuff=toArray_u(userListNode);
  if (typeof(userStuff)=='string') {
     iid.innerHTML='<b>Error</b>: '+userStuff;
     return 0
  }

  varlist=userStuff[0] ;

   idAt=-1;
   for (var ii=0;ii<varlist.length;ii) {
        if (varlist[ii].toUpperCase()=='ID' ) {
            idAt=ii;
            break;
         }
   }
   if (idAt<0) {
        alert('Error: unable to find ID variable ');
        return 0;
   }
   atd=document.createElement('h3');
   aval=document.createTextNode('List of participants: from server ');
   atd.appendChild(aval);
   iid.appendChild(atd);
     
   atd=document.createElement('span');
   aval=document.createTextNode('Note: this is the current list of participants enrolled in the session, as reported by the server. ');
   atd.appendChild(aval);
   iid.appendChild(atd);


   atd=document.createElement('div');
   aval=document.createTextNode('To select a participant, click on his ID (in a green box) ');
   atd.appendChild(aval);
   iid.appendChild(atd);

   atable=document.createElement('table');  
   atable.setAttribute('border',1);
   atable.style.marginTop='6px';
   abody=document.createElement('tbody');
   atr=document.createElement('tr');

   atd=document.createElement('th');
       aval=document.createTextNode(' ');
        atd.appendChild(aval);
        atd.style.backgroundColor="cyan";
        atr.appendChild(atd);

   atd=document.createElement('th');
       aval=document.createTextNode('PartcipantID');
        atd.appendChild(aval);
        atr.appendChild(atd);

  for (var m=0 ; m<varlist.length ; m++) {
        avar=strip(varlist[m]);
        atd=document.createElement('th');
           aval=document.createTextNode(avar);
        atd.appendChild(aval);
        atr.appendChild(atd);
  }
  abody.appendChild(atr);

 for (var m=1;m<userStuff.length;m++) {  
      vv2=userStuff[m];
      atr=document.createElement('tr');
         atd=document.createElement('th');
           aval=document.createTextNode(1*m);
        atd.appendChild(aval);
        atd.style.backgroundColor="cyan";
       atr.appendChild(atd);
           atd=document.createElement('td');
           atd.style.backgroundColor='#acacbc';
             aval=document.createTextNode(vv2[0]);
           atd.appendChild(aval);
       atr.appendChild(atd);
       for (var m2=0 ; m2<varlist.length ; m2++) {
          atd=document.createElement('td');
          aval=document.createTextNode(vv2[m2+1]);    // since vv[0]=id
          if (m2==idAt)  {
              useIdList[m]=vv2[m2+1];
              atd.style.backgroundColor='lime';atd.style.fontSize='130%'; 
              ff=document.createElement('span');
              ff.setAttribute('onClick','fillInId('+m+')');
              ff.appendChild(aval);
              atd.appendChild(ff);
          } else {
            atd.appendChild(aval);
          }
          atr.appendChild(atd);
       }
       abody.appendChild(atr);

     }
     atable.appendChild(abody);
     iid.appendChild(atable);
    spySession(2);  

    return 1;
}
//====
// fill in id field
function fillInId(iat) {
var oy ;  

oy=document.getElementById('myNAME1'); 
oy.value=useIdList[iat] ;
return 0;
}

// =-======================================
// parse an XML file containing a user list (as returend by server). 
// Return an array, 1 row per "user". Each row is an array
// The 0'th row is an array of variable names
// row 1 ... are the "user" rows, with variables matching the 0th row
// column 0 is always the id. 
// If a string, it's an error message. 
// NOTE: this is similar to parseVarNodeUR(.,'currentParticipants'). 
//  However, it creates an array and returns it -- it does NOT   change the currentParticipants global


function toArray_u(uNode) {

var tmp,m,anode,aid,alist,m2,res ;
var varname,vlist,av,ii,avar,aval,m1 ;


gnode=E2_getNodes(uNode,'USER');                // participant list has <USER> as top level nodes (not embedded in  <users>) .

var tmp={};                     // create an object with variables, and ids (use this to build an array)
tmp['$vars']={};
tmp['$ids']={} ;
for (var m=0;m<gnode.length;m++) {  
     anode=gnode[m];
     aid=getAttributes(anode,'id','');
     if (aid=='') continue ;                    //no id, skip
     tmp['$ids'][aid]=1; 
     tmp[aid]={} ;
     alist=E2_getNodes(anode,'*');
     for (var m2=0;m2<alist.length;m2++) {
        varname=alist[m2].nodeName.toUpperCase() ;
        tmp['$vars'][varname]=1;
        tmp[aid][varname]=E2_getNodeText(alist[m2],1,'');
     }
}

res=[]; res[0]=[];
vlist=[]; vlist[0]='ID' ;
for (var av in tmp['$vars'])  vlist=vlist.concat(av)

for (var m=0;m<vlist.length;m++) res[0][m]=vlist[m];            // 0 element of returned array is the array of varnames

for (var aid in tmp['$ids'])  {                         // 1 .. elements contain the data for record, as an array. 0 element of this array is id, others match above varlist
   ii=res.length;
   res[ii]=[];
   res[ii][0]=aid ;
   for (var m=1;m<vlist.length;m++) {
       avar=vlist[m];
       aval='';
       if (typeof(tmp[aid][avar])!='undefined') aval=tmp[aid][avar];
       res[ii][m]=aval
   }
}
return res ;

}


