/**
 * @author: xiaofyu@gmail.com
 * 26/Jul/2007
 */

    //shortcuts
    var lb = LLDL.bundle;
    var lldl = LLDL.activities;
    var yud = YAHOO.util.Dom;
    var yue = YAHOO.util.Event;
//    var logger = YAHOO.log;
    var yuc = YAHOO.util.Connect;
    
    var lba = LLDL.bundle.authentication;
    var DDM = YAHOO.util.DragDropMgr;
    var log_server = "";
    
/**
 * Class 
 * @constructor
 * @param id : String (element id) || HTML 
 * @param info {  
                    module_name: 
        			basic_server_url: '?a=pr&amp;o=xml&amp;ro=1&amp;rt=r&amp;c=' + c_name + '&amp;s1.collname=' + c_name;
        			help_server_url: 
        			images_url: 
        			reference_src_link_elem_id: 
        			mform_root_id: 
        			mform_activity_type_elem_name: 
        			caller_obj: 
        			caller_obj_callback_fn: 
        			ajax_fn:
                }
 */
LLDL.Authentication = function(authen_id_from_flax_style_xsl, containerid_from_flax_style_xsl,config/*object passed from flax-activity.xsl*/) {

    lba.config_info = config;
    //Keywords used in protocol when communicating with the backend Flax server
    lba.NAME = "name";
    lba.ID = "id";
    lba.TYPE = "type";
    lba.URL = "url";
    lba.C = "c";
  
    lba.un = "un";
    lba.pw = "pw";
    lba.umgp = "umgp";
    lba.umun = "umun";
    lba.umpw = "umpw";
    lba.umas = "umas";
    lba.activity_db_access = "access";
    lba.admin = "administrator";
    lba.teacher = "teacher";
    lba.student = "student";
    lba.guest = "guest";
    
    lba.dialog = null;
    lba.containerid = containerid_from_flax_style_xsl; 
    lba.userlist_tbody_id = "_u_list_tbody_id";
     
    //A array of objects (collections configured with ActivityManagement service)
    //Initialised when the first time doing the 'listUsers'
    //The format of object: {name:"", title:"", summary:""}(initialised in queryCollectionsCallback)
    this.am_collections = null;
    
    this.all_user_list = null;//A list of all users of this collection (a list of {username:"", password:"", role:"", activity_db_access:false})
                    
    lba.authen_id = authen_id_from_flax_style_xsl;

    this.body = yud.get(lba.authen_id);
    LLDL.clearup(this.body);
    
    lba.login_container = LLDL.createEl("div", "login_container_id");
    lba.userlist_container = LLDL.createEl("div", "userlist_container_id");
    lba.userlist_container.style.display = "none";
    //lba.design_container = LLDL.createEl("div", "design_container_id");
    this.body.appendChild(lba.login_container);
     this.body.appendChild(lba.userlist_container);
  
   
     if(!this.body) { 
        throw new Error(lba.server_error);
    }
    this.toString = function() {
        return "LLDL.Authentication";
    };
    
    //Valid values of role: administrator, teacher, student, guest (if a teacher/student doesn't have access to this collection, they are put in the 'guest' category)
    //activity_db_access: true/false - whether the user has access to edit activities of this collection. 
    this.user = {username:null, password:null, role:null, activity_db_access:false};
    try{
        this.checkUser(); //initialise the object 'this.user'
        lba.login_container.innerHTML = this.getUserElement(); 
    }catch(e) {
        try{ 
            LLDL.switchToErrorView(lba.server_error, log_server, null, e);
        }catch(ex) {
            document.writeln(lba.server_error);
            document.writeln(ex);
        }
    }
	
   
  
    lba.convertRequestParams = function(val) {
        var result = val.replace( new RegExp( ";", "g" ), "=" );
        result = result.replace( new RegExp( "]]", "g" ), "&" );
        result = result.replace("preview", "serve");
        //alert(result);
        return result;        
    };
            
    lba.showContainer = function() {
        try{
            lba.userlist_container.style.display = "none";
            var container = yud.get(lba.containerid);
	    container.style.display = "";
        }catch(e) {
            alert(e);
        }
    };

    lba.wait_panel = LLDL.getWaitPanel(lba.config_info.images_url+'blocking_loading.gif', window.document.body/*el to render*/);
          
    //passback_obj - an obj which is passed from the caller of this function back to the 'callback' function
    lba.talk2server = function(caller_obj, callback, url, passback_obj, err_msg) {
        lba.wait_panel.show();
       yuc.resetDefaultHeaders();
      
        yuc.asyncRequest("GET", url, {
    		success:function(o){ 
         	    try{
        		    lba.wait_panel.hide(); 
        		    //alert(url + "  "+postdata);
        		    //alert("in lba.talk2server: o.responseText="+o.responseText);
        		    callback.call(caller_obj, o.responseXML, passback_obj);
                }catch (expt) {
                    try{
                        LLDL.switchToErrorView(lba.server_error+' '+expt, lba.config_info.log_server_url, expt);
                    }catch(ex) {
                        document.writeln("The following error occurred: ");
                        document.writeln(ex);
                    }
                }                
    		},				   
         	failure:function(o){ 
                    //lba.wait_panel.hide(); 
                    try{
                        alert(err_msg);
                        return false;
                    }catch(ex) {
                        document.writeln("The following error occurred: ");
                        document.writeln(ex);
                    }
            }
                
        }, null);

    };
 
 
if (null == document.ELEMENT_NODE) {
	document.ELEMENT_NODE                   = 1;
	document.ATTRIBUTE_NODE                 = 2;
	document.TEXT_NODE                      = 3;
	document.CDATA_SECTION_NODE             = 4;
	document.ENTITY_REFERENCE_NODE          = 5;
	document.ENTITY_NODE                    = 6;
	document.PROCESSING_INSTRUCTION_NODE    = 7;
	document.COMMENT_NODE                   = 8;
	document.DOCUMENT_NODE                  = 9;
	document.DOCUMENT_TYPE_NODE             = 10;
	document.DOCUMENT_FRAGMENT_NODE         = 11;
	document.NOTATION_NODE                  = 12;
}

   lba.showUserList = function() {
        try{
         	
	    var container = yud.get(lba.containerid);
	    container.style.display = "none";
            lba.userlist_container.style.display = "";
    	    var anim = new YAHOO.util.Anim(lba.userlist_container, { height: { from: 1, to: 100, unit: '%' }}, 1, YAHOO.util.Easing.easeIn);
    	    anim.animate(); 
        }catch(e) {
            alert(e);
        }
    };
  
  
    //this is so that the class name .bd of the context menu can be applied thru .yui-skin-sam .yuimenu .bd - required by yui treeview display
    yud.get("flax-body").className = "yui-skin-sam";
   

    window.onerror = function(msg, url, lno) { alert(msg+" "+url+" "+lno);
        try{ 
            LLDL.switchToErrorView(lba.server_error, lba.config_info.log_server_url, null, msg+" Location: "+url+" Line: "+lno);
        }catch(ex) {
            document.writeln(lba.server_error);
            document.writeln(ex);
        }
    }
 }; 


LLDL.Authentication.prototype= {
    ///////General functions
    checkUser : function() {
        //The value of lba.umgp sent back from server is: 'administrator', or 'student', or 'guest', or 'teacher,coll_1,coll_2,coll_3...'
        
        var uname = (new Cookie(lba.un)).read();
        var password = (new Cookie(lba.pw)).read();
        var role = (new Cookie(lba.umgp)).read(); 
                
        if(!uname || uname.length<1 ||
            !password || password.length<1 ||
            !role || role.length<1) {
            return false;
        }
        var access = role.split(",");
        this.user.username = uname;
        this.user.password = password;
        this.user.role = access[0];
        
        switch (this.user.role) {
            case lba.admin : {
                this.user.activity_db_access = true; break;    
            }
            case lba.teacher : {
                if(access.indexOf(lba.collname) !== -1) {
                    this.user.activity_db_access = true;                    
                } 
                break;    
            }
            default : {
                this.user.activity_db_access = false; break;    
            }
                
        }           
    },
    getUserElement : function() {
         var v = "";
        if(this.user.username === null) {//not logged in
            v = "<span>"+lba.not_login+"</span>" +
                    "<span title='Click to login' id='login_btn' class='admin_btn'>"+lba.login+"</span>";// +
//                    "<span id='guest_login_btn' class='admin_btn'>("+lba.guest_login+")</span>";
            yue.on("login_btn", "click", function(e) {
                try{
                    this.login();
                }catch(e) { alert(e); }
            }, this, true);
            yue.on("guest_login_btn", "click", function(e) {
                try{
                    this.guestLogin();
                }catch(e) { alert(e); }
            }, this, true);
            
        } else {
            v = "<span>"+lba.login_as+"</span>" +
                    "<span title='Click to change your password' class='admin_btn' id='username'>"+this.user.username +"</span>"+
                    "<span title='Click to logout' id='logout_btn' class='admin_btn'>"+lba.logout+"</span>";
            yue.on("logout_btn", "click", function(e) {
                try{
                    (new Cookie(lba.un)).kill();
                    (new Cookie(lba.pw)).kill();
                    (new Cookie(lba.umgp)).kill();
                    window.location.reload();
                }catch(e) { alert(e); }
            }, this, true);
            
            if(this.user.role !== lba.guest) {//users other than guests are allowed to change their passwords
                yue.on("username", "click", function(e) {
                    try{
                        this.changePassword();
                    }catch(e) { alert(e); }
                }, this, true);
            }
        } 
         
        if(this.user.role === lba.teacher && this.user.activity_db_access) {
            v += "<span title='Click to manage student accounts' id='student_account_btn' class='admin_btn'>"+lba.student_account+"</span>";
            yue.on("student_account_btn", "click", function(e) {
                try{
                    this.listStudents();
                }catch(e) { alert(e); }
            }, this, true);
        } 
        else if(this.user.role === lba.admin) {
           // v += "<span title='Click to manage student accounts' id='student_account_btn' class='admin_btn'>"+lba.student_account+"</span>" +
           //      "<span title='Click to manage user accounts' id='user_account_btn' class='admin_btn'>"+lba.user_account+"</span>";
            // remove the student account temporally: shaoqun
           v += "<span title='Click to manage user accounts' id='user_account_btn' class='admin_btn'>"+lba.user_account+"</span>";
            yue.on("student_account_btn", "click", function(e) {
                try{
                    this.listStudents();
                }catch(e) { alert(e); }
            }, this, true);
            yue.on("user_account_btn", "click", function(e) {
                try{
                    this.listUsers();
                }catch(e) { alert(e); }
            }, this, true);
        } 

        return v;
    },
    getAddStudentBody : function(number) {
        var body = LLDL.createEl("div", "add_student_body_id");
        var default_row = 1;
        var option, selected;
        var select_el = LLDL.createEl("select");
        for(var i=1; i<number; i++) {
            selected = (i === default_row)? true : false;
            option = new Option(i.toString(), i.toString(), false, selected); 
            select_el.options[select_el.options.length] = option;
        }
            yue.on(select_el, "change", function(e) {
                try{
                    var target = yue.getTarget(e); 
            		var value = parseInt(select_el.options[select_el.selectedIndex].value);
            		if(isNaN(value) || typeof value !== "number") {
            		    alert(value + " is not number");
            		    return false;
            		}
            		alert("TODO: adjust the rows of the textarea");
                }catch (expt) { alert(expt); }
            }, this, true);
        var num_block = LLDL.createEl("div", "", "", "num_student_div_class");
        num_block.appendChild(LLDL.createEl("span", "", "Number of students to add"));
        num_block.appendChild(select_el);    
        body.appendChild(num_block);
        
        var textarea_div = LLDL.createEl("div");
        var textarea = LLDL.createEl("textarea", "textarea_id", "username,password");
        textarea.rows = default_row;
        textarea.cols = 50;
        textarea_div.appendChild(textarea);
        textarea_div.appendChild(LLDL.createInnerHTML("span", "", "<input type='button' value='Add' id='add_btn_id'/>"));
        body.appendChild(textarea_div);    
            yue.on("add_btn_id", "click", function(e) {
                alert("add students");
            }, this, true);    
        return body;
    },
    getAddUserBody : function() {
            var add_user = LLDL.createInnerHTML("div", "", "<a id='add_user_link_id'>"+lba.add_user+"</a>", "add_user_div_class");
            yue.on("add_user_link_id", "click", function(e) {
                this.addUser();
            }, this, true);    
        return add_user;
    },
    parseServiceNode : function(dom) {
        try{
        	    var authen_node = dom.getElementsByTagName("authenticationNode");
        	    if(!authen_node || !authen_node[0]) { return false; }
        	    var service_node = authen_node[0].getElementsByTagName("service");
        	    if(!service_node || !service_node[0]) { alert("Mal-response from server"); return false; }
        	    return service_node[0];
            
        }catch(e) { alert(e); }
    },
    getUserForm : function(umun, umpw, umas, umgp, username_disabled) {
           var group = umgp.split(",");
            var inputs = "";
            for(var i=0; i<this.am_collections.length; i++) {
                var coll = this.am_collections[i];
                var collname = coll.name;
                var colltitle = coll.title;
                var checked = "checked";
               if(this.am_collections.length == 1){
                   inputs += "<input id='colloname-input' type='checkbox' name='s1.umgp[]' title='"+coll.summary+"' value='"+collname+"' "+checked+">"+colltitle+"</input><br />";
               }
	       else{
                   inputs += "<input type='checkbox' name='s1.umgp[]' title='"+coll.summary+"' value='"+collname+"' "+checked+">"+colltitle+"</input><br />";
                }
            }
            var checked_true = (umas==="true")? "checked" : "";
            var checked_false = (umas==="false")? "checked" : "";
            var checked_admin = (group.indexOf(lba.admin) !== -1)? "checked" : "";
            var checked_teacher = (group.indexOf(lba.teacher) !== -1)? "checked" : "";
            var coll_visual = (group.indexOf(lba.admin) !== -1)? "visibility:hidden" : "visibility:visible";
            var disable_un = "";
            if(username_disabled === true){ 
                //this function is called in editUser(), in which case username is not to be modified
                disable_un = "disabled=true";
            }
        
	var v = "<form method='' action=''>" +
                      "<table>" +
                        "<tr><td><label for='s1.umun'>Username:</label></td>" +
                            "<td><input type='text' name='s1.umun' value='"+umun+"' "+disable_un+"/></td></tr>" +
                        "<tr><td><label for='s1.umpw'>Password:</label></td>" +
                            "<td><input type='password' name='s1.umpw' value='"+umpw+"' /></td></tr>" +
                        "<tr><td><label for='s1.umas'>Account status:</label></td>" +
                            "<td><input type='radio' name='s1.umas' value='true' "+checked_true+"/>Enabled" +
                            "<input type='radio' name='s1.umas' value='false' "+checked_false+"/>Disabled</td>" +
                        "</tr>" +
                        "<tr><td><label for='s1.role'>User role:</label></td>" +
                            "<td id='s1.role'><input type='radio' name='s1.role' value='"+lba.admin+"' "+checked_admin+"/>" + lba.admin +
                            "<br /><input type='radio' name='s1.role' value='"+lba.teacher+"' "+checked_teacher+"/>" + lba.teacher + "</td>" +
                        "</tr>" +
                        "<tr id='s1.umgp' style='"+coll_visual+"'><td valign='top'><label for='s1.umgp[]'>Collection access:</label></td>" +
                            "<td ><div style='height:100px;overflow:auto;'>"+inputs+"</div></td>" +
                        "</tr>" +
                      "</table>" +
                    "</form>"; 

            yue.on("s1.role", "click", function(evt) {
                var el = yue.getTarget(evt); 
//                if(el.tagName !== "input") { return false; }
                var data = lba.dialog.getData(); 
                (yud.get("s1.umgp")).style.visibility = (data["s1.role"] === lba.admin)? "hidden" : "visible";
            }, this, true);
                    
        return v;
    },
    getUserRow : function(rowid, umun, umpw, umas, umgp) {
        try{
            var convertCollnames = function(gp, am_colls) {
                var am_coll;
                var name_arr = gp.split(",");
                for(var i=0; i<name_arr.length; i++) {
                    for(var k=0; k<am_colls.length; k++) {
                        am_coll = am_colls[k];
                        if(am_coll.name === name_arr[i]) {
                            name_arr[i] = am_coll.title;
                            break;
                        }
                    }
                }
                return name_arr.join(", ");
            }
            var tr = LLDL.createEl("tr", rowid);
            tr.appendChild(LLDL.createEl("td", "", umun));
            tr.appendChild(LLDL.createEl("td", "", (umas==="true")? "Enabled" : "Disabled"));
            tr.appendChild(LLDL.createInnerHTML("td", "", convertCollnames(umgp, this.am_collections)));
            var btns = "";
            if(umun !== "admin") {
                //'admin' is the master user and is not allowed to be edited/deleted
                btns = "<a href='#' id='edit_"+umun+"' rowid='"+rowid+"' umun='"+umun+"' umpw='"+umpw+"' umas='"+umas+"' umgp='"+umgp+"'>Edit</a>";
                btns += "<a href='#' id='del_"+umun+"' rowid='"+rowid+"' umun='"+umun+"' umpw='"+umpw+"' umas='"+umas+"' umgp='"+umgp+"'>Delete</a>";
            } 
            tr.appendChild(LLDL.createInnerHTML("td", "", btns));
                
            yue.on(("edit_"+umun), "click", function(e) {
                try{
                    var el = yue.getTarget(e);
                    var rowid = el.getAttribute("rowid");
                    var un = el.getAttribute("umun");
                    var pw = el.getAttribute("umpw");
                    var as = el.getAttribute("umas");
                    var gp = el.getAttribute("umgp");
                    this.editUser(rowid, un, pw, as, gp);
                }catch(e) { alert(e); }
            }, this, true);
            
            yue.on(("del_"+umun), "click", function(e) {
                try{
                    var el = yue.getTarget(e);
                    var rowid = el.getAttribute("rowid");
                    var un = el.getAttribute("umun");
                    var pw = el.getAttribute("umpw");
                    var as = el.getAttribute("umas");
                    var gp = el.getAttribute("umgp");
                    this.deleteUser(rowid, un, as, gp);
                }catch(e) { alert(e); }
            }, this, true);             
            return tr;
        }catch(e) { alert(e); }
    },
    initDialog : function(dialog_title, dialog_form_el_str, ok_handle_fn) {
        try{
        	var dialog_c = LLDL.createEl("div", "_dialog_c_id");
        	dialog_c.innerHTML = "<div id='dialog1_h' class='hd' >"+dialog_title+"</div>" +
                                    "<div class='bd'>" + dialog_form_el_str +
                                    "</div>" +
                                 "</div>"; 
            						       
        	// when the dialog is invoked within userlist_container (add/edit user form), 
        	//the blinking vertical bar cursor is missing in the text input fields
        	//Solution: lba.login_container cannot be set to 'display:none'; it must be either 'visibility:hidden' or removed from dom
        	document.body.appendChild(dialog_c);
        	lba.dialog = new YAHOO.widget.Dialog(dialog_c, 
        							{ //width : "30em",
        							  fixedcenter : true,
        							  visible : false, 
        							  close: false,//no close button on the top right corner
        							  modal : true,//block the background
        							  underlay: "matte",
        							  draggable: false,
//        							  keylisteners: YAHOO.util.KeyListener
//            							  zIndex: 100000,
        							  constraintoviewport : true,
        							  buttons : [ { text:"Ok", handler: ok_handle_fn},
        								      { text:"Cancel", handler: function(){	this.cancel(); this.destroy(); lba.dialog = null;  } } ]
        							});
        	lba.dialog.render();
        	lba.dialog.show();
        }catch(e) { alert(e); }
        return true;
    },
    ////////////////////////////
    ////////Ajax action functions
    listStudents : function() {
        try{
            var authen_url = "?o=xml&a=pr&sa=authen&s=Authentication&rt=r&ro=1&s1.asn=1&s1.uan=1&s1.aup=ListUsers&s1.pw=&s1.un=admin";
            lba.talk2server(this, this.listStudentsCallback, authen_url, null, "Listing student accounts failed due to server errors.");                 
        }catch(e) {
            alert(e);
        }        
    },
    listUsers : function() {
        try{
            var authen_url = "?o=xml&a=pr&sa=authen&s=Authentication&rt=r&ro=1&s1.asn=1&s1.uan=1&s1.aup=ListUsers&s1.pw=&s1.un=admin";
            lba.talk2server(this, this.listUsersCallback, authen_url, null, "Listing user accounts failed due to server errors.");                 
        }catch(e) {
            alert(e);
        }        
    },    
    editUser : function(rowid, un, pw, as, gp) {
        try{
        	// Define various event handlers for Dialog
        	var admin_obj = this;
        	var handleEditUser = function(uname, passwd, umas, group) {//execution context: Window
                //s1.asn=1 means the current user is in the 'administrator' group
                //s1.asn=2 means the current user is NOT in the 'administrator' group
                var authen_url = "?o=xml&a=pr&rt=r&ro=1&sa=authen&s=Authentication&s1.aup=EditUser" +
                        "&s1.pw=&s1.un=&s1.asn=1&s1.uan=1" +
                        "&s1.umas="+umas+"&s1.umc=x&s1.oumun="+uname+"&s1.umun="+uname+"&s1.umpw="+passwd+"&s1.umgp="+group+"&s1.cm=submit";
                //these values will be picked up in getUserRow()  
                var o = {};  
                o.rowid = rowid;    
                o.username = uname;
                o.password = passwd;
                o.account_status = umas;
                o.group = group;
                lba.talk2server(admin_obj, admin_obj.editUserCallback, authen_url, o,"Edit user failed due to server errors.");     
        	};
        	var handleOK = function() {//execution context: Dialog instance
               var data = this.getData();
               var uname = LLDL.trim(data["s1.umun"]); 
               if (uname === "") {
        	       alert("Please enter a user name");
        		   return false;
        	   } 
               if (uname.length < 2 || uname.length > 30) {
        	       alert("User name must be 2-30 characters");
        		   return false;
        	   } 
               var passwd = LLDL.trim(data["s1.umpw"]); 
               if (passwd === "") {
        	       alert("Please enter a password");
        		   return false;
        	   } 
               var passwd = LLDL.trim(data["s1.umpw"]); 
               if (passwd.length<3 || passwd>8) {
        	       alert("Password must be 3-8 characters");
        		   return false;
        	   } 
        	   
        	   var role = data["s1.role"];
        	   if(role === lba.teacher) {
            	   //documentation about data["s1.umgp[]"]: 'typeof group' will always be 'object'(Array in fact) even if none of the checkboxes is checked(group.length will be 0);
            	   var group = data["s1.umgp[]"];        	   
    //        	   alert(typeof group+" * "+group+" * "+group[0]+" * ");
            	   if(typeof group == "boolean") {//check the type of 'group'
			     if(!group){
            	                 alert("Please specify collection access for the user");
            	                 return false;
                             }
			     else{
			         role +=  ","+yud.get("colloname-input").value;
                              }
                   }
		   else{
        	          role += "," + group.join(",");
		       }
        	   }

               handleEditUser(uname, passwd, data["s1.umas"], role); 
        	};
            //pass the flag 'true' to signify that the username is not to be modified
            var form_str = this.getUserForm(un, pw, as, gp, true);
        	this.initDialog("Edit User", form_str, handleOK);
        }catch(e) {
            alert(e);
        }
    },
    deleteUser : function(rowid, umun, umpw, umgp) {
        try{
            var msg = "\n" +
                    "_______________________________________________\n\n" +
                    "Are you sure you want to delete the user: " + umun + "\n" +
                    "_______________________________________________\n\n" +
                    "Click Ok to proceed or Cancel to abort\n";
            if(!window.confirm(msg)) { return false; }
            var authen_url = "?o=xml&a=pr&rt=r&ro=1&sa=authen&s=Authentication&s1.aup=DeleteUser" +
                    "&s1.pw=&s1.un="+umun+"&s1.asn=1&s1.uan=1&s1.umun="+umun+"&s1.cm=yes";
            lba.talk2server(this, this.deleteUserCallback, authen_url, rowid, "Delete user failed due to server errors.");  
        }catch(e) { alert(e); }   
    },
    addUser : function() {
        try{
        	// Define various event handlers for Dialog
        	var admin_obj = this;
        	var handleAddUser = function(uname, passwd, umas, group) {//execution context: Window
                         //s1.asn=1 means the current user is in the 'administrator' group
                         //s1.asn=2 means the current user is NOT in the 'administrator' group
                         var authen_url = "?o=xml&a=pr&rt=r&ro=1&sa=authen&s=Authentication&s1.aup=AddUser" +
                                          "&s1.pw=&s1.un=&s1.asn=1&s1.uan=1" +
                                           "&s1.umas=true&s1.umc=x&s1.umun="+uname+"&s1.umpw="+passwd+"&s1.umgp="+group;
                         //these values will be picked up in getUserRow()        
                             var o = {};      
                             o.username = uname;
                             o.password = passwd;
                             o.account_status = umas;
                             o.group = group;
                              lba.talk2server(admin_obj, admin_obj.addUserCallback, authen_url, o, "Add user failed due to server errors.");     
        	}

        	var handleOK = function() {//execution context: Dialog instance
                      var data = this.getData();
                      var uname = LLDL.trim(data["s1.umun"]); 
                      if (uname === "") {
        	           alert("Please enter a user name");
        		   return false;
        	       } 
                     if (uname.length < 2 || uname.length > 30) {
        	       alert("User name must be 2-30 characters");
        		   return false;
        	      } 
                     var passwd = LLDL.trim(data["s1.umpw"]); 
                     if (passwd === "") {
        	       alert("Please enter a password");
        		   return false;
        	      } 
                     var passwd = LLDL.trim(data["s1.umpw"]); 
                     if (passwd.length<3 || passwd.length>8) {
        	       alert("Password must be between 3-8 characters");
        		   return false;
        	   } 
        	   var role = data["s1.role"];
		   if(role === lba.teacher) {
            	   //documentation about data["s1.umgp[]"]: 'typeof group' will always be 'object'(Array in fact) even if none of the checkboxes is checked(group.length will be 0);
            	   var group = data["s1.umgp[]"];        	   
		         
                   if(typeof group == "boolean") {//check the type of 'group'
			     if(!group){
            	                 alert("Please specify collection access for the user");
            	                 return false;
                             }
			     else{
			         role +=  ","+yud.get("colloname-input").value;
                              }
                   }
		   else{
        	          role += "," + group.join(",");
		       }
        	   } 
		   
                   handleAddUser(uname, passwd, data["s1.umas"], role); 
        	}

            //initialise default values for adding a new user
            var un = "", pw = "", as = "true", gp = lba.admin;
            var form_str = this.getUserForm(un, pw, as, gp, false);//'false' means 'username' field allows to be modified
	   
        	this.initDialog("Add User", form_str, handleOK);

        }catch(e) {
            alert(e);
        }        
    },
    changePassword: function() {
        try{
        	// Define various event handlers for Dialog
        	var admin_obj = this;
        	var handleChangePassword = function(new_passwd) {//execution context: Dialog instance
                var authen_url = "?o=xml&a=pr&sa=authen&s=Authentication&rt=r&ro=1&s1.aup=ModifyPassword&s1.asn=2&s1.uan=1&s1.umc=&s1.umgp=&s1.umun=&s1.umas=" +
                        "&s1.un="+admin_obj.user.username+"&s1.pw="+admin_obj.user.password+"&s1.umpw="+admin_obj.user.password+
                        "&s1.umpw1="+new_passwd+"&s1.umpw2=" +new_passwd;
                lba.talk2server(admin_obj, admin_obj.changePasswordCallback, authen_url, new_passwd, "Changing password failed due to server errors.");     
        	}
        	var handleOK = function() {//execution context: Dialog instance
               var data = this.getData();
               var pw = LLDL.trim(data["s1.pw"]);
               var pw1 = LLDL.trim(data["s1.umpw1"]);
               var pw2 = LLDL.trim(data["s1.umpw2"]);
                
               if (pw==="" || pw1==="" || pw2==="") {
        	       alert("Missing mandatory fields");
        		   return false;
        	   }
        	   if(pw !== admin_obj.user.password) {
        	       alert("Invalid old password");
        	       return false;
        	   } 
        	   if(pw1 !== pw2) {
        	       alert("New entered passwords mismatch");
        	       return false;
        	   } 
        	   lba.dialog.destroy(); lba.dialog = null;  
               handleChangePassword(pw1); 
        	}
            var form_str = "<form method='' action=''>" +
                              "<table>" +
                                "<tr><td><label for='s1.pw'>Old password:</label></td><td><input type='password' name='s1.pw' value='' /></td></tr>" +
                                "<tr><td><label for='s1.umpw1'>New password:</label></td><td><input type='password' name='s1.umpw1' value='' /></td></tr>" +
                                "<tr><td><label for='s1.umpw2'>Enter again:</label></td><td><input type='password' name='s1.umpw2' value='' /></td></tr>" +
                              "</table>" +
                            "</form>";
        	this.initDialog("Change Password", form_str, handleOK);

        }catch(e) { alert(e); }
    },
    login : function () {
        try{
        	// Define various event handlers for Dialog
        	var admin_obj = this;

        	var handleLogin = function(uname, passwd) {//execution context: Dialog instance
                         var authen_url = "?o=xml&a=pr&sa=authen&c=&s=Authentication&rt=r&ro=1&s1.asn=0&s1.uan=1&s1.aup=Login" +
                        "&s1.umpw1=&s1.umpw2=&s1.umc=&s1.umgp=&s1.umun=&s1.umpw=&s1.umas=" +
                        "&s1.un="+uname+"&s1.pw="+passwd;
		
		        lba.talk2server(admin_obj, admin_obj.loginCallback, authen_url, null, "Login failed due to server errors.");     
        	}
        	var handleOK = function() {//execution context: Dialog instance
                      var data = this.getData();
                      var uname = LLDL.trim(data["s1.un"]); 
                       if (uname === "") {
        	             alert("Please enter a user name");
        		    return false;
        	       } 
                      var passwd = LLDL.trim(data["s1.pw"]); 
                      if (passwd === "") {
        	          alert("Please enter a password");
        		    return false;
        	       } 
//        	         lba.dialog.destroy(); lba.dialog = null;  
		         handleLogin(uname, passwd); 
        	}
            var form_str = 
                "<form method='' action=''>" +
                  "<table>" +
                    "<tr><td><label for='s1.un'>Username:</label></td><td><input type='text' name='s1.un' value='' /></td></tr>" +
                    "<tr><td><label for='s1.pw'>Password:</label></td><td><input type='password' name='s1.pw' value='' /></td></tr>" +
                  "</table>" +
                "</form>";
                            
            this.initDialog("Login", form_str, handleOK);  
        }catch(e) {
            alert(e);
        }
    },
    guestLogin : function() {
        try{
            var uname = pw = "guest_"+parseInt(Math.random()*100000000);
            var umgp = "guest";
            (new Cookie(lba.un, uname)).set();
            (new Cookie(lba.pw, pw)).set();
            (new Cookie(lba.umgp, umgp)).set();                
            window.location.reload();    	        
        }catch(e) { alert(e); }
    },
    //Query all collections of a site, then filter out collections with ActivityManagement service configured
    queryCollections : function(usernode) {
        var req_library_url = "?o=xml&a=p&sa=home";//location to the 'library' link on Flax website
        lba.talk2server(this, this.queryCollectionsCallback, req_library_url, usernode, "QueryCollections failed due to server errors.");             
    },
    
    ////////////////////////////
    //////Ajax action callback functions
    queryCollectionsCallback : function(dom, usernode) {
        try{
            var isAMCollection = function(coll_el){
                var service_list = coll_el.getElementsByTagName("serviceList"); 
                if(!service_list || service_list.length<1) {  return false; }
                var service = yud.getElementsBy(function(e){ return (e.getAttribute("type")==="activity"); }, "service", service_list[0]);
                
                if(!service || service.length<1) { return false; }
                //alert(service[0].getAttribute("name"));
                return true;
            }
    	    var coll_list_node = dom.getElementsByTagName("collectionList");
    	    if(!coll_list_node || coll_list_node.length<1) { alert("collectionList node not found"); return false; }
    	    var colls = coll_list_node[0].getElementsByTagName("collection");
    	    if(colls.length < 1) { alert("No collection returned from server"); return false; }

            this.am_collections = [];
            var len = colls.length;
            var coll, name, title, summary;
	   
    	    for(var i=0; i<len; i++) {
    	        coll = colls[i]; 
    	        if(!isAMCollection(coll)) { continue; }    
    	        var am_coll = {name:null, title:null, summay:null};	        
    	        am_coll.name = coll.getAttribute("name");
    	        var displayItems = coll.getElementsByTagName("displayItem");
    	        for(var j=0; j<displayItems.length; j++) {
    	            var display_item = displayItems[j];
    	            var name_attr = display_item.getAttribute("name");
    	            if(name_attr && name_attr === "name") {
    	                am_coll.title = (display_item.firstChild&&display_item.firstChild.nodeValue)?display_item.firstChild.nodeValue : am_coll.name;
       	            }else 
       	            if(name_attr && name_attr === "description") {
    	                am_coll.summary = (display_item.firstChild&&display_item.firstChild.nodeValue)?display_item.firstChild.nodeValue : am_coll.name;
       	            }
    	        }
    	        
    	        this.am_collections[this.am_collections.length] = am_coll;
    	        
    	    }
    	    
            if(this.am_collections.length < 1) {
                //double check there is indeed legit collections filtered
	        this.am_collections = null;//reset it back
            } else {
                this.postListUsersCallback(usernode);
            }
        }catch(e) { alert(e); }
    },
    listUsersCallback : function(dom, o) {
        try{
            var usernode = this.getUserList(dom);
            if(!usernode) { return false; }
 
             if(this.am_collections) {
                this.postListUsersCallback(usernode);
                
            } else {
                //As long as this.am_collections !== null, its length won't be 0
                //queryCollectionsCallback() will eventually turn to postListUsersCallback() after this.am_collections is fulfilled
                this.queryCollections(usernode);                
            }
        }catch(e) {
            alert(e);
        }        
    },
    listStudentsCallback : function(dom, o) {
        try{
            var usernode = this.getUserList(dom);
            if(!usernode) { return false; }

	  
            var table = LLDL.createEl("table");
//            var tbody = yud.get(lba.userlist_tbody_id);
            
            tbody = LLDL.createEl("tbody", lba.userlist_tbody_id);                        
            var tr = LLDL.createEl("tr");
            tr.appendChild(LLDL.createEl("th", "", "Username"));
            tr.appendChild(LLDL.createEl("th","",""));
            tbody.appendChild(tr);
            //add current user as the person who manages the following students
            tr = LLDL.createEl("tr");
            tr.appendChild(LLDL.createEl("td", "", this.user.username));
            tr.appendChild(LLDL.createEl("td","",""));
            tbody.appendChild(tr);
            
            var node, umun, umgp, rowid, btns;
            for(var i=0; i<usernode.length; i++) {
                node = usernode[i];
                umgp = node.getAttribute(lba.umgp).split(",");
                if(umgp.indexOf(lba.student) === -1 || umgp.indexOf(this.user.username) === -1) {
                    continue;//skip users who are not student and their teacher is not current user
                }

                umun = node.getAttribute(lba.umun);
                if(!umun || umun.length<1) { continue; }
                rowid="row"+umun;
                tr = LLDL.createEl("tr");
                tr.appendChild(LLDL.createEl("td", "", umun));
                btns = "<a href='#' id='del_"+umun+"' rowid='"+rowid+"' umun='"+umun+"' umgp='"+umgp+"'>Delete</a>";
                tr.appendChild(LLDL.createInnerHTML("td", "", btns)); 
                tbody.appendChild(tr); 
            }//end of for()       
                
            table.appendChild(tbody);
            LLDL.clearup(lba.userlist_container);
            lba.showUserList();

            var frag = document.createDocumentFragment();
            frag.appendChild(this.getCloseButton()); 
            frag.appendChild(table);
            frag.appendChild(this.getAddStudentBody(30));
            lba.userlist_container.appendChild(frag);
        }catch(e) {
            alert(e);
        }        
    },
    getCloseButton : function() {
            var btn = LLDL.createInnerHTML("div", "", "<span id='close_btn_id'>close</span>", "close_btn_class"); 
            yue.on("close_btn_id", "click", lba.showContainer, this, true);
        return btn;
    },
    getUserList: function(dom) {
    	    var service_node = this.parseServiceNode(dom);
    	    if(!service_node) { alert("Mal-response from server"); return false; }
    	    var err = service_node.getAttribute("err");
    	    if(err && err.length>0) {
    	       alert(lba.server_error);
    	       return false;
    	    } 
    	    var usernodelist = service_node.getElementsByTagName("userNodeList");
    	    if(!usernodelist || !usernodelist[0]) { alert("No user returned from server"); return false; }
    	    var usernode = usernodelist[0].getElementsByTagName("userNode");
    	    if(!usernode || usernode.length<1) { alert("No user returned from server"); return false; }
    	    
    	    if(!this.all_user_list) {
        	    this.all_user_list = [];
                for(var i=0; i<usernode.length; i++) {
                    node = usernode[i];
                    umgp = node.getAttribute(lba.umgp);
                    umpw = node.getAttribute(lba.umpw);
                    umun = node.getAttribute(lba.umun);
                    this.all_user_list[this.all_user_list.length] = {username: umun, password:umpw, role:umgp};
                }
    	    }
    	    return usernode;
    },
    postListUsersCallback : function(usernode) {
        try{
            var table = LLDL.createEl("table");
            
            tbody = LLDL.createEl("tbody", lba.userlist_tbody_id);                        
            var tr = LLDL.createEl("tr");
            tr.appendChild(LLDL.createEl("th", "", "Username"));
            tr.appendChild(LLDL.createEl("th", "", "Account status"));
            tr.appendChild(LLDL.createEl("th", "", "Group"));
            tr.appendChild(LLDL.createEl("th","",""));
            tbody.appendChild(tr);
            var node, umun, umpw, umas, umgp, rowid;
            for(var i=0; i<usernode.length; i++) {
                node = usernode[i];
                umgp = node.getAttribute(lba.umgp).split(",");
                if(umgp.indexOf(lba.admin) === -1 && umgp.indexOf(lba.teacher) === -1) {
                    continue;//filter out students
                }
                
                umun = node.getAttribute(lba.umun);
                umpw = node.getAttribute(lba.umpw);
                umas = node.getAttribute(lba.umas);
                rowid = "row"+umun;
                var group = null;
                if(umgp.indexOf(lba.admin) !== -1) {
                    group = lba.admin;
                } else {
                    group = umgp.join(",");
                }
                if(!umun || !umas || !group || group.length<1) { continue; }
                
                tbody.appendChild(this.getUserRow(rowid, umun, umpw, umas, group)); 
            }//end of for()       
                
            table.appendChild(tbody);
            LLDL.clearup(lba.userlist_container);
            lba.showUserList();

            var frag = document.createDocumentFragment();
            frag.appendChild(this.getCloseButton()); 
            frag.appendChild(this.getAddUserBody());
            frag.appendChild(LLDL.createEl('hr'));
            var div = LLDL.createEl('div');
            div.appendChild(table);
            frag.appendChild(div);
            yud.setStyle(div, 'overflow','auto');
            yud.setStyle(div, 'height','450px');

            lba.userlist_container.appendChild(frag);
            
        }catch(e) {
            alert(e);
        }        
    },
    deleteUserCallback : function(dom, rowid) {
        try{
    	    var service_node = this.parseServiceNode(dom);
    	    if(!service_node) { alert("Mal-response from server"); return false; }
    	    var err = service_node.getAttribute("err");
    	    var info = service_node.getAttribute("info");
    	    if((err && err.length>0) || info !== "all-un") {
    	        alert("The following errors occurred: " + err);    	        
     	        return false;
    	    } else {
    	        var tbody = yud.get(lba.userlist_tbody_id);
                var urow = yud.get(rowid);
                if(tbody && urow) { tbody.removeChild(urow); }
    	    }
        }catch(e) {
            alert(e);
        }        
    },
    editUserCallback : function(dom, o) {
        try{
    	    var service_node = this.parseServiceNode(dom);
    	    if(!service_node) { alert("Mal-response from server"); return false; }
    	    var err = service_node.getAttribute("err");
    	    if(err && err.length>0) {
    	        if(err === "un-exist") {
    	            alert("Username unavailable");
    	        } else
    	        if(err === "un-err"){
    	            alert("Username contains non-ascii characters");
    	        } else
    	        if(err === "pw-err"){
    	            alert("Password contains non-ascii characters");
    	        } else {
    	            alert("The following errors occurred: " + err);
    	        }
     	        return false;
    	    } else {
    	        lba.dialog.destroy(); lba.dialog = null; 
                var tbody = yud.get(lba.userlist_tbody_id);
                var new_row = this.getUserRow("row"+o.username, o.username, o.password, o.account_status, o.group);
                var old_row = yud.get(o.rowid);
                if(tbody && new_row && old_row) { 
                    tbody.replaceChild(new_row, old_row);
                    if(o.username === (new Cookie(lba.un)).read()) {
                        //Given the fact that username is not to be edited, we can use o.username to check whether it's the current user
                        //whose info is being modified; if so, keep its password info in the cookie up to date as well.
                        (new Cookie(lba.pw, o.password)).set();
                        this.user.password = o.password;
                    } 
                }
                else { alert("Error occurred when updating user row in editUserCallback"); }
    	    }
        }catch(e) {
            alert(e);
        }        
    },
    addUserCallback : function(dom, o) {
        try{
    	    var service_node = this.parseServiceNode(dom);
    	    if(!service_node) { alert("Mal-response from server"); return false; }
    	    var err = service_node.getAttribute("err");
    	    if(err && err.length>0) {
    	        if(err === "un-exist") {
    	            alert("Username unavailable");
    	        } else
    	        if(err === "un-err"){
    	            alert("Username contains non-ascii characters");
    	        } else
    	        if(err === "pw-err"){
    	            alert("Password contains non-ascii characters");
    	        } else {
    	            alert("The following errors occurred: " + err);
    	        }
     	        return false;
    	    } else {
    	        lba.dialog.destroy(); lba.dialog = null; 
                var tbody = yud.get(lba.userlist_tbody_id);
                if(tbody) { tbody.appendChild(this.getUserRow("row"+o.username, o.username, o.password, o.account_status, o.group)); }
    	    }
        }catch(e) {
            alert(e);
        }        
    },
    changePasswordCallback : function(dom, new_passwd) {
	    try{
    	    var service_node = this.parseServiceNode(dom);
    	    if(!service_node) { alert("Mal-response from server"); return false; }
    	    var err = service_node.getAttribute("err");
    	    if(err === "") {
    	        this.user.password = new_passwd;
    	        (new Cookie(lba.pw, new_passwd)).set();
    	        
    	        alert("Password successfully modified");
    	    } else {
    	       alert("Error occurred during password modification: " + err);    	        
    	    } 
	    }catch(e) {
	        alert(e);
	    } 	            
    },
	loginCallback : function(dom, o) { 
	    try{
	        //: provides a veriaty of feedback messages for different invalid users
    	    
            var service_node = this.parseServiceNode(dom);
    	    if(!service_node) { alert("Mal-response returned from server"); return false; }
    	    var err = service_node.getAttribute("err");
    	    if(err && err.length>0) {
    	       if(err==="un-pw-err") { alert("Login failed: invalid username or password"); return false; }
    	       if(err==="as-false") { alert("Login failed: account disabled. See your administrator"); return false; }
    	       alert("Login failed: "+err);
    	       return false;
    	    } 
    	    var uname = service_node.getAttribute(lba.un);
    	    var pw = service_node.getAttribute(lba.pw);
    	    var umgp = service_node.getAttribute(lba.umgp);

          
    	    if((uname&&uname.length>0) && (pw&&pw.length>0) && (umgp&&umgp.length>0) ) {
    	        var group = umgp.split(","); 
	      // if(group.indexOf(lba.teacher) !== -1 &&
    	      //     group.indexOf(lba.collname) === -1) {
              //      var msg = "\n" +
              //              "_______________________________________________\n\n" +
              //              "You can login as a teacher, but you won't have access\n" +
              //              " to editing the activities of the collection.\n" +
              //              "If you believe you should, see your library administrator.\n" +
              //              "_______________________________________________\n\n";
    	      //      alert(msg);
    	      //  }
    	        
                (new Cookie(lba.un, uname)).set();
                (new Cookie(lba.pw, pw)).set();
                (new Cookie(lba.umgp, umgp)).set();                
                lba.dialog.destroy(); lba.dialog = null;   
                window.location.reload();    	     
    	    }
	    }catch(e) {
	        alert(e);
	    } 	    
	} 
};

