/**
 * @author: xiaofyu@gmail.com
 * 26/Jul/2007
 */
/**
 * Class used by both stand-alone and module
 * @constructor
 * @param container : HTML 
 * @param config {   }
 */
var lbb = LLDL.bundle.BuildCollection; 
LLDL.BuildCollection = function(container, config) {	
    this.config_info = config;
    this.config_info.classname = 'BuildCollection';
    this.timer = null;
    //A counter tracking how many collections are currently being built so as to determine whether to disable msg retrieving timer or not
    this.num_coll_being_built = 0;
    this.build_section_object_map = new HashMap();

    // Executing scripts
    this.collection_list_body = container;
    this.attachCollectionNodeEvents(container);
    this.getBody(container);
    this.flax_alert = new LLDL.FLAXAlert();
};
LLDL.BuildCollection.prototype = {    

    attachCollectionNodeEvents: function(container) {
        
        yue.on(container, 'click', function(e) {//Add handling of events bubbled up from each of the collection nodes
            var el = yue.getTarget(e);
    		if(!el || !(el.id)) { return true; }
    		var eid = el.getAttribute('collbtn');
    		if(!eid) { return true; }
            // Is it one of the functional btns of a collection being clicked?
            var idx = (el.id).indexOf('_');
            if(idx == -1) { return true; }
            var action = el.id.substring(0, idx);
            var collname = el.id.substring(idx+1);
            if(action=='edit') {
                this.editCollection(collname);
            }else if(action=='preview') {
                window.open('?a=fp&sa=collAbout&c='+collname, 'previewcollection');
            }else if(action=='del') {
                this.deleteCollection(collname);
            }else if(action=='copy') {
            	var coll_obj = this.config_info.collection_map.get(collname);                    
                var o = {coll_obj:coll_obj, newcolltitle:'Copy of '+coll_obj.meta.title};
            	this.copyCollection(o);
//                this.promptCollectionName(this.copyCollection, 'New collection name', collname);
            }
            
        }, this, true);
        
    },
    getBody: function(container) {
        this.getBuildButton();//init this.build_button_body
        yud.insertAfter(this.build_button_body, container);

//        var close_window_btn = LLDL.createButtonEl(null, 'Close this window');
//        this.build_button_body.appendChild(close_window_btn);
//        yud.setStyle(close_window_btn, 'float', 'left');
//        yue.on(close_window_btn, 'click', function() { self.close(); });
        
        this.build_body = LLDL.createEl('div', '','','build_body_class');        
        yud.insertAfter(this.build_body, this.build_button_body);
        LLDL.setElementsStyle([this.build_button_body, this.build_body], ['display', 'display'], ['', 'none']); 
        
//        //Check if there are collections being built at this point; if so, start the query timer
//        for(var i=0; i<this.config_info.collection_map.size(); i++) {
//        	var coll = this.config_info.collection_map.valSet()[i];
//        	if(coll.meta.state === lbb.building) {
//        		//If a collection is being built, its state is set to 'building' in ListCollections.java
//        		//There is at least one collection that is being built, start timer
//        		this.startTimer();
//        	}
//        }
        
    },
    getNewCollectionMetadata: function(collname) {
	    var metadata_list = this.config_info.model_collection_config_xml.getElementsByTagName('metadataList')[0];
	    var activity_metadata = LLDL.getNamedElement(metadata_list, 'metadata', 'name', 'activity');
	    var act_list = activity_metadata.firstChild.data;
	    var doclist_metadata_el = LLDL.getNamedElement(metadata_list, 'metadata', 'name', 'docList');
	    var collo_metadata_el = LLDL.getNamedElement(metadata_list, 'metadata', 'name', 'collocation');
//	    var extract_collo = collo_metadata_el.getAttribute('value');// '1' or '0'
//	    var collocation = { extract_collo: extract_collo, 
//	                        metamap: new HashMap() };
//   
//    	var metalist = collo_metadata_el.getElementsByTagName('meta');
//    	var name, title, value;
//    	for(var i=0; i<metalist.length; i++) {
//    		var m = metalist[i];
//    		name = m.getAttribute('name');
//    		displayName = m.getAttribute('displayName');
//    		value = m.getAttribute('value');
//    		var itemlist = m.getElementsByTagName('displayItem');
//    		var items = [];
//    		for(var k=0; k<itemlist.length; k++) {
//    			items.push({value:itemlist[k].getAttribute('value'), title:itemlist[k].firstChild.data});
//    		}
//            collocation.metamap.put(name, {
//    			name: name,
//    			displayName: displayName,
//    			value: value,
//    			items: items
//    		});	    		
//    	}
	
    	// Default 'build' type of a collection
    	var coll_lang = 'en'; var coll_type = 'txt';
        var build_option_value = 'entxtcollo';//window.prompt("Enter collection type:", 'entxt');//'entxt';   
        var new_coll_meta = {
        	build: build_option_value,
        	lang: coll_lang,
        	collname: collname, 
        	creator: this.config_info.username,
        	category:lbb.c4,
        	mdlsiteid:this.config_info.mdlsiteid,
        	title:'',
        	description:'',
        	activity:act_list,
        	docList:doclist_metadata_el,
        	collocation:collo_metadata_el
        }
        return new_coll_meta;
    },
    getBuildButton: function() {
        // do 'Design collection' button
        this.build_button_body = LLDL.createEl('div', '', '', 'build_btn_body_class');
        var build_new_coll_btn = LLDL.createButtonEl(null, 'Create a new collection');
        this.build_button_body.appendChild(build_new_coll_btn);
        yue.on(build_new_coll_btn, 'click', function() {
            var collname = this.generateCollname(this.config_info.username);
            var new_coll_meta = this.getNewCollectionMetadata(collname);
            
            var coll_obj = new LLDL.Bean.FlaxCollection(this.config_info, new_coll_meta);
            
            this.setCollInEdit(collname);
            
            // Put the basic model collection obj to editing
            LLDL.clearup(this.build_body);//clear up the editing panel
            var button_body = this.getCollEditPanelButtonBody(coll_obj);
            this.getBuildEditorPanel(this.build_body, coll_obj);
            this.build_body.appendChild(button_body);
            LLDL.setElementsStyle([this.collection_list_body, this.build_button_body, this.build_body], 
            ['display', 'display', 'display'], ['none', 'none', '']);            

//            LLDL.animScrollIntoView(this.build_body, 1);//causes unnecessary page jumping
        }, this, true);
/* // Use this block, instead of above, when we have more options on new collection configuration. For example, mr+txt, en+img, etc. //////
        this.build_button_body = LLDL.createEl('fieldset', '', '', 'build_btn_body_class');
        this.build_button_body.appendChild(LLDL.createEl('legend', '', 'New collection configuration'));
        var table = LLDL.createEl('tbody');
        
        // lang menu
        var lang_list = this.config_info.collection_build_xml.getElementsByTagName('contentLanguageOptionList')[0].getElementsByTagName('option');
        var lang_tr = LLDL.createEl('tr'); table.appendChild(lang_tr);
        var td = LLDL.createEl('td', '', 'Select collection language', 'label'); lang_tr.appendChild(td);
        var option_arr = [];
        for(var op, selected, i=0; i<lang_list.length; i++) {
        	op = lang_list[i];
        	selected = (i==0)? true : false;
        	option_arr.push({value:op.getAttribute('name'),
        	                 title: op.getAttribute('value'),
        	                 selected: selected});
        }
        var lang_obj = new UI.SingleSelectionList(option_arr);
        var lang_li = LLDL.createEl('td','','','menu_td'); lang_li.appendChild(lang_obj.body);
        lang_tr.appendChild(lang_li);
        
        // Content type menu
        var content_type_list = this.config_info.collection_build_xml.getElementsByTagName('contentTypeOptionList')[0].getElementsByTagName('option');
        var content_tr = LLDL.createEl('tr'); table.appendChild(content_tr);
        li = LLDL.createInnerHTML('td', '', 'Select collection content type', 'label');
        content_tr.appendChild(li);
        option_arr = [];
        for(var op, selected, i=0; i<content_type_list.length; i++) {
            op = content_type_list[i];
            selected = (i==0)? true : false;
            option_arr.push({value:op.getAttribute('name'),
                             title: op.getAttribute('value'),
                             selected: selected});
        }
        var type_obj = new UI.SingleSelectionList(option_arr);
        var type_li = LLDL.createEl('td','','','menu_td'); type_li.appendChild(type_obj.body);
        content_tr.appendChild(type_li);
        
        var table_el = LLDL.createEl('table'); table_el.appendChild(table);
        this.build_button_body.appendChild(table_el);

        var build_new_coll_btn = LLDL.createButtonEl(null, 'Build a new collection');
        var btn_tr = LLDL.createEl('tr'); btn_tr.appendChild(LLDL.createEl('td'));btn_tr.appendChild(LLDL.createEl('td'));
        var btn_td = LLDL.createEl('td','','','btn_td'); btn_td.appendChild(build_new_coll_btn);
        btn_tr.appendChild(btn_td);
        table.appendChild(btn_tr);
        
        yue.on(build_new_coll_btn, 'click', function(e) {
        	var build_option_value = lang_obj.get() + type_obj.get();

            var collname = this.generateCollname(this.config_info.username);
	        var coll_obj = LLDL.FlaxCollection.getModelCollection(this.config_info, build_option_value);
	        coll_obj.meta.collname = collname;
	        coll_obj.meta.creator = this.config_info.username;
	        coll_obj.meta.lang = lang_obj.get();
            var button_body = this.getCollEditPanelButtonBody(coll_obj);

            var table = LLDL.createEl('table');
            var tbody = LLDL.createEl('tbody');
            var tr = LLDL.createEl('tr'); table.appendChild(tbody); tbody.appendChild(tr);
//	        var tabnav = LLDL.createEl('ul', '', '', 'tabnav');
	        this.build_body.appendChild(table);
	        yud.setStyle(table, 'width', '100%');
	        this.getTabNavBody({head:tr, body:this.build_body}, coll_obj);
	        this.build_body.appendChild(button_body);
	        LLDL.setElementsStyle([this.build_button_body, this.build_body], ['display', 'display'], ['none', '']);
        }, this, true);
*/        
        
        return this.build_button_body;
    },
    editCollection: function(collname) {
        // Check out if there is already a collection being edited in the build body; if so, warn the user all data will be lost if proceed.
        if(this.collname_in_edit){
            if(this.collname_in_edit === collname) { return; }
            var msg = "\n" +
                        "__________________________________________________\n\n" +
                        "A collection is currently being edited.\n\n" +
                        "If you proceed, any modifications will be lost!\n\n" +
                        "__________________________________________________\n\n" +
                        "Discard your changes?\n\n";
            if(!window.confirm(msg)){return false;}
        }
        this.setCollInEdit(collname);
//        console.log('collname='+collname);
        var coll_obj = this.config_info.collection_map.get(collname);
        LLDL.clearup(this.build_body);//clear up the editing panel
        var button_body = this.getCollEditPanelButtonBody(coll_obj);
        this.getBuildEditorPanel(this.build_body, coll_obj);
        this.build_body.appendChild(button_body);
        LLDL.setElementsStyle([this.collection_list_body, this.build_button_body, this.build_body], ['display', 'display', 'display'], ['none', 'none', '']);

        LLDL.animScrollIntoView(this.build_body, 1);

    },
    generateCollname: function(uname) {
    	//For the purposes of building password and imgdemo collections
//    	var cname = window.prompt("Enter collection name:"); return cname;

        var collname_prefix = uname + this.config_info.mdlsiteindex + 'c';
        var filtered_collname_arr = [];
        var collname_arr = this.config_info.collection_map.keySet();
        for(var collname, i=0; i<collname_arr.length; i++) {
            collname = collname_arr[i];
            if(LLDL.startsWith(collname, collname_prefix)) {
            	filtered_collname_arr.push(collname);
            }
        }

        var max_num = 0;
        for(var digit, collname, i=0; i<filtered_collname_arr.length; i++) {
            collname = filtered_collname_arr[i];
            var result = collname.match(/\d+$/);
            if(result != null){
                digit = parseInt(result[0]);
//                console.log('digit='+digit);
                if(digit > max_num) {
                    max_num = digit;
                }
            }
        }
        var newcollname = collname_prefix + (max_num+1);
//        console.log('newcollname='+newcollname);
        return newcollname;
    },
    //This function is called in ListCollections.js when drag-drop collections between different categories
    setCollectionCategory: function(config) {
        var coll_obj = config.coll_obj;
        var collname = coll_obj.meta.collname;
    	var url = this.config_info.ajax_server_url+'&s=BuildCollection' +
                '&s1.service='+LLDL.services.SET_COLL_CATEGORY+"&s1.collname="+collname+
                "&s1.category="+config.category+"&s1.stus="+config.stus;
        var obj = {caller_obj: this,
                   callback_fn: this.setCollectionCategoryCallback,
                   http_method: 'GET',
                   url: url,
                   err_msg: 'Error occurred when activating collection: '+collname,
                   passover_obj: config,
                   postdata: null,
                   show_loading_panel: true,
                   loading_img_url: this.config_info.images_url+'blocking_loading.gif'};
        LLDL.talk2server(obj);
    },
    setCollectionCategoryCallback: function(xml, config) {
        var msg_el = xml.getElementsByTagName(LLDL.MESSAGE)[0];
        var cname = msg_el.getAttribute("collname");
        var type = msg_el.getAttribute(LLDL.TYPE);
        var coll_obj = config.coll_obj;
        if(type == "1") {
            var cate = msg_el.getAttribute("category");
        	coll_obj.setCategory(cate);//set collection's category
            coll_obj.updateStyle();
            //Since the opt on the server side was successful, move the collection node into the intended block
            config.parent_node.appendChild(config.child_node);
            this.config_info.list_collections_obj.refreshList();
        } 
        else {
            console.log('In setCollectionCategoryCallback: type<>1');
        }   
    },
    deleteCollection: function(collname) {
    	var coll_obj = this.config_info.collection_map.get(collname);
        var msg = "\n" +
        "_______________________________________________\n\n" +
        "Are you sure you really want to delete the\n\n" +
        "collection: "+coll_obj.meta.title+"?\n\n" +
        "_______________________________________________\n\n" +
        "Click Ok to proceed or Cancel to abort\n";
        if(!window.confirm(msg)){return false;}
        
        var url = this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.DEL_COLL
                  +"&s1.collname="+collname+"&s1.category="+coll_obj.meta.category;
        var obj = {caller_obj: this,
                   callback_fn: this.deleteCollectionCallback,
                   http_method: 'GET',
                   url: url,
                   err_msg: 'Error occurred when deleting collection',
                   passover_obj: null,
                   postdata: null,
                   show_loading_panel: true,
                   loading_img_url: this.config_info.images_url+'blocking_loading.gif'};
        LLDL.talk2server(obj);
    },
    deleteCollectionCallback: function(xml) {
        var msg_el = xml.getElementsByTagName(LLDL.MESSAGE)[0];
        var cname = msg_el.getAttribute("collname");
        var type = msg_el.getAttribute(LLDL.TYPE);
        if(type == "1") {
            var coll_obj = this.config_info.collection_map.get(cname);
            this.config_info.private_block.removeChild(coll_obj.body);
            this.config_info.list_collections_obj.refreshBlock(this.config_info.private_block);
            this.config_info.collection_map.remove(cname);// delete it from collection map
        } 
        else {
            var msg = "____________________________\n\n" +
                      "For some reason, the request\n\n" +
                      "couldn't be fulfilled by " +
                      "the server. Please try again.\n\n" +
                      "____________________________";
            console.log('In deleteCollectionCallback: type<>1');//alert(msg);       
        }   
    },
		// Make a copy of a collection. The resulted collection only has two directories: 'etc' and 'archives'. 
		// This copied collection's category is set to tobuild
    duplicateCollection: function(old_coll_obj, newcollname, newcolltitle) {
    	var new_meta = {};
    	for(var p in old_coll_obj.meta) {
//    		console.log('meta.p='+p);
    		new_meta[p] = old_coll_obj.meta[p];
    	}
    	new_meta.category = lbb.c4;
    	new_meta.collname = newcollname;
    	new_meta.title = newcolltitle;
    	var new_coll_obj = new LLDL.Bean.FlaxCollection(this.config_info, new_meta);
//    	console.log('newcoll doclist='+new_coll_obj.meta['docList']);
//        console.log('oldcoll doclist='+old_coll_obj.meta['docList']);
    	return new_coll_obj;
    },
	promptCollectionName : function (fn, popup_window_title, collname) {
        var coll_obj = this.config_info.collection_map.get(collname);        
	        var handleOK = function(data) {
	            var new_coll_title = LLDL.trim(data["collection_name"]); 
	            fn.call(this, {coll_obj:coll_obj, newcolltitle:new_coll_title});
	        };
	        var handleCancel = function(){}; 
	        var form_str = 
	            "<label for='collection_name'>Choose a new collection name:</label>" +
	            "<input type='text' name='collection_name' value='Copy of "+coll_obj.meta.title+"' />";
	        LLDL.promptData(popup_window_title, form_str, handleOK, function(){}, this);
	},
    copyCollection: function(o) {    	
        var newcollname = this.generateCollname(this.config_info.username);
        var new_coll_obj = this.duplicateCollection(o.coll_obj, newcollname, o.newcolltitle);
        var url = this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.COPY_COLL+
        "&s1.collname="+o.coll_obj.meta.collname+"&s1."+lbb.newcolltitle+"="+o.newcolltitle
        +"&s1."+lbb.newcollname+"="+newcollname+"&s1."+lbb.newcollcategory+"="+new_coll_obj.meta.category;
        var obj = {caller_obj: this,
                   callback_fn: this.copyCollectionCallback,
                   http_method: 'GET',
                   url: url,
                   err_msg: 'Error occurred when deleting collection',
                   passover_obj: new_coll_obj,
                   postdata: null,
                   show_loading_panel: true,
                   loading_img_url: this.config_info.images_url+'blocking_loading.gif'};
        LLDL.talk2server(obj);
    },
    copyCollectionCallback: function(xml, new_coll_obj) {
        var msg_el = xml.getElementsByTagName(LLDL.MESSAGE)[0];
        var newcollname = msg_el.getAttribute("collname");
        var type = msg_el.getAttribute(LLDL.TYPE);
        if(type == "1") {
        	this.config_info.collection_map.put(newcollname, new_coll_obj);
            this.config_info.private_block.appendChild(new_coll_obj.getBody());
            this.config_info.list_collections_obj.refreshBlock(this.config_info.private_block);            
        } else {
            var msg = "____________________________\n\n" +
                      "Error occurred while copying\n\n" +
                      "collections. Please try again.\n\n" +
                      "____________________________";
            console.log('In copyCollectionCallback: type<>1');  
        }   
    },
    getBuildEditorPanel: function(container, coll_obj) {
//            var table = LLDL.createEl('table','','','section');
//            var tr = LLDL.createEl('tr','','','section_head'); 
//            table.appendChild(tr);
////          var tabnav = LLDL.createEl('ul', '', '', 'tabnav');
//            this.build_body.appendChild(table);
////            yud.setStyle(table, 'width', '100%');

        var active_tab_class = 'activetab';

        this.config_info.active_tab_class = active_tab_class;
        this.config_info.inactive_tab_class = '';
        this.config_info.coll_obj = coll_obj;
        this.config_info.super_class = this;
        // 'build_section_map' of each collection object was inited in LLDL.FlaxCollection (file: BeanObject.js)
        /** <buildType name="entxt">
              <section step="0" name="CollectionInfo" />
              <section step="1" name="Documents" />
              <section step="2" name="ActivityInfo"/>
              <section step="3" name="Build" />
            </buildType>
        * */
        var build_section_arr = (coll_obj.build_section_map).valSet().slice();
        build_section_arr.sort(function(a, b){return (parseInt(a.step) > parseInt(b.step));})
        for(var i=0; i<build_section_arr.length; i++) {
            var section = build_section_arr[i];
            var section_obj = new LLDL.BuildCollection[section.name](container, this.config_info);
            if(section.step === "0") {
            	section_obj.tab.setActive(true, active_tab_class);
            } else {
            	section_obj.tab.setActive(false, this.config_info.inactive_tab_class);
            }
            this.build_section_object_map.put(section.name, section_obj);
        }

    },
    getTabNavBody: function(tabnav, coll_obj) {
    },
    disableNavButtons: function(value) {
        LLDL.setButtonDisable('prev', value);
        LLDL.setButtonDisable('next', value);
    },
    getCollEditPanelButtonBody: function(coll_obj) {
    	this.current_step_index = 0;
    	
        // Action buttons
        var button_body = LLDL.createEl('div', '', '', 'btn_body_class');
        
        var exit_btn = LLDL.createButtonEl('exit', 'Exit');
        yud.setStyle(exit_btn, 'float', 'left');
        exit_btn.coll_obj = coll_obj;
        button_body.appendChild(exit_btn);
        yue.on(exit_btn, 'click', function(e) {
            this.exit(exit_btn.coll_obj);
        }, this, true);

        var prev_btn = LLDL.createButtonEl('prev', 'Previous');
//        yud.setStyle(prev_btn, 'display', 'none');
          yud.setStyle(prev_btn, 'visibility', 'hidden');
        prev_btn.coll_obj = coll_obj;

        var next_btn = LLDL.createButtonEl('next', 'Next');
        next_btn.coll_obj = coll_obj;
        button_body.appendChild(prev_btn);
        button_body.appendChild(next_btn);

        yue.on(prev_btn, 'click', function(e) {
        	var next_step_index = this.current_step_index - 1;
        	this.build_section_object_map.valSet()[this.current_step_index].saveData(next_step_index, prev_btn, next_btn);
        }, this, true);
        yue.on(next_btn, 'click', function(e) {
            var next_step_index = this.current_step_index + 1;
            this.build_section_object_map.valSet()[this.current_step_index].saveData(next_step_index, prev_btn, next_btn);
        }, this, true);

        return button_body;
    },
    exit: function(coll_obj) {
        LLDL.setElementsStyle([this.collection_list_body, this.build_button_body, this.build_body], ['display', 'display', 'display'], ['', '', 'none']);
        if(this.config_info.collection_map.containsKey(coll_obj.getCollname())){
        	if(coll_obj.meta.category != lbb.c4) {
	            //if it's editting an existing good collection, refresh the collection title.
	            this.config_info.list_collections_obj.removeDD(coll_obj.meta.collname);
	            coll_obj.setCategory(lbb.c4);
        	}
            coll_obj.refresh();
            this.config_info.list_collections_obj.refreshList();
        }        
        this.setCollInEdit(null);
    },
    setCollInEdit: function(collname) {
    	this.collname_in_edit = collname;
    },
    navSections: function(next_step_index, prev_btn, next_btn) {
    	this.current_step_index = next_step_index;
    	
            if(this.current_step_index == 0){
//                yud.setStyle(prev_btn, 'display', 'none');
                yud.setStyle(prev_btn, 'visibility', 'hidden');
            }else {
//                yud.setStyle(prev_btn, 'display', '');
                yud.setStyle(prev_btn, 'visibility', 'visible');
            }       
            if(this.current_step_index == this.build_section_object_map.size() - 1 ){
//                yud.setStyle(next_btn, 'display', 'none');
                yud.setStyle(next_btn, 'visibility', 'hidden');
            }else {
//                yud.setStyle(next_btn, 'display', '');
                yud.setStyle(next_btn, 'visibility', 'visible');
            }
            var sec_to_show = this.build_section_object_map.valSet()[this.current_step_index];
            var section_obj_arr = this.build_section_object_map.valSet();
            for(var i=0; i<section_obj_arr.length; i++) {
                var section_obj = section_obj_arr[i]; 
                section_obj.show(sec_to_show.tab.head.id === section_obj.name, this.config_info.active_tab_class);              
            }
             
    },
    getOKResponse: function(xml) {
            // xml: <response><message type="1"/></response>
            // or: <response><error type="other"/></response>
        var msg_el = xml.getElementsByTagName(LLDL.MESSAGE)[0];
        if(!msg_el) { console.log('message element not found. most likely exception occurred on server'); return false; }
        var type = msg_el.getAttribute(LLDL.TYPE);
        return (type == "1");
    }
    /*,
    startTimer: function() {
        var context_obj = this;
        this.timer = window.setTimeout(function() {
            context_obj.queryCollBuildState.call(context_obj);
        }, 500);
    },
    stopTimer: function() {
        window.clearTimeout(this.timer); 
    }*/    
};//End of prototype
LLDL.BuildCollection.Tab = function(container, o) {
    this.id = o.tab_id;
    this.head_class_name = o.head_class;
    this.body_class_name = o.body_class;
    this.title = o.tab_title;
    this.tab_body_name = o.tab_body_name;
    this.is_default = o.is_default;
    
    this.name_class = 'name left';
    this.value_class = 'value right';
    
    this.head = this.getTabHead();
    this.body = this.getTabBody();
//    container.head.appendChild(this.head);
    container.appendChild(this.body);
};
LLDL.BuildCollection.Tab.prototype = {
    getTabHead: function() {
        var tab = LLDL.createEl('td', this.id, '', this.head_class_name);
        tab.innerHTML = "<a href='javascript:void(null);'>"+this.title+"</a>";
        return tab;
    },
    getTabBody: function() {
        var tab_body = LLDL.createEl('form', '', '', this.body_class_name);
        tab_body.setAttribute('name', this.tab_body_name);
        yud.setStyle(tab_body, 'display', (this.is_default? '' : 'none'));
        return tab_body;
    },
    setActive: function(show, active_tab_class) {      
        if(show) { 
            yud.addClass(this.head, active_tab_class);
            yud.setStyle(this.body, 'display', '');     
        } else {
            yud.removeClass(this.head, active_tab_class);
            yud.setStyle(this.body, 'display', 'none');         
        }
    }
};
LLDL.BuildCollection.CollectionInfo = function(container, config) {
	this.name = 'CollectionInfo';
	this.config_info = config;
    var o = {tab_id: this.name,
                   head_class: '',//this.config_info.active_tab_class,
                   body_class: 'tabbody',
                   tab_title: 'Collection Info',
                   tab_body_name: this.name,
                   is_default: true};
    this.tab = new LLDL.BuildCollection.Tab(container, o);
    this.getSectionBody();
};
LLDL.BuildCollection.CollectionInfo.prototype = {
    getSectionBody : function() {
LLDL.__help_info = ['collection_name.html', 'collection_description.html'];    	
        // collection name
        var html = "<span class='label_text'>Collection name" +
                LLDL.getHelpButtonInnerHTML(this.config_info, this.config_info.classname+ ".collection_name", this.config_info.lang)+
                "</span><br/><input class='coll_title_class' name='title' type='text' value='"+this.config_info.coll_obj.meta.title+"' />";
        var coll_name_el = LLDL.createInnerHTML("div", "", html, "title_div_class");
        this.tab.body.appendChild(coll_name_el);

        // collection description
        html = "<span class='label_text'>Collection description" +
        		LLDL.getHelpButtonInnerHTML(this.config_info, this.config_info.classname+ ".collection_description", this.config_info.lang)+
                "</span><br/><textarea class='coll_description_class' name='description' rows='18' cols='90''>"+
                this.config_info.coll_obj.meta.description+"</textarea>";
        this.tab.body.appendChild(LLDL.createInnerHTML("div", "", html, "content_div_class"));
        yue.onAvailable(this.tab.body, function() {
            this.tab.body.title.focus();
        }, this, true);
    },
    getData: function() {
        var title = LLDL.trim(this.tab.body.title.value);
        if(!title) {
            var msg = "<p></p>" +
                      "<p>Please enter a collection name</p>" +
                      "<p></p>";
            this.config_info.super_class.flax_alert.setHeader(msg);
            this.config_info.super_class.flax_alert.show();
            this.tab.body.title.focus();
            return false;
        }
        var description = LLDL.trim(this.tab.body.description.value);
        if(!description) {
            var msg = "<p></p>" +
                      "<p>Please write a description of the collection</p>" +
                      "<p></p>";
            this.config_info.super_class.flax_alert.setHeader(msg);
            this.config_info.super_class.flax_alert.show();
            this.tab.body.title.focus();
            return false;
        }
        var description = LLDL.trim(this.tab.body.description.value);
        if(this.config_info.coll_obj.meta.title === title && this.config_info.coll_obj.meta.description === description) { 
        	//if neither title nor description are changed, we won't send saving data request to server
            return true; 
        }

        var data = {};
       	data.title = title;
        data.description = description;
        return data;
    },
    saveData: function(next_step_index, prev_btn, next_btn) {
    	
        var data = this.getData();
        if(data === false) { 
        	// Invalid data input. Remain on current section
        	return false; 
        }
        if(data === true) { 
        	// No data has been modified. Moving on to next section without the need of saving data to server
        	this.config_info.super_class.navSections(next_step_index, prev_btn, next_btn);
        	return true;
        }
        var postdata = [];
        for(var p in data) {
            postdata.push('s1.'+p+'='+data[p]);
        }
        postdata.push('s1.creator='+this.config_info.username);
        postdata.push('s1.build='+this.config_info.coll_obj.meta.build);
        postdata.push('s1.lang='+this.config_info.coll_obj.meta.lang);
        
        postdata.push('s1.mdlsiteid='+this.config_info.mdlsiteid);
    	
    	var passover_o = [data, next_step_index, prev_btn, next_btn];
       console.log(postdata.join(','));
        LLDL.talk2server( {caller_obj: this,
		                   callback_fn: this.saveDataCallback,
		                   http_method: 'POST',
		                   url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.SAVE_COLL+
		                        '&s1.step='+this.name+'&s1.collname='+this.config_info.coll_obj.meta.collname,
		                   err_msg: 'Error occurred when saving collection: '+this.name,
		                   passover_obj: passover_o,
		                   postdata: postdata.join('&'),
		                   show_loading_panel: true,
		                   loading_img_url: this.config_info.images_url+'blocking_loading.gif'
		                  } );
    },
    saveDataCallback: function(xml, arr) {
        if(this.config_info.super_class.getOKResponse(xml)) {
        	// Saving coll data on server was successful, assign the title/description of the coll obj on the client side
        	var coll_data = arr[0];
        	for(var p in coll_data) {
	            this.config_info.coll_obj.meta[p] = coll_data[p];
	        }
        	
            if(this.config_info.collection_map.containsKey(this.config_info.coll_obj.meta.collname)===false){
                // it's a new collection, add it to map, append into dom tree
                this.config_info.collection_map.put(this.config_info.coll_obj.meta.collname, this.config_info.coll_obj);
                this.config_info.private_block.appendChild(this.config_info.coll_obj.getBody());
            }

        	this.config_info.super_class.navSections(arr[1], arr[2], arr[3]);
        } else {
            console.log('In CollectionInfo/saveDataCallback: errorOnServer');          
            this.config_info.super_class.exit(this.config_info.coll_obj);
        }
    	
    },
    show: function(show/*boolean*/, css_class) {
        this.tab.setActive(show, css_class);     	
    },
    // function used to put together information about this section on the last page 
    // of the collection building process before the collection finally gets built.
    showSectionInfo: function(container) {
        
        //coll name
        var coll_title = this.config_info.coll_obj.meta.title;
        var tr = LLDL.createEl('tr'); 
        var td_name = LLDL.createEl('td','','Collection name', this.tab.name_class); 
        var td_value = LLDL.createEl('td','',coll_title, this.tab.value_class);
        tr.appendChild(td_name); tr.appendChild(td_value); 
        container.appendChild(tr);
        	
        //coll description
        var coll_des = this.config_info.coll_obj.meta.description;
        tr = LLDL.createEl('tr'); 
        td_name = LLDL.createEl('td','','Description', this.tab.name_class); 
        td_value = LLDL.createEl('td','',coll_des,this.tab.value_class);
        tr.appendChild(td_name); tr.appendChild(td_value); 
        container.appendChild(tr);
        
        return true;
    }    
};
LLDL.BuildCollection.ActivityInfo = function(container, config) {
    this.name = 'ActivityInfo';
    this.config_info = config;
    this.coll_obj = config.coll_obj;
    var o = {tab_id: this.name,
                   head_class: '',
                   body_class: 'tabbody',
                   tab_title: 'Activities',
                   tab_body_name: this.name,
                   is_default: false};
    this.tab = new LLDL.BuildCollection.Tab(container, o);
    this.getSectionBody();
    
};
LLDL.BuildCollection.ActivityInfo.prototype = {
	getSectionBody: function() {
		var div = LLDL.createEl('div','','','title_div_class');
		var label_text = LLDL.createInnerHTML('span','','Check the activity types to include'+
		  LLDL.getHelpButtonInnerHTML(this.config_info, this.config_info.classname+ ".select_activity", this.config_info.lang),'label_text');
		div.appendChild(label_text);
		this.tab.body.appendChild(div);
		
        // The value of default_activity_list is determined in flax-resources/collectionConfig.xml
        var metadata_list = this.config_info.model_collection_config_xml.getElementsByTagName('metadataList')[0];
        var default_activity_list = LLDL.getNamedElement(metadata_list, 'metadata', 'name', 'activity').firstChild.nodeValue;//  this.config_info.coll_obj.build_section_map.get(this.name)['activityList'];
        // Activties the user had chosen last time the collection was being built (or all activity types if new collection)
        // user_chosen_activity_list <= default_activity_list
        this.activity_list_obj = new LLDL.BuildCollection.ActivityList('activity_list_body');
        var user_chosen_activity_list = this.config_info.coll_obj.meta.activity;
        console.log(user_chosen_activity_list);
        this.tab.body.appendChild(this.activity_list_obj.getBody(default_activity_list, user_chosen_activity_list, this.config_info.all_activity_map));
	},
    saveData: function(next_step_index, prev_btn, next_btn) {
        var data = this.activity_list_obj.getList();
        if(this.config_info.coll_obj.meta.activity === data) {
            this.config_info.super_class.navSections(next_step_index, prev_btn, next_btn);
        	return true;//no change has been made
        }
        var passover_o = [data, next_step_index, prev_btn, next_btn];
        LLDL.talk2server( {caller_obj: this,
                           callback_fn: this.saveDataCallback,
                           http_method: 'POST',
                           url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.SAVE_COLL+
                                '&s1.step='+this.name+'&s1.collname='+this.config_info.coll_obj.meta.collname,
                           err_msg: 'Error occurred when saving collection: '+this.name,
                           passover_obj: passover_o,
                           postdata: 's1.activity='+data,// keyword 'activity' is defined in BeanObjects.js/getModelCollection()
                           show_loading_panel: true,
                           loading_img_url: this.config_info.images_url+'blocking_loading.gif'
                          } );
    },
    saveDataCallback: function(xml, arr) {
        if(this.config_info.super_class.getOKResponse(xml)) {
        	// Saving activity info on server was successful, assign the coll obj on the client side
            this.config_info.coll_obj.meta.activity = arr[0];
            
            this.config_info.super_class.navSections(arr[1], arr[2], arr[3]);
        } else {
                      
            console.log('In ActivityInfo/saveDataCallback: errorOnServer');          
            this.config_info.super_class.exit(this.config_info.coll_obj);
        }
        
    },
    show: function(show/*boolean*/, css_class) {
        this.tab.setActive(show, css_class);        
    },
    showSectionInfo: function(container) {
        
//        var ul = LLDL.createEl('ul');
        var activity_info = 'No activities';
        if(this.config_info.coll_obj.meta.activity.length > 0) {
	        var act_titles = [];
	        var activities = this.config_info.coll_obj.meta.activity.split(',');
	        for(var i=0; i<activities.length; i++) {
	            var ttl = this.config_info.all_activity_map.get(activities[i]).title;
	            act_titles.push(ttl);
	//          ul.appendChild(LLDL.createEl('li','',ttl));
	        }
            activity_info = act_titles.join('<br/>');
        }
//        var div = LLDL.createEl('div'); div.appendChild(ul);
        var tr = LLDL.createEl('tr'); 
        var td_name = LLDL.createEl('td','','Activities',this.tab.name_class); 
        var td_value = LLDL.createInnerHTML('td','',activity_info,this.tab.value_class);
        tr.appendChild(td_name); tr.appendChild(td_value); 
//        td_value.appendChild(ul);
        container.appendChild(tr);
        
        return true;
    }    
     
};
LLDL.BuildCollection.Documents = function(container, config) {
    this.name = 'Documents';
    this.config_info = config;
    var o = {tab_id: this.name,
                   head_class: '',
                   body_class: 'tabbody',
                   tab_title: 'Content',
                   tab_body_name: this.name,
                   is_default: false};
    this.tab = new LLDL.BuildCollection.Tab(container, o);
    this.para_marker = "(\n\s*\n|\r\s*\r|\r\n\s*\r\n){1,}";//FF uses \n on all platforms; IE uses \r\n and \r on Windows and Macintosh respecitively.
    this.para_unmarker = "\n\n";
    this.doc_map = this.config_info.coll_obj.doc_map;
    this.levels_to_choose_from = this.config_info.coll_obj.choose_from_levels;
    this.getSectionBody(this.tab.body);
};
LLDL.BuildCollection.Documents.prototype = {
    generateNewDocID: function() {
    	function getDocID(doc_id_num/*int*/) {
            return 'D' + doc_id_num;
    	}
    	if(this.doc_map.size() === 0) {
    		return getDocID(0);
    	}
        var max_num = 0;
        var doc_id_arr = this.doc_map.keySet();
        for(var digit, doc_id, i=0; i<doc_id_arr.length; i++) {
            doc_id = doc_id_arr[i];
            var result = doc_id.match(/\d+$/);
            if(result != null){
                digit = parseInt(result[0]);
                if(digit > max_num) {
                    max_num = digit;
                }
            }
        }
        return getDocID(max_num+1);
    },
    getLevelInputCombo: function(container) {
    	var option_arr = [];
    	for(var level, selected, i=0; i<this.levels_to_choose_from.length; i++) {
    		level = this.levels_to_choose_from[i];
    		selected = (i===0)?true:false;
    		option_arr.push({value:level, title:level, selected:selected});
    	}
    	var dropdown_obj = new UI.SingleSelectionList(option_arr);
    	var combo_config = {width:435};
    	this.level_combo = new UI.ComboInputBox(container, combo_config, dropdown_obj);
    	this.level_combo.set(this.levels_to_choose_from[0]);//default value set to 'Beginner'
    	// this.level_combo.set(this.levels_to_choose_from[0]);//default value should set to 'type or select' which should disappear upon click (done in ComboInputBox)
    },
    queryDocContent: function(obj) {
    	var doc = obj.doc;
        LLDL.talk2server( {caller_obj: this,
                           callback_fn: this.queryDocContentCallback,
                           http_method: 'POST',
                           url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.RETRIEVE_DOC+
                                '&s1.collname='+this.config_info.coll_obj.meta.collname,
                           err_msg: 'Error occurred when deleting document',
                           passover_obj: obj,
                           postdata: 's1.Identifier='+doc.Identifier,
                           show_loading_panel: true,
                           loading_img_url: this.config_info.images_url+'blocking_loading.gif'
                          } );
    	
    },
    queryDocContentCallback: function(xml, obj) {   
    	var doc = obj.doc; //This doc object is defined in BeanObjects/FlaxDocument()
        var msg_el = xml.getElementsByTagName(LLDL.MESSAGE)[0];
        var type = msg_el.getAttribute(LLDL.TYPE);
        if(type !== "1") {            
            console.log('In Documents/queryDocContentCallback: errorOnServer');          
        }else {
        	/**
        	 * The flow of document content paragraph marking:
        	 * a. After the content is queried back from server: decode(to be <p> and </p>) -> unmark(to be '\n') ->set into doc editor -> call markPara
        	 * b. When collecting content off editor textarea: countPara -> markPara(to be <p> and </p>) -> countWords -> enconde -> send to server
        	 */
            var content_el = msg_el.getElementsByTagName('Content')[0];
            var contnt = LLDL.xml2string(content_el);
            contnt = contnt.substring(9, contnt.length-10).convertHTMLEntities();//trim off leading <Content> and trailing </Content>
            
            cont_arr = contnt.split('</div><div id="auxtext">');
            doc.text = cont_arr[0].substring(19);
            doc.auxtext = (cont_arr[1])?cont_arr[1].substring(0, cont_arr[1].length-6):'';

            var description_el = msg_el.getElementsByTagName('Description')[0];
            var img_el = LLDL.getNamedElement(description_el, 'Metadata', 'name', 'img'),
                aud_el = LLDL.getNamedElement(description_el, 'Metadata', 'name', 'aud'),
                vid_el = LLDL.getNamedElement(description_el, 'Metadata', 'name', 'vid');
            var imgs = LLDL.trim(LLDL.getNodeValue(img_el)),
                auds = LLDL.trim(LLDL.getNodeValue(aud_el)),
                vids = LLDL.trim(LLDL.getNodeValue(vid_el));
                if(LLDL.startsWith(imgs,',')) imgs = imgs.substring(1);
            // A JS lesson: when split() is applied to an empty string, split returns an array containing one empty string (array length is 1) rather than an empty array!
            var imglist=(imgs.length==0)?[]:imgs.split(','),
                audlist=(auds.length==0)?[]:auds.split(','),
                vidlist=(vids.length==0)?[]:vids.split(',');
            
/**
            //TODO: Before passing doc object to composeDocEditor, get img/aud/vid metadata info for initing AttachFileGadget
            var meta_list = LLDL.getNamedElements(description_el, 'Metadata', 'name', 'gsdlassocfile');
            var imglist=[], audlist=[], vidlist=[];
            var meta_value_arr = meta_list.map(function(meta_elem){
            	//meta_elem example: <Metadata name='x'>imgname_screen.gif:img</Metadata>
            	var meta_value = LLDL.trim(LLDL.getNodeValue(meta_elem));
            	var img_regexp = /:img$/, aud_regexp = /:aud$/, vid_regexp = /:vid$/;
            	if(img_regexp.test(meta_value)) {
            		var imgname = meta_value.split(':')[0];
            		imgname = imgname.replace(/_screen|_thumb/, '');//ends up with imgname.gif
            		if(imglist.indexOf(imgname)==-1) {
                        imglist.push(imgname);
            		}
            	} else if(aud_regexp.test(meta_value)) {
            		audlist.push(meta_value.split(':')[0]);
            	} else if(vid_regexp.test(meta_value)) {
            		vidlist.push(meta_value.split(':')[0]);
            	}
            });
            * */
            doc.img = imglist; doc.aud = audlist; doc.vid = vidlist;//these will eventually be used by AttachFileGadget
            this.composeDocEditor(obj.doc_editor_container, doc);//pass in a doc object instead of doc_id to restore the conditions of an existing document for editing
	        LLDL.setElementsStyle(obj.el_arr[0], obj.el_arr[1], obj.el_arr[2]);
            
	        this.tab.body.title.value=doc.Title;
	        this.tab.body.content.value=this.unmarkPara(doc.text);//replace <p></p> with '\n' and remove leading <p> and trailing </p>
	        this.tab.body.auxtext.value=this.unmarkPara(doc.auxtext);
	        this.level_combo.set(doc.Level);
	        //Call countParas() to display number of paragraphs for the doc (otherwise, the counting action has to be activated by mouseover or keyup event on the textarea element)
	        this.countParas(doc.text, 'text_area_notice_panel_id');//count using this.para_marker
	        this.countParas(doc.auxtext, 'auxtext_area_notice_panel_id');
            
            //Note: information about images/audios/videos are displayed by AttachFileGadget which were inited in composeDocEditor()
	    }        
    },
    getDocInfoHead: function() {
        var head = LLDL.createEl('tr','header_tr');
        head.appendChild(LLDL.createEl('th','','t','hidden_th'));
        head.appendChild(LLDL.createEl('th','','Title','doc_title_cell_class'));
        head.appendChild(LLDL.createEl('th','','Difficulty'));
        head.appendChild(LLDL.createEl('th','','Paragraphs'));
        head.appendChild(LLDL.createEl('th','','Words'));
        return head;
    },
    getSectionBody: function(container) {
    	
    	var add_doc_btn_body = LLDL.createEl('div','','','add_doc_btn_body');
        var add_doc_btn = LLDL.createButtonEl('add_doc_btn', 'Add a new document');
        add_doc_btn_body.appendChild(add_doc_btn);
        var copyright_notice = LLDL.createEl('div', '', lbb.copyright_notice, 'copyright_notice_class');
        add_doc_btn_body.appendChild(copyright_notice);
        container.appendChild(add_doc_btn_body);
    	
        var doc_list_body = LLDL.createEl('fieldset', '','', 'doc_list_fieldset');
        container.appendChild(doc_list_body);
        doc_list_body.appendChild(LLDL.createInnerHTML('legend', '', 'Document List'+LLDL.getHelpButtonInnerHTML(this.config_info, 
              this.config_info.classname+ ".document_list", this.config_info.lang), 'content_fieldset_legend'));        
        
        // document list
        var doc_list = LLDL.createEl('tbody');
        var wrapper = LLDL.createEl('table','','','doc_list');//this.getDocListContainer();
        wrapper.appendChild(doc_list);
        doc_list_body.appendChild(wrapper);

        // false means this is not for presenting build info on the build panel
        // This function call also appends the doc body in the dom tree
        this.getCollectionContent(doc_list, false);
        ////// New Document
        // These tow ids will be used by saveData() when user clicks Next button and might lose document in editing
        var new_doc_body_id = 'new_doc_body_id';
        var doc_editor_body_id = 'doc_editor_body_id';
        
        var new_doc_body = LLDL.createEl('div',new_doc_body_id,'','edit_doc_panel');
        container.appendChild(new_doc_body);
        LLDL.setElementsStyle([new_doc_body, add_doc_btn_body, doc_list_body], ['display', 'display', 'display'], ['none', '', '']);
        var doc_editor_body = LLDL.createEl('fieldset', doc_editor_body_id,'', 'doc_info_tabbody');
        new_doc_body.appendChild(doc_editor_body);            
                
        // Collection content buttons
        var submit_doc_btn = LLDL.createButtonEl('submit_doc_btn', 'Save');
        var cancel_doc_btn = LLDL.createButtonEl('cancel_doc_btn', 'Cancel');
        var doc_btn_body = LLDL.createEl('div','','','doc_btn_body');
        doc_btn_body.appendChild(submit_doc_btn);
        doc_btn_body.appendChild(cancel_doc_btn);
        new_doc_body.appendChild(doc_btn_body);
        
        // Attach event of deleting/editting document on doc list
        yue.on(doc_list, 'click', function(e) {
            var el = yue.getTarget(e);
            var docbtn = el.getAttribute('docbtn');
            if(!docbtn) { return true; }
            var arr = el.id.split('_');
            var doc_id = arr[0];
            var doc = this.doc_map.get(doc_id);
            if(arr[1] == 'del') {
                var obj = {doc:doc, doc_list_container:doc_list}; 
                this.deleteDocFromServer(obj);
            } else
            if(arr[1] == 'edit') {
                doc.show(false);//hide it
                this.setDocIdToButtons(doc_id, [doc_editor_body, submit_doc_btn, cancel_doc_btn]);
//                submit_doc_btn.doc_id = doc_id;
//                cancel_doc_btn.doc_id = doc_id;
                var obj = {doc:doc, doc_editor_container:doc_editor_body, doc_list_container:doc_list, 
                           el_arr:[[new_doc_body, add_doc_btn_body, doc_list_body], ['display', 'display', 'display'], ['', 'none', 'none']]};
                this.queryDocContent(obj);
            }
        }, this, true);
        // Attach event on buttons
        yue.on(add_doc_btn, 'click', function(e){
                        
            var doc_id = this.generateNewDocID();
            // set doc_id to: doc_editor_body (accessed in clearDocEditor()), 
            // submit_doc_btn/cancel_doc_btn (accessed when submit/cancel button is clicked)
            this.setDocIdToButtons(doc_id, [doc_editor_body, submit_doc_btn, cancel_doc_btn]);
//            submit_doc_btn.doc_id = doc_id;
//            cancel_doc_btn.doc_id = doc_id;
            LLDL.setElementsStyle([new_doc_body, add_doc_btn_body, doc_list_body], ['display', 'display', 'display'], ['', 'none', 'none']);
            this.composeDocEditor(doc_editor_body, doc_id);
            
        }, this, true);
        yue.on(submit_doc_btn, 'click', function(e) {
            var title = LLDL.trim(this.tab.body.title.value);
            var level = LLDL.trim(this.level_combo.get());
			var imglist = this.getMediaList(LLDL.IMAGE);
			var audlist = this.getMediaList(LLDL.AUDIO);
			var vidlist = this.getMediaList(LLDL.VIDEO);
	
            var text = LLDL.trim(this.tab.body.content.value);//the escaping for content is done below after markPara()
            var auxtext = LLDL.trim(this.tab.body.auxtext.value);//optional
            var missing_items = [];
            var invalid_level = (!level)? true:false;
            if(!title) { missing_items.push('Document title'); }
            if(invalid_level) { missing_items.push('Difficulty level'); }
            if(!text) { missing_items.push('Document content'); }
            if(!title || !text || invalid_level) { 
	            this.config_info.super_class.flax_alert.setHeader("<p></p><p>Please enter: </p><p>" + missing_items.join(' and ') + "</p><p></p>");
	            this.config_info.super_class.flax_alert.show();
                return false; 
            }else
            if(level.length > 20) { 
                this.config_info.super_class.flax_alert.setHeader("<p></p><p>Please choose difficulty level names</p><p>in 20 characters or less</p><p></p>");
                this.config_info.super_class.flax_alert.show();
                return false; 
            }else
            if(level.indexOf(",") !== -1) { 
                alert("_________________________________________________\n\n" +
                      "Commas are not allowed in difficulty level names.\n\n" +
                      "_________________________________________________\n\n");
                return false; 
            }
            var doc_id = submit_doc_btn.doc_id;

            var num_paras = this.countParas(text, 'text_area_notice_panel_id');
            var content = this.markPara(text, auxtext);//combine main text and auxiliary text together
            var num_words = this.countWords(text);
            // These will be used to store as metadata names in the doc.xml file, 
            // so we capitalize the first letter. Refer to BuildCollection.java on the server side.
            var doc_data = {Identifier:doc_id, Title:title, Content:content, Level:level, numParas:num_paras, 
                            numWords:num_words};//data that is sent to server
            //Always send to server the 'img', 'aud', and 'vid' parameters even if they are empty strings
            doc_data[LLDL.IMAGE] = imglist; 
            doc_data[LLDL.AUDIO] = audlist;
            doc_data[LLDL.VIDEO] = vidlist;
            if(this.doc_map.containsKey(doc_id) == false) {//A brand new doc
                var o = LLDL.cloneObject(doc_data);//data that is passed to callback handler
 	            var doc = new LLDL.Bean.FlaxDocument(this.config_info, o);
	            var action = 'add';
            } else {
            	//editting on an existing doc: we always send to server regardless doc data have been modified
                var doc = this.doc_map.get(doc_id);
                	doc.Title = title;
               	    doc.Level = level;
                    doc.Content = content;
                    doc.numParas = num_paras;
                    doc.numWords = num_words;
		            doc[LLDL.IMAGE] = imglist;
		            doc[LLDL.AUDIO] = audlist;
		            doc[LLDL.VIDEO] = vidlist;

            	var action = 'edit';
            }
            this.sendDocToServer(doc_list, doc_data, doc, action); 
                
            this.clearDocEditor();
        }, this, true);
        yue.on(cancel_doc_btn, 'click', function(e){
            
            var doc_id = cancel_doc_btn.doc_id;
            if(this.doc_map.containsKey(doc_id)) {//editting on an existing doc
                this.doc_map.get(doc_id).show(true);
            }
//            LLDL.setElementsStyle([new_doc_body, add_doc_btn_body, doc_list_body], ['display', 'display', 'display'], ['none', '', '']);
            this.clearDocEditor();
        }, this, true);
        
        // I really hate doing this, but we need to make the following accessible in this.clearDocEditor() and this.saveData()
        this.new_doc_body = new_doc_body;
        this.add_doc_btn_body = add_doc_btn_body;
        this.doc_list_body = doc_list_body;
        this.doc_editor_body = doc_editor_body;
    },
    setDocIdToButtons: function(doc_id, btn_arr) {
    	for(var i=0; i<btn_arr.length; i++) {
    		btn_arr[i].doc_id = doc_id;
    	}
    },
    clearDocEditor: function() {
        LLDL.setElementsStyle([this.new_doc_body, this.add_doc_btn_body, this.doc_list_body], ['display', 'display', 'display'], ['none', '', '']);
    	LLDL.clearup(this.doc_editor_body);
    	
        var doc_id = this.doc_editor_body.doc_id;
        if(this.doc_map.containsKey(doc_id)) {//editting on an existing doc
            this.doc_map.get(doc_id).show(true);
        }
        // Enable Previous/Next button
        this.config_info.super_class.disableNavButtons(false);
    },
    countParas: function(o, id) {//count the number of paragraphs
        var num_para = 0;
        var content = '';
        var notice_panel_id = id;

//        var content = LLDL.trim(this.tab.body.content.value);
        if(typeof o == 'string') {//text to parse
            content = o;
        } else if(typeof o == 'object'){//function invoked from event listener
        	var el = yue.getTarget(o);
        	if(el && el.tagName.toLowerCase() == 'textarea') {
        		content = el.value;
        		notice_panel_id = el.id + '_notice_panel_id';//Id defined in composeDocEditor
        	}
        }
        content = LLDL.trim(content);
        if(content.length > 0) {
	        var result = content.match(new RegExp(this.para_marker, "g"));
	        num_para = (result==null)? 1 : result.length+1;
        }
        
        var el = yud.get(notice_panel_id);
        if(num_para === 0){
            el.innerHTML = lbb.separate_paragraph_instruction;        	
        } else {
	        el.innerHTML = num_para.toString() + ' paragraph' + ((num_para==1)? '':'s');
        }
        return num_para;        
    },
    /**
     * This function is called after the content has been marked with '<p>' and '</p>'. 
     * So count the number of words of each paragraph after splitting using delimiter '</p><p>'.
     */
    countWords: function(content) {
    	var num_words = 0;
        var content = content || LLDL.trim(this.tab.body.content.value);
        var para_arr = content.split('</p><p>');
        for(var i=0; i<para_arr.length; i++) {
        	num_words += (para_arr[i].split(/\s+/)).length;
        }
        return num_words;
    },
//    getAllLevels: function(){
//        var num_doc = this.doc_map.size();
//        if(num_doc == 0) { return false; }
//        var levels = []; 
//        for(var doc, i=0; i<num_doc; i++) {
//          doc = this.doc_map.valSet()[i];
//          if(levels.indexOf(doc.Level) === -1) {
//              levels.push(doc.Level);
//          }
//        }
//        levels.sortString(true);//sort ascendingly
//        value = levels.join(',');
//        console.log('levels value='+value);
//        return value;
//    },
    composeDocEditor: function(container, doc) {
    	// Disable Previous/Next button
    	this.config_info.super_class.disableNavButtons(true);
    	
        LLDL.clearup(container);
        var editor_title = ((typeof doc == 'string')? 'Add':'Edit') + ' Document';
        container.appendChild(LLDL.createEl('legend', '', editor_title, 'legend_class'));
        // doc title
		var html = "<span class='label_text'>Document title" +
                LLDL.getHelpButtonInnerHTML(this.config_info, 
                this.config_info.classname+ ".document_title", this.config_info.lang)+
                "</span>" +
                "<input name='title' type='text' title='Document title' class='doc_title' />";
        container.appendChild(LLDL.createInnerHTML("div", "", html, "title_div_class"));
        yue.onAvailable(this.tab.body, function() {
            this.tab.body.title.focus();
        }, this, true);
        
        // doc difficulty level
        var level_el_body = LLDL.createEl('div', '', '', "title_div_class");
        var type_or_choose = "<span style='font-style:italic;font-weight:normal;font-size:0.8em;'>(type or choose)</span>";
        var level_el = LLDL.createInnerHTML("span", '', "Difficulty level "+type_or_choose+
              LLDL.getHelpButtonInnerHTML(this.config_info, 
              this.config_info.classname+ ".doc_difficulty_level", this.config_info.lang), 'label_text');
        level_el_body.appendChild(level_el);
        container.appendChild(level_el_body);
        this.getLevelInputCombo(level_el_body);
        var tabs_id = 'DDCSS-tabs-docs';
		html = "<div class='doc_content_label_container'>"+
			"<span class='label_text'>Document content" +//add the class 'float_left' here to fix IE8 
			LLDL.getHelpButtonInnerHTML(this.config_info, 
			this.config_info.classname+ ".document_content", this.config_info.lang)+ "</span>" +
                "<div id='"+tabs_id+"' class='DDCSS-tabs'>" +
                "<ul>" +
                "<li><a><span id='text-tab'>Text</span></a></li>" +
                "<li><a><span id='auxtext-tab'>Auxiliary Text</span></a></li>" +
                "<li><a><span id='"+LLDL.IMAGE+"-tab'>Images</span></a></li>" +
                "<li><a><span id='"+LLDL.AUDIO+"-tab'>Audio</span></a></li>" +
                "</ul>" +
                "</div>" +
            "<div id='text-tab-content' class='tab-content' style='display:none'>"+
				"<div id='text_area_notice_panel_id' class='num_para_notice_panel'>" + lbb.separate_paragraph_instruction +"</div>" +
			    "<textarea id='text_area' name='content' title='Copy and paste document text here' class='doc_content'></textarea>" +
			"</div>"+
            "<div id='auxtext-tab-content' class='tab-content' style='display:none'>"+
                "<div id='auxtext_area_notice_panel_id' class='num_para_notice_panel'>" + lbb.separate_paragraph_instruction +"</div>" +
                "<textarea id='auxtext_area' name='auxtext' title='Copy and paste text here' class='doc_content'></textarea>" +
            "</div>"+
            "<ul id='"+LLDL.IMAGE+"-tab-content' class='tab-content' style='display:none'></ul>"+
            "<ul id='"+LLDL.AUDIO+"-tab-content' class='tab-content' style='display:none'></ul>";
		container.appendChild(LLDL.createInnerHTML("div", "", html));
        
        //compose image/audio/video tabs (NOTE: the key words 'image', 'audio', and 'video' are also hard wired on the server side (BuildCollection.java)
        var o = {container_id:LLDL.IMAGE+'-tab-content',
                 media_type:LLDL.IMAGE,
                 doc:doc};
        this.imggadget = new LLDL.BuildCollection.AttachFileGadget(o, this.config_info);
        o = {    container_id:LLDL.AUDIO+'-tab-content',
                 media_type:LLDL.AUDIO,
                 doc:doc};
        this.audgadget = new LLDL.BuildCollection.AttachFileGadget(o, this.config_info);
        
        yue.on('text_area', 'mouseover', this.countParas, this, true);//Covers Right-click -> paste
        yue.on('text_area', 'keyup', this.countParas, this, true);// Covers copy and paste using Ctrl-c -> Ctrl-v
        yue.on('auxtext_area', 'mouseover', this.countParas, this, true);//Covers Right-click -> paste
        yue.on('auxtext_area', 'keyup', this.countParas, this, true);// Covers copy and paste using Ctrl-c -> Ctrl-v
        
        //Make the default tab 'text-tab' highlighted
        yud.setStyle('text-tab', 'color', '#FFFFFF');
        yud.setStyle('text-tab-content', 'display', '');
        
        yue.on(tabs_id, 'click', function(e) {
        	var el = yue.getTarget(e);console.log('el.id='+el.id);
        	if(['text-tab','auxtext-tab',LLDL.IMAGE+'-tab', LLDL.AUDIO+'-tab'].indexOf(el.id)==-1){
        		return;
        	}
        	var tabmap = new HashMap();
                tabmap.keyArray = ['text-tab', 'auxtext-tab', LLDL.IMAGE+'-tab', LLDL.AUDIO+'-tab'];
                tabmap.valArray = ['darkTurquoise', 'darkTurquoise', 'darkTurquoise', 'darkTurquoise'];
//                tabmap.valArray = ['#000000', '#000000', '#000000', '#000000'];
            var contentmap = new HashMap();
                contentmap.put('text-tab-content', 'none');
                contentmap.put('auxtext-tab-content', 'none');
                contentmap.put(LLDL.IMAGE+'-tab-content', 'none');
                contentmap.put(LLDL.AUDIO+'-tab-content', 'none');

            tabmap.put(el.id, '#FFFFFF');
            contentmap.put(el.id+'-content', '');
            console.log(contentmap.valSet());
        	for(var i=0; i<contentmap.size(); i++) {
                yud.setStyle(tabmap.keyArray[i], 'color', tabmap.valArray[i]);
        		yud.setStyle(contentmap.keySet()[i], 'display', contentmap.valSet()[i]);
        	}
        }, this, true);
    },

    deleteDocFromServer: function(obj) {
    	var doc = obj.doc;
        var msg = "\n" +
        "_______________________________________________\n\n" +
        "Are you sure you want to delete the\n\n" +
        "document: "+doc.Title+"\n\n" +
        "from the collection?\n\n" +
        "_______________________________________________\n\n" +
        "Click Ok to proceed or Cancel to abort\n";
        if(!window.confirm(msg)){return false;}
    	
        LLDL.talk2server( {caller_obj: this,
                           callback_fn: this.deleteDocFromServerCallback,
                           http_method: 'POST',
                           url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.SAVE_COLL+
                                '&s1.action=del&s1.step='+this.name+'&s1.collname='+this.config_info.coll_obj.meta.collname,
                           err_msg: 'Error occurred when deleting document',
                           passover_obj: obj,
                           postdata: 's1.Identifier='+doc.Identifier,
                           show_loading_panel: true,
                           loading_img_url: this.config_info.images_url+'blocking_loading.gif'
                          } );
    },
    deleteDocFromServerCallback: function(xml, obj) {
    	var doc = obj.doc;
        if(this.config_info.super_class.getOKResponse(xml)) {
            this.doc_map.remove(doc.Identifier);
            
            // We are not specifically deleting a particular document html node from the dom tree. 
            // We actually clear up the whole document list, and then recompose all existing documents.
            // See getCollectionContent() for how it's done.
            this.getCollectionContent(obj.doc_list_container, false);

        } else {
        	console.log('In Documents/deleteDocFromServerCallback: errorOnServer');          
        }
    },
    getMediaList: function(type) {
    	var obj = this[type+'gadget'];
    	if(!obj) {
    		return "";
    	}
    	var list = obj.uploads;//array
    	//strip off file extensions
    	for(var i=0; i<list.length; i++) {
    		var idx = list[i].indexOf('.');
    		if(idx!=-1) {
    			list[i] = list[i].substring(0, idx);
    		}
    	}
    	return list.join(',');
    },
    markPara: function(content, auxtext){
    	var auxtext_html = '';
    	auxtext = LLDL.trim(auxtext);
    	if(auxtext.length > 0) {
    		auxtext_html = '<div id="auxtext"><p>' + auxtext.replace(new RegExp(this.para_marker, 'g'), '</p><p>') + '</p></div>';
    	}
        var v = '<div id="maintext"><p>' + content.replace(new RegExp(this.para_marker, 'g'), '</p><p>') + '</p></div>' +
        		auxtext_html;
		return v;
    },
    unmarkPara: function(content) {//parse both main text and auxilary text
    	var cont = unescape(content);

        cont = LLDL.trim(cont);
        cont = cont.replace(/<\/div>/g, '');
        cont = cont.replace(/<div\s+id="[maintext|auxtext]">/g, '');
        cont = cont.replace(/<\/?w>/g, '');//remove all <w> and </w> tags (if any)
        
        //filter all gloss tags
        cont = cont.replace(/<(\w{4})\s+gloss=[^>]{2,}>([^<]*)<\/\1>/g, '$2');//replace <span gloss='xxx'>hello</span> with hello
        cont = cont.replace(/<\/p>\s*<p>/g, this.para_unmarker);
        cont = cont.replace(/<\/?p>/g, '');
        return cont;
    },
    // Send doc data to server for adding/editing purposes (flagged by action)
	sendDocToServer: function(container, doc_data/**{}*/, doc/***/, action) {
        var docinfo = [];    
        
        docinfo.push('s1.Language='+this.config_info.coll_obj.meta.lang);
        for(var p in doc_data) {
        	docinfo.push('s1.'+p+'='+encodeURIComponent(doc_data[p]));
        }
//console.log('in sendDocToServer, docinfo='+docinfo);
        LLDL.talk2server( {caller_obj: this,
                           callback_fn: this.sendDocToServerCallback,
                           http_method: 'POST',
                           url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.SAVE_COLL+
                                '&s1.action='+action+'&s1.step='+this.name+'&s1.collname='+this.config_info.coll_obj.meta.collname,
                           err_msg: 'Error occurred when saving document',
                           passover_obj: [container, doc],
                           postdata: docinfo.join('&'),
                           show_loading_panel: true,
                           loading_img_url: this.config_info.images_url+'blocking_loading.gif'
                          } );
	},
	sendDocToServerCallback: function(xml, arr) {
		var container = arr[0], doc = arr[1];
        if(this.config_info.super_class.getOKResponse(xml)) {
            if(this.doc_map.containsKey(doc.Identifier) == false) {//A brand new doc
                this.doc_map.put(doc.Identifier, doc);
                this.getCollectionContent(container, false);
                if(this.levels_to_choose_from.indexOf(doc.Level) === -1){
                    this.levels_to_choose_from.unshift(doc.Level);
                }
            } else {//editting on an existing doc
                doc.show(true);
            }            
        } else {
        	alert("_______________________\n\n" +
        		  "The FLAX server seems to \n\n" +
        		  "be experiencing problems.\n\n" +
        		  "Please report this to your\n\n" +
        		  "system administrator.\n" +
        		  "_______________________");
        	this.config_info.super_class.exit(this.config_info.coll_obj);	  
        	console.log('In Documents/saveDocToServerCallback: errorOnServer');                                
        }
		
	},
	loseDocumentWarning: function() {
        var msg = "\n" +
        "_______________________________________________\n\n" +
        "A document is currently being edited.\n\n" +
        "If you proceed, any modifications will be lost.\n\n" +
        "_______________________________________________\n\n" +
        "Discard your changes?\n";
        if(!window.confirm(msg)){return false;}
        return true;
	},
    saveData: function(next_step_index, prev_btn, next_btn) {
        var proceed = false;    	
    	//Check if there is a document is currently being edited in the editor panel. If so, display warning.
    	var display = yud.getStyle(this.new_doc_body, 'display');
    	if(display === 'none') {
    		proceed = true;
    	} else {
    		proceed = this.loseDocumentWarning();
    	}
    	if(proceed) {
    		this.clearDocEditor();
            this.config_info.super_class.navSections(next_step_index, prev_btn, next_btn);
    	}
    },
    show: function(show/*boolean*/, css_class) {
        this.tab.setActive(show, css_class);        
    },
    getCollectionContent: function(container, for_final_section_info_display){
    	LLDL.clearup(container);
    	
        if(this.doc_map.size()>0) {            
            var doc_obj_arr = this.doc_map.valSet().slice();
            doc_obj_arr.sort(function(doc_obj_a, doc_obj_b) {
                return doc_obj_a.Level > doc_obj_b.Level;
            });

            container.appendChild(this.getDocInfoHead());
            for(var doc, doc_obj, doc_body, i=0; i<this.doc_map.size(); i++) {
                doc_obj = doc_obj_arr[i];
                if(for_final_section_info_display) {
                    doc_body = doc_obj.getDocDisplayBody((i+1)+'. ');
                } else {
                	doc_body = doc_obj.getDocBody();//use getDocBody() function instead of the body property to make sure dom tree is being refreshed
                }                
                container.appendChild(doc_body);
            }
            return true;
        } else {
        	var tr=LLDL.createEl('tr'); var td = LLDL.createEl('td','no_doc_notice_id',"There are no documents in this collection. You're not able to build this collection.");
        	tr.appendChild(td);
			container.appendChild(tr);
            return false;
        }        
    },
    showSectionInfo: function(container) {
        //
        var tr = LLDL.createEl('tr'); 
        var td_name = LLDL.createEl('td','','Content',this.tab.name_class); 
        var td_value = LLDL.createEl('td','','',this.tab.value_class);
        tr.appendChild(td_name); tr.appendChild(td_value); 
        container.appendChild(tr);        
        var content_container = LLDL.createEl('div','','','doc_content_container');
        td_value.appendChild(content_container);
        var doc_list = LLDL.createEl('tbody'); var table = LLDL.createEl('table','','','doc_list');
        table.appendChild(doc_list);
        content_container.appendChild(table);

        this.getCollectionContent(doc_list, true);
        return (this.doc_map.size()>0);
        
//        if(this.doc_map.size()>0) {            
////            var doc_list = LLDL.createEl('ol');
////            for(var doc, i=0; i<this.doc_map.size(); i++) {
////                doc = LLDL.createEl('li','',this.doc_map.valSet()[i].Title);
////                doc_list.appendChild(doc);
////            }
//            var doc_obj_arr = this.doc_map.valSet().slice();
//            doc_obj_arr.sort(function(doc_obj_a, doc_obj_b) {
//            	return doc_obj_a.Level - doc_obj_b.Level;
//            });
//
//            var doc_list = LLDL.createEl('table','','','doc_list'); content_container.appendChild(doc_list);
//            doc_list.appendChild(this.getDocInfoHead());
////            var tr = LLDL.createEl('tr'); doc_list.appendChild(tr);
////	        var td1 = LLDL.createEl('td'), td2 = LLDL.createEl('td', '', 'Title','doc_title_cell_class'), 
////	        td3 = LLDL.createEl('td', '', 'Difficulty level'), td4 = LLDL.createEl('td', '', 'Paragraphs'), td5 = LLDL.createEl('td', '', 'Words');
////	        tr.appendChild(td1);tr.appendChild(td2);tr.appendChild(td3);tr.appendChild(td4);tr.appendChild(td5);
//            for(var doc, i=0; i<this.doc_map.size(); i++) {
////            for(var doc, i=0; i<15;i++) {
//            	var doc_obj = doc_obj_arr[i];
////            	var ttl = doc_obj.Title + ' Title Title Title Title Title Title Title Title Title Title Title Title Title Title Title Title Title Title Title';
////                doc = LLDL.createEl('tr');
//                doc_list.appendChild(doc_obj.getDocDisplayBody(i+1));
////	            td1 = LLDL.createEl('td','',''+(i+1)+'.'), td2 = LLDL.createEl('td', '', ttl,'doc_title_cell_class'), 
////	            td3 = LLDL.createEl('td', '', doc_obj.Level), td4 = LLDL.createEl('td', '', doc_obj.numParas), 
////	            td5 = LLDL.createEl('td', '', doc_obj.numWords);
////	            doc.appendChild(td1);doc.appendChild(td2);doc.appendChild(td3);doc.appendChild(td4);doc.appendChild(td5);
//                
//            }
//            return true;
//        } else {
//            var no_content_notice = LLDL.createInnerHTML('div', '','<b style="color:red">Collection content is required to build a collection<b>', 'empty_doc_notice');
//            content_container.appendChild(no_content_notice);
//            return false;
//        }        
    } 
}
LLDL.BuildCollection.AttachFileGadget = function(o, config) {
    this.config_info = config;
    this.container = yud.get(o.container_id);
    this.file_type = o.media_type;
    this.file_index = -1;
    this.uploads = [];//Used for preventing duplicate files from being uploaded more once
    
    if(typeof o.doc=='string') {
    	this.doc = null;
    	this.doc_id = o.doc;
    } else {
    	this.doc = o.doc;
    	this.doc_id = o.doc.Identifier;
    	var uploaded_file_names = this.doc[this.file_type];
        //This is to edit an existing document which might contain some media files uploaded previously        
        for(var i=0; i<uploaded_file_names.length; i++) {
        	var n = uploaded_file_names[i];
        	if(n.length>0){
                this.doBody(n);
                this.uploads.push(uploaded_file_names[i]);
        	}        	
        }
    }
    this.doBody('');
}
LLDL.BuildCollection.AttachFileGadget.prototype = {
//	presentExistingMediaFiles: function() {
//		//This is to edit an existing document which might contain some media files uploaded previously
////		var files = LLDL.parseMediaFileNames(this.doc.Content, this.file_type);
////		if(files == null) return;//no existing files
////		this.uploaded_file_names = files.join(',');//init existing files names to check if duplicated files are uploaded again
//		
//		for(var i=0; i<this.length; i++) {
//			this.doBody(files[i]);
//		}
//	},
	doBody: function(filename) {
		//Indexing the elements is used to compose element ids for the purpose of uploading more than one file
		this.file_index = this.file_index + 1;
		
        var attach_file_container = this.file_type + this.file_index + '_attach_file_container', 
        file_input = this.file_type + this.file_index + '_file_input', 
        upload_status_container = this.file_type + this.file_index + '_upload_status_container', 
        upload_status = this.file_type + this.file_index + '_upload_status',
        upload_form = this.file_type + this.file_index + '_upload_form',
        attach_result_container = this.file_type + this.file_index + '_attach_result_container', 
        attach_result = this.file_type + this.file_index + '_attach_result', 
        remove_file = this.file_type + this.file_index + '_remove_file',
        rename_file = this.file_type + this.file_index + '_rename_file',
        delete_status_container = this.file_type + this.file_index + '_delete_status_container', 
        delete_status = this.file_type + this.file_index + '_delete_status';
        
        //Object passed to event handlers below
        var obj = {attach_file_container:attach_file_container,
                 upload_status_container:upload_status_container,
                 upload_status:upload_status,
                 upload_form:upload_form,
                 delete_status_container:delete_status_container,
                 delete_status:delete_status,
                 attach_result_container:attach_result_container,
                 attach_result:attach_result,
                 file_input : file_input,
                 doc_id : this.doc_id }
                 
        html = "<img src='"+this.config_info.images_url+"clip.png'/>";
        var styles = "";
        if(!filename) {
        //if filename is not available this is to construct a brand new body, we need to compose upload elements
        //We also need to hide the 'delete_status_container' and 'attach_result_container'
        	styles = "style='display:none;'";
        	html += 
                "<span id='"+attach_file_container+"' class='attach_file_container'>" + this.getAttachFileHTML(obj) + "</span>"+
                "<span id='"+upload_status_container+"' class='upload_file_container' style='display:none'>"+
                    "<img src='"+this.config_info.images_url+"loading.gif'/>" +
                    "Uploading <span id='"+upload_status+"' class='upload_status'></span>"+
                "</span>";
        }
        html += "<span id='"+delete_status_container+"' class='delete_status_container' style='display:none;'>"+
                    "<img src='"+this.config_info.images_url+"loading.gif'/>" +
                    "Deleting <span id='"+delete_status+"' class='delete_status'></span>"+
                "</span>"+
                "<span id='"+attach_result_container+"' class='attach_result_container' "+ styles + ">" + 
                    "<span id='"+attach_result+"' class='attach_result'>"+filename+"</span>" + 
                    "<span id='"+remove_file+"' class='remove_file'>Remove</span>"+
//                    "<span id='"+rename_file+"' class='remove_file'>Rename</span>"+	
                "</span>";
        var bd = LLDL.createInnerHTML('li','', html,'attach_file_gadget_body_class');
        this.container.appendChild(bd);
        
        yue.on(attach_result_container, 'click', function(e) {
        	var el = yue.getTarget(e);
        	if(!el) return;
        	if(!el.id || el.tagName.toLowerCase() != 'span') return;
        	
            var filename = LLDL.getNodeValue(yud.get(attach_result));
            if(!filename) return;
            
            if(el.id == remove_file) {
		        bd.parentNode.removeChild(bd);
		        this.uploads = this.uploads.remove(filename);
            }
//            if(el.id == rename_file) {
//            	var new_file_name = 'new_file_name';
//				var form_str ="<label for='new_coll_name'>Please enter a new media file name</label>" +
//						"<input type='text' name='"+new_file_name+"' value='' />";
//				LLDLpromptData("Rename file", form_str, handleOK, function(){}, this);
//				var handleOK = function(data) {
//					var new_name = LLDL.trim(data[new_file_name]);
//					if(!new_name) return;
//					yud.get(o.attach_result).innerHTML = new_name;
//					this.uploads = this.uploads.remove(filename);
//					
//					var url = this.config_info.ajax_server_url+
//					var postdata = ''
//			        yuc.asyncRequest('POST', url, null, postdata);
//			        var obj = {
//			            http_method: 'POST',
//			            url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.TEST_GLOSS+
//			            '&s1.collname='+this.config_info.coll_obj.meta.collname+'&s1.glossurl='+body.glossurl,
//			            postdata:body
//			        };
//			        LLDL.talk2server( obj );
//				};
//            }
        }, this, true);
		
		this.body = bd;
	},
    //This function is used by both composing the interface for the first time and after removing an already uploaded file and then resuming the interface again
    getAttachFileHTML: function(o) {
        var str =  'Unknown file type', text='', tooltip='';
        if(this.file_type == LLDL.IMAGE) {
        	text = 'Upload an image'; tooltip = 'Add an illustrative image';
        } else if(this.file_type == LLDL.AUDIO) {
            text = 'Upload an audio file'; tooltip = 'Add an audio file';        	
        } else if(this.file_type == LLDL.VIDEO) {
        	text = 'Upload a video file'; tooltip = 'Add a video file';
        }
        str = "<form title='"+tooltip+"' id='"+o.upload_form+"'>" +
        	  "<span class='upload_file'>"+ text + "</span>"+ 
               //the name 'uploadfile' here is not important since there is only one file to upload each time; 
               // otherwise this name would be used on the server side to differentiate each uploaded file                               
               "<input id='"+o.file_input+"' class='file_input' value='_n_' size=1 type='file' name='uploadfile'/>" +
               "</form>";

        yue.on(o.file_input, 'change', function(e) {
            var el = yue.getTarget(e);
            var full_path = el.value;
            var filename = this.validateFile(full_path);
            if(!filename) { console.log('filename is null: '+filename); return; }
            o.filename = filename;
            yud.get(o.file_input).name = filename;//for the purposes of uploading more than one file to server
            this.uploadFile(o);
        }, this, true);
        return str;               
    },
    /**
    * Return string file_name; or false if file is not of required types
    */
    validateFile: function(full_path) {
    	if(full_path.indexOf(",")!=-1) {
            var msg = 'Commas (,) are not allowed in the file name.';
            this.failToUpload(msg);
            return false;
    	}
        var idx = full_path.lastIndexOf('.');
        if(idx == -1) return;
        var ft = full_path.substring(idx+1);
        var pattern='', media_types = '';
        if(this.file_type == LLDL.IMAGE) {
        	pattern = /(jpg|jpeg|gif|bmp)/;///(jpe?g|png|gif|bmp|xbm|tif?f|jpf|jpx|jp2|jpc|j2k|pnm|pgx)/;
        	media_types = 'jpg, jpeg, gif, bmp';//'jpg, jpeg, png, gif, bmp, xbm, tif, tiff, jpf, jpx, jp2, jpc, j2k, pnm, pgx';
        } else if(this.file_type == LLDL.AUDIO) {
        	pattern = /mp3/;///(mp3|wav|dct|ogg|gsm|flac|au|aiff|vox)/;
        	media_types = 'mp3';//'mp3, wav, dct, ogg, gsm, flac, au, aiff, vox';
        } else if(this.file_type == LLDL.VIDEO) {
        	pattern = /(mp4|flv)/;
        	media_types = 'mp4, flv';
        }
        if(!(ft.match(pattern))) {
        	var type_name = (this.file_type==LLDL.IMAGE)?'images' : 
        	((this.file_type==LLDL.AUDIO)?'audios': 'videos');
            var msg = 'You have chosen to upload the file: '+ full_path + '<br />' +
            'The allowed file formats for '+ type_name +' are: <br />' + media_types +'<br />';
            this.failToUpload(msg);
            return false;
        }
        var real_file_name = full_path;
        //In IE8, full_path is like: C:\Document and Settings\xxx\name.jpg, where in FF, it's just name.jpg
        var last_backslash_pos = full_path.lastIndexOf("\\");
        if(last_backslash_pos != -1){
            real_file_name = full_path.substring(last_backslash_pos+1);
        }
        if(real_file_name.match(/\w+\s+\w+/)) {
            var msg = 'White space characters in file names are likely to<br/>' +
            		'cause errors when files are processed on the server.<br/>' +
            		'Please change the name and upload again';
            this.failToUpload(msg);
            return false;
        }
        //check to see if this file name has already been in the list
        var duplicate = this.uploads.indexOf(real_file_name) != -1;
        if(duplicate) {
            this.failToUpload('The file '+real_file_name+' has already been uploaded.');
            return false;
        }
        return real_file_name;
    },
    uploadFile: function(o) {
        yud.setStyle(o.attach_file_container, 'display', 'none');
        yud.get(o.upload_status).innerHTML = o.filename;
        yud.setStyle(o.upload_status_container, 'display', '');
        var obj = {caller_obj: this,
                   callback_fn: this.uploadFileCallback,//this.pauseOnUpload,
                   url: this.config_info.ajax_server_url+'&media='+ this.file_type +//parameter 'media' is picked up in FlaxServlet.java/doPost() and BuildCollection.java/uploadFile()
                        '&mediafilename='+o.filename+'&s=BuildCollection&Identifier='+o.doc_id+
                        '&collname='+this.config_info.coll_obj.meta.collname,
                   passover_obj: o,
                   form: yud.get(o.upload_form)
                  };
        LLDL.upload2server( obj );
    },
/** 
    pauseOnUpload: function(xml, o) {
        //Pause some time for demo purposes (when client and server are on the same machine)
        var scope = this;
        window.setTimeout(function() { 
                scope.uploadFileCallback(xml, o); 
                }, 2000);
    },
    pauseOnDelete: function(xml, o) {
        //Pause some time for demo purposes (when client and server are on the same machine)
        var scope = this;
        window.setTimeout(function() { 
                scope.deleteFileCallback(xml, o); 
                }, 2000);
    },
*/ 
    uploadFileCallback: function(xml, o) {
        var filename = o.filename;
        var suceed = true;
        var msg_el = xml.getElementsByTagName(LLDL.MESSAGE)[0];
        if(!msg_el) { 
            console.log( 'message element not found. most likely exception occurred on server'); 
        } else {
            var type = msg_el.getAttribute(LLDL.TYPE);
            if (type !== "1"){
            	console.log(msg_el.firstChild.nodeValue);
            	suceed = false;
            } 
        }
            
        if(suceed) {//uploading suceeded
            yud.setStyle(o.upload_status_container, 'display', 'none');
            yud.get(o.attach_result).innerHTML = filename;      
            yud.setStyle(o.attach_result_container, 'display', '');
            this.uploads.push(filename);
            this.doBody('');
        } else {        
            this.failToUpload('File size exceeds 10MB limitation.');
        }//end of else
    },
    failToUpload: function(err_msg) {
        this.body.parentNode.removeChild(this.body);
        this.doBody('');
        
        this.config_info.super_class.flax_alert.setHeader("<p></p><p>" + err_msg + "</p><p></p>");
        this.config_info.super_class.flax_alert.show();
    }
}
LLDL.BuildCollection.Build = function(container, config) {
    this.name = 'Build';
    this.config_info = config;
    var o = {tab_id: this.name,
                   head_class: '',
                   body_class: 'tabbody',
                   tab_title: 'Build',
                   tab_body_name: this.name,
                   is_default: false};
    this.tab = new LLDL.BuildCollection.Tab(container, o);
    this.getSectionBody();
};
LLDL.BuildCollection.Build.prototype = {
    getSectionBody: function() {
        var div = LLDL.createEl('div','','', "build_info_body");
        this.tab.body.appendChild(div);
        div.appendChild(LLDL.createEl('div','','Collection Information','build_info_header'));
        var table = LLDL.createEl('table','','','build_info'); 
        this.info_body = LLDL.createEl('tbody'); 
        table.appendChild(this.info_body);
        div.appendChild(table);
        
        var enable_gloss_body = LLDL.createEl('div','','','enable_gloss_body');
//        enable_gloss_body.innerHTML = "<img src='"+this.config_info.images_url+"loading.gif'/>Testing Gloss Generation Engine ...";
//        yud.insertBefore(enable_gloss_body, 'confirm_build');
        this.tab.body.appendChild(enable_gloss_body);
        this.testGloss(enable_gloss_body);
        
        var confirm_build = LLDL.createEl('div','confirm_build','','confirm_build_body');
        confirm_build.appendChild(LLDL.createEl('span', '','Build collection?'));
        confirm_build.appendChild(LLDL.getHelpButtonEl(this.config_info, 
               this.config_info.classname+ ".build", this.config_info.lang));
        this.OK_btn = LLDL.createButtonEl('buildcol', 'OK');
        confirm_build.appendChild(this.OK_btn);
        this.tab.body.appendChild(confirm_build);

        yue.on(this.OK_btn, 'click', this.buildcol, this, true);
    },
    testGloss: function(body) {
    	if(!window.navigator.onLine){
//    		body.innerHTML = "<img src='"+this.config_info.images_url + "warn16_1.gif'/>" + 'Your computer is disconnected';
    		return;
    	}
        body.glossurl = 'http://flax.nzdl.org';
        var obj = {
            caller_obj: this,
            callback_fn: this.testGlossCallback,
            http_method: 'GET',
            url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.TEST_GLOSS+
            '&s1.collname='+this.config_info.coll_obj.meta.collname+'&s1.glossurl='+body.glossurl,
            err_msg: 'Error occurred when testing gloss',
            passover_obj:body
        };
        LLDL.talk2server( obj );
    	
//    	this.hasGloss = true;
//    	yug.script('http://flax.nzdl.org/FlaxReader/reader/CreateReaderService?l1=es&text=hello&callback=LLDL.BuildCollection.Build.testGlossCallback', {
//    		//Note: the callback method specified as parameter in the url will get executed before onSuccess
//    		onSuccess: function(obj) {
//    			this.doGlossBody(obj.data.container);
//    		},
//    		onFailure: function() {
//    			
//    		},
//    		scope: this,
//    		data: {container: body}
//    	});
    },
    testGlossCallback: function(xml, body) {
    	var hasGloss = true;
        var msg = xml.getElementsByTagName('message')[0];
        if(msg) {
           var type = msg.getAttribute('type');
           if(type == '-1') {
//               body.innerHTML = "<img src='"+this.config_info.images_url + "warn16_1.gif'/>" + 'Gloss Engine Not Operating';
               hasGloss = false
           }
        } else {
//            body.innerHTML = "<img src='"+this.config_info.images_url + "warn16_1.gif'/>" + 'Internet Unavailable';
            hasGloss = false;
        }
        if(hasGloss) {
	        LLDL.clearup(body);
	        this.gloss_obj = new UI.CheckBox({name:'gloss', value:'gloss', checked:false});
	        body.appendChild(this.gloss_obj.body);
	        body.appendChild(LLDL.createEl('span', '','Enable glosses in '));
	        var option_arr = [{value:'es',title:'Spanish',selected:true},
	                          {value:'en',title:'English',selected:false},
                              {value:'fr',title:'French',selected:false},
                              {value:'de',title:'German',selected:false},
                              {value:'it',title:'Italian',selected:false},
                              {value:'pl',title:'Polish',selected:false},
                              {value:'pt',title:'Portuguese',selected:false},
                              {value:'ru',title:'Russian',selected:false}
	                         ];
	        this.gloss_lang_obj = new UI.SingleSelectionList(option_arr);
	        this.gloss_lang_obj.glossurl = body.glossurl;
	        body.appendChild(this.gloss_lang_obj.body);
	        body.appendChild(LLDL.getHelpButtonEl(this.config_info, 
	               this.config_info.classname+ ".enable_gloss", this.config_info.lang));
        }
        LLDL.setButtonDisable(this.OK_btn, false);
        
    },
    saveData: function(next_step_index, prev_btn, next_btn) {    
        this.config_info.super_class.navSections(next_step_index, prev_btn, next_btn);
    },
    showSectionInfo: function() {   return true;    },
    show: function(show/*boolean*/, css_class) {
        this.tab.setActive(show, css_class);        
        if(!show) { return false; }
        
        LLDL.clearup(this.info_body);

//        LLDL.setButtonDisable(this.OK_btn, false);
        var sections = this.config_info.super_class.build_section_object_map.valSet();
        for(var i=0; i<sections.length; i++) {
            var sec = sections[i];
//            if(sec.name === this.name) { continue; }
//            if(sec.name === 'ActivityInfo') { continue; }
//            if(sec.name === 'CollectionInfo') { continue; }
            if(sec.showSectionInfo(this.info_body) === false) {
            	LLDL.setButtonDisable(this.OK_btn, true);
            	this.OK_btn.setAttribute('title', 'Building is disabled because of warning in section: '+sec.name);
            }
        }
    },
    buildcol: function(e) {

        var postdata = [];
        postdata.push('s1.lang='+this.config_info.coll_obj.meta.lang);
        var built_in_acts = this.config_info.coll_obj.meta.activity;
        postdata.push('s1.creator='+this.config_info.coll_obj.meta.creator);
        var enable_collo = this.config_info.coll_obj.collocation.get('collocation').value;
        postdata.push('s1.collocation='+enable_collo);
        if(enable_collo === '1') {
        	var data = this.config_info.coll_obj.collocation.valSet();
        	for(var i=0; i<data.length; i++) {
        		var n = data[i].name, v = data[i].value;
        		if(n=='collocation') {
        			continue;
        		}else if(n=='activity' && v.length>0) {
	                built_in_acts += ','+ v;
	            } else {
	            	postdata.push('s1.'+n+'='+v);
	            }
        	}
        }

        postdata.push('s1.activity='+built_in_acts);

        postdata.push('s1.mdlsiteid='+this.config_info.mdlsiteid);

        if(this.gloss_obj && this.gloss_obj.get()) {
        	postdata.push('s1.glosslang='+this.gloss_lang_obj.get());
            postdata.push('s1.glosslangtitle='+this.gloss_lang_obj.getTitle());
            postdata.push('s1.glossurl='+this.gloss_lang_obj.glossurl);
        }
        console.log('buildcol postdata='+postdata.join('&'));
        LLDL.talk2server( {caller_obj: this,
                           callback_fn: this.buildcolCallback,
                           http_method: 'POST',
                           url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.BUILD_COLL+
                                '&s1.step='+this.name+'&s1.collname='+this.config_info.coll_obj.meta.collname,
                           err_msg: 'Error occurred when building collection',
                           passover_obj: this.config_info.coll_obj,
                           postdata: postdata.join('&'),
                           show_loading_panel: true,
                           loading_img_url: this.config_info.images_url+'blocking_loading.gif'
                          } );
    },
    buildcolCallback: function(xml, coll_obj) {
    	var build_obj = this.config_info.super_class;
        if(build_obj.getOKResponse(xml)) {
            coll_obj.setCategory(lbb.c3);
            this.config_info.list_collections_obj.initDD(build_obj, coll_obj);
            coll_obj.refresh();
            coll_obj.showBuildNotice(true);
            //In case it's the first collection in the block, remove the "none" flag
            this.config_info.list_collections_obj.refreshBlock(this.config_info.private_block);
            
	        // Reset corresponding place holders and be ready for next collection building
            LLDL.setElementsStyle([build_obj.collection_list_body, build_obj.build_button_body, build_obj.build_body], ['display', 'display', 'display'], ['', '', 'none']);
	        build_obj.setCollInEdit(null);
        } else {
            coll_obj.setCategory(lbb.c4);
            this.config_info.list_collections_obj.removeDD(coll_obj.meta.collname);
            coll_obj.refresh();
            coll_obj.showBuildNotice(false);
        	console.log('In Build/buildcolCallback: errorOnServer');          
        }
    }
    
};
LLDL.BuildCollection.Collocations = function(container, config) {
    this.name = 'Collocations';
    this.config_info = config;
//    this.collometa_bnc = 'bnc', this.collometa_webdata = 'webdata', 
//    this.collometa_db = 'db', this.collometa_type = 'type', this.collometa_activity = 'activity';
    var o = {tab_id: this.name,
                   head_class: '',
                   body_class: 'tabbody',
                   tab_title: 'Collocations',
                   tab_body_name: this.name,
                   is_default: false};
    this.tab = new LLDL.BuildCollection.Tab(container, o);
    this.getSectionBody();
};
LLDL.BuildCollection.Collocations.prototype = {
	getSectionBody: function() {
        var collo_body = LLDL.createEl('fieldset','','', "collo_body");
        this.tab.body.appendChild(collo_body);
        collo_body.appendChild(LLDL.createEl('legend','', 'Extract collocations from documents'));
        
        // do the whole yes/no switch on/off radio buttons
        var radio_container = LLDL.createEl('h4'); 
        collo_body.appendChild(radio_container);
        this.collo_radio_obj = new UI.RadioButton(radio_container, [{name:'collocation',value:'1',title:'Yes',checked:true, newline:false},
                                                                  {name:'collocation',value:'0',title:'No',checked:false, newline:false}]);
        collo_body.appendChild(this.collo_radio_obj.body);
        
        var collotype_body_id = 'collo_types_container';
        var html = '<hr/><table><tbody>' + 
                this.getColloTypeInterfaceBody(collotype_body_id) + 
                '</tbody></table>' +
                /**
                '<hr/><ul class="collo_list"><li id="collo_notepad">' +
                '<img src="'+this.config_info.images_url+'collocation_notepad.png"/>' +
//                '<div class="collo_notepad_screenshot">' +
//        		'<div class="panel_header"><span class="left">Collocation Notepad</span>' +
//        		'<img src="'+this.config_info.images_url+'delete.gif"/></div>' +
//        		'<div class="body"></div>' +
//        		'<div class="footer"></div>' +
//        		'</div>' +
        		'</li>' +
                '<li id="collo_feature"><table><tbody>' +
        		this.getUseMetaInterface(this.config_info.coll_obj.collocation.get('db')) + 
        		this.getUseMetaInterface(this.config_info.coll_obj.collocation.get('bnc')) + 
                this.getUseMetaInterface(this.config_info.coll_obj.collocation.get('webdata')) + 
        		'</tbody></table></li></ul><hr/>' +*/
        		'';	
        var collo_option_body = LLDL.createInnerHTML('div', '', html, 'collo_option_body');	
        collo_body.appendChild(collo_option_body);  
        
        // The value of default_activity_list is determined in flax-resources/modelcol/collectionConfig.xml (model collection config file)
        var model_metadata_list = this.config_info.model_collection_config_xml.getElementsByTagName('metadataList')[0];
        var activity_metadata = LLDL.getNamedElement(model_metadata_list, 'meta', 'name', 'activity');
        var default_activity_list = activity_metadata.getAttribute('value');
        // Activities the user had chosen last time the collection was being built (or all activity types if new collection)
        this.collo_activity_obj = new LLDL.BuildCollection.ActivityList('collo_activity_body');
        var user_chosen_activity_list = this.config_info.coll_obj.collocation.get('activity').value;
        collo_option_body.appendChild(this.collo_activity_obj.getBody(default_activity_list, user_chosen_activity_list, this.config_info.all_activity_map));	
        
        this.queryColloTypes(collotype_body_id);
        //Restore options of last time (or of a new collection defaults), except collo types
        this.setSectionOptions(collo_option_body);
/**        
        yue.on('collo_types_container', 'click', function(e){
          var el = yue.getTarget(e);
          if(el.tagName.toLowerCase() !== 'input') { return; }
          var checks = this.getColloTypes();
          if(checks.length < 1) {
          	var msg = '________________________\n\n' +
          			  ' At least one collocation\n' +
          			  ' type must be selected!\n\n' +
          			  '________________________';
              alert(msg);
              el.checked = 'checked';
          }
        }, this, true);*/
        yue.on(radio_container, 'click', function() {
            var v = this.collo_radio_obj.get();
            this.showColloOptionBody(collo_option_body, v);
        }, this, true);

	},
	getColloTypeInterfaceBody: function(collotype_body_id) {
		var collo_type_html = '<tr><td class="collo_left">' + 
		this.config_info.coll_obj.collocation.get('type').displayName +
                '</td><td class="collo_right" id="'+collotype_body_id+'">' +
//                '<table class="collo_types"><tbody id="'+o.body_id+'">' +
//                '<img src="'+this.config_info.images_url+'loading.gif" /> Loading collocation patterns ...' +
//                '</tbody></table>' +
                '</td></tr>';
        return collo_type_html;
	},
	getColloTypeHTML: function(collo_type_el, existing_collo_type_arr) {
		var type = collo_type_el.getAttribute('type');
		var checked = (existing_collo_type_arr.indexOf(type)==-1)?'':'checked';
		var display_name = LLDL.getNamedElement(collo_type_el, 'item', 'name', 'display_name').firstChild.data;
		var sample = LLDL.getNamedElement(collo_type_el, 'item', 'name', 'sample').firstChild.data;
		var html = '<li><input type="checkbox" name="'+type+'" '+checked+'/><span class="collo_type_displayname">'+display_name+'</span>' +
				'(<span class="collo_type_sample">'+sample+'</span>)</li>';
		return html;		
	},
	/*getUseMetaInterface: function(o) {
		var image_src = this.config_info.images_url + o.icon;
		var helpfile = this.config_info.help_server_url + o.helpFile;
		var id = 'collo'+o.name;
	    var img = "<img height='17' width='17' src='"+ image_src+ "' id='"+id+"'/>";
	    yue.on(id, "click", function(e) {
	        var url = helpfile;
	        var options = 'menubar=no,location=yes,scrollbars=yes,resizable=no,width=450,height=250';
	        var bReplace = false;
	        var wobj = LLDL.openpopup(url, o.helpFile, options, bReplace);
	    }, this, true);
        var meta_html = '<tr>' +
        		'<td class="collo_feature_name"><span>'+img+'</span>'+o.displayName+'</td><td class="collo_feature_value">';
        for(var i=0; i<o.items.length; i++) {
        	var v = '<input type="radio" name="'+o.name+'" value="'+o.items[i].value+'"/>' + 
        	        o.items[i].title;
            meta_html += v;
        }
        meta_html += '</td></tr>';
        return meta_html;
	},*/
    queryColloTypes: function(collotype_body_id){ 
        LLDL.talk2server( {caller_obj: this,
                           callback_fn: this.queryColloTypesCallback,
                           http_method: 'GET',
                           url: this.config_info.ajax_server_url+'&s=FlaxCollocationDescribe',
                           err_msg: 'Error occurred when querying collocation types',
                           passover_obj: collotype_body_id,
                           postdata: null,
                           show_loading_panel: false
                          } );
                          
    },
    queryColloTypesCallback: function(collo_types_xml, collotype_body_id) {
    	var bd = yud.get(collotype_body_id);
    	bd.innerHTML = '';

    	// Existing collo type values:
    	// For a new collection: empty
    	// For an existing collection: verb;VVG,RV]noun;NON,NN
    	var existing_collo_type_arr = [], obj = this.config_info.coll_obj.collocation.get('type');
    	if(obj.value && obj.value.length>0) {
    		existing_collo_type_arr = this.parseColloPatterns(obj);
    	} 

    	var collo_groups = collo_types_xml.getElementsByTagName('colloGroup');
    	this.collo_type_groups = [];//used when reading collo type values and organise them into groups
    	this.collo_type_tab_ids = [];
    	this.collo_type_tabcontent_ids = [];
    	//The head of the tabs
    	var tabs_id = 'DDCSS-tabs-collo';
    	var html = '<div id="'+tabs_id+'" class="DDCSS-tabs"><ul>';
    	for(var cg, name, display_name, i=0; i<collo_groups.length; i++) {
    		cg = collo_groups[i];
    		name = cg.getAttribute('name');
    		var tab_id = name + '-tab';
    		this.collo_type_groups.push(name);
    		this.collo_type_tab_ids.push(tab_id);
    		this.collo_type_tabcontent_ids.push(tab_id+'-content');
    		display_name = name.charAt(0).toUpperCase() + name.substring(1);
    		html += '<li><a><span id="'+tab_id+'">' + display_name +'</span></a></li>';
    	}
    	html += '</ul></div>';
    	//Check All/None buttons
		html += '<div class="all_none_btns_panel">' +
				'<span id="check_all" title="Check all">All</span>/' +
				'<span id="check_none" title="Uncheck all">None</span>' +
				'</div>';

    	//Firstly, work out the number of children of the largest group
    	var max_num_children = 0;
    	for(var i=0; i<this.collo_type_tabcontent_ids.length; i++) {
    		var num_collo_type = collo_groups[i].getElementsByTagName('collo').length;
    		if(num_collo_type > max_num_children) max_num_children = num_collo_type;
    	}
    	//The content part of the tabs
    	for(var i=0; i<this.collo_type_tabcontent_ids.length; i++) {
    		var collo_type_group_list = collo_groups[i].getElementsByTagName('collo');
            var type_html = '';
    		for(var k=0; k<max_num_children; k++) {
    			if(k < collo_type_group_list.length) {
    				type_html += this.getColloTypeHTML(collo_type_group_list[k], existing_collo_type_arr);
    			}else {
    				//append dummy (hidden) elements to make the interface not jump when clicking thru tabs
    				type_html += '<li style="visibility:hidden;">.</li>';
    			}
    		}
    		html += '<div id="'+this.collo_type_tabcontent_ids[i]+'" class="collo_type_contents" style="display:none">' +
    				'<ul>'+type_html+'</ul></div>';    		
    	}
    	bd.innerHTML = html;
        //Make the first tab active
        yud.setStyle(yud.get(this.collo_type_tab_ids[0]), 'color', '#FFFFFF');
        yud.setStyle(yud.get(this.collo_type_tabcontent_ids[0]), 'display', '');
		this.active_tab_content_id = this.collo_type_tabcontent_ids[0];//needed by All/None button clicking
		
        yue.on(tabs_id, 'click', function(e) {
            var el = yue.getTarget(e);//console.log('el.id='+el.id);
            if(this.collo_type_tab_ids.indexOf(el.id)==-1){
                return;
            }
            var tabmap = new HashMap();
                tabmap.keyArray = this.collo_type_tab_ids;
                tabmap.valArray = ['darkTurquoise', 'darkTurquoise', 'darkTurquoise', 'darkTurquoise'];
            var contentmap = new HashMap();
                contentmap.keyArray = this.collo_type_tabcontent_ids;
                contentmap.valArray = ['none','none','none','none'];

            tabmap.put(el.id, '#FFFFFF');
            contentmap.put(el.id+'-content', 'block');
            this.active_tab_content_id = el.id+'-content';
            for(var i=0; i<contentmap.size(); i++) {
                yud.setStyle(tabmap.keyArray[i], 'color', tabmap.valArray[i]);
                yud.setStyle(contentmap.keySet()[i], 'display', contentmap.valSet()[i]);
            }
        }, this, true);
        yue.on('check_all', 'click', function() {
        	LLDL.checkAll(this.active_tab_content_id, true);
        }, this, true);
        yue.on('check_none', 'click', function() {
        	LLDL.checkAll(this.active_tab_content_id, false);
        }, this, true);
    	
    },
	showColloOptionBody: function(collo_option_body, v) {
        if(v==='1'){
            yud.setStyle(collo_option_body, 'visibility', 'visible');
        } else {
            yud.setStyle(collo_option_body, 'visibility', 'hidden');
        }
	},
	setSectionOptions: function(collo_option_body) {
		// Restore the interface based on this.config_info.coll_obj.meta.collocation (in case the user is editing an existing collection)
		var enable_collo = this.config_info.coll_obj.collocation.get('collocation').value;//typeof==string; value=1 or 0
		this.collo_radio_obj.set(enable_collo);

		this.showColloOptionBody(collo_option_body, enable_collo);
/**
	    this.setRadioValue(this.tab.body['db'], this.config_info.coll_obj.collocation.get('db'));
	    this.setRadioValue(this.tab.body['bnc'], this.config_info.coll_obj.collocation.get('bnc'));
        this.setRadioValue(this.tab.body['webdata'], this.config_info.coll_obj.collocation.get('webdata'));
*/
	},
//	setColloTypes: function(types) {
//	    var me = this;
//        var type_group = yud.getElementsBy(function(el) { return el.name==me.collometa_type;
//                                           }, "input", yud.get('collo_types_container'));  
//
//        if(types === 'all') {
//            var checkall = yud.get('collo_types_checkall');    
//        	checkall.checked = 'checked';
//	        for(var i=0; i<type_group.length; type_group[i].checked = "checked", i++);
//        } else if(types === 'none') {
//            var checkall = yud.get('collo_types_checkall');    
//        	checkall.checked = null;
//        	for(var i=0; i<type_group.length; type_group[i].checked = null, i++);
//        } else {//types = vn,nn,vv ...
//            var arr = types.split(/,/);
//        	for(var n, i=0; i<type_group.length; i++) {
//        		type_group[i].checked = (arr.indexOf(type_group[i].value) !== -1)? "checked" : null;
//        	}
//        }
//	},
    getColloTypes: function() {
    	var group_values = [];
    	for(var i=0; i<this.collo_type_tabcontent_ids.length; i++) {
    		var types = yud.getElementsBy(function(el) { return el.checked; }, "input", yud.get(this.collo_type_tabcontent_ids[i]));
    		var arr = [];
    		for(var k=0; k<types.length; arr.push(types[k].name), k++);
    		if(arr.length>0) {
	    		group_values.push(this.collo_type_groups[i]+LLDL.param_nv_separator+arr.join(','));
    		}
    	}
    	return group_values.join(LLDL.param_arg_separator);
//        var type_group = yud.getElementsBy(function(el) { return el.checked; }, "input", yud.get('collo_types_container'));  
//        var arr = [];
//        for(var i=0; i<type_group.length; arr.push(type_group[i].name), i++);       
//        return arr.join(',');
    },
/**    setRadioValue: function(radio_node_list, collo_type_meta) {
    	if(!radio_node_list) return;
        for(var i=0; i<radio_node_list.length; i++) {
            if(radio_node_list[i].value === collo_type_meta.value) {
                radio_node_list[i].checked = 'checked';
            } else {
            	radio_node_list[i].checked = null;
            }
        }
    },
	getRadioValue: function(radio_node_list) {
		if(!radio_node_list) return null;
        for(var i=0; i<radio_node_list.length; i++) {
			if(radio_node_list[i].checked) {
				return radio_node_list[i].value;
			}
		}
		console.log('no radio buttons were checked, weird!')
		return null;
	},*/
    getData: function(arr) {   
        var value_arr = arr || [];
        var ext_collo = this.collo_radio_obj.get();
//        var bnc = this.getRadioValue(this.tab.body['bnc']);
//        var webdata = this.getRadioValue(this.tab.body['webdata']);
//        var db = this.getRadioValue(this.tab.body['db']);
        var collo_types = this.getColloTypes();
        var collo_activities = this.collo_activity_obj.getList();

        value_arr.push('s1.collocation='+ext_collo);
        if(ext_collo === '1'){
//	        value_arr.push('s1.bnc=' + bnc);
//	        value_arr.push('s1.webdata=' + webdata);
//	        value_arr.push('s1.db=' + db);
	        value_arr.push('s1.type=' + collo_types);
	        value_arr.push('s1.activity=' + this.collo_activity_obj.getList());        
        }
        return value_arr.join('&');
    },
    //Function is called when previous/next is clicked
    saveData: function(next_step_index, prev_btn, next_btn) {
        
    	var data =  this.getData();
//        if(data === 0) {
//            this.config_info.super_class.navSections(next_step_index, prev_btn, next_btn);
//            return true;//no change has been made; no need to send it to server
//        }
        
        var passover_o = [data, next_step_index, prev_btn, next_btn];
        LLDL.talk2server( {caller_obj: this,
                           callback_fn: this.saveDataCallback,
                           http_method: 'POST',
                           url: this.config_info.ajax_server_url+'&s=BuildCollection&s1.service='+LLDL.services.SAVE_COLL+
                                '&s1.step='+this.name+'&s1.collname='+this.config_info.coll_obj.meta.collname,
                           err_msg: 'Error occurred when saving collection: '+this.name,
                           passover_obj: passover_o,
                           postdata: data,
                           show_loading_panel: true,
                           loading_img_url: this.config_info.images_url+'blocking_loading.gif'
                          } );
        
        this.config_info.super_class.navSections(next_step_index, prev_btn, next_btn);
        return true;
    },
    saveDataCallback: function(xml, arr) {
        if(this.config_info.super_class.getOKResponse(xml)) {
            // Saving collocation info on server was successful, assign the coll obj on the client side
            var info = arr[0].replace(/s1./g, '');
            info = info.split('&');
            for(var nv, name, value, i=0; i<info.length; i++) {
            	nv = info[i].split('=');
           		this.config_info.coll_obj.collocation.get(nv[0]).value = nv[1];
            }
            
            this.config_info.super_class.navSections(arr[1], arr[2], arr[3]);
        } else {
            console.log('In CollocationInfo/saveDataCallback: errorOnServer');          
            this.config_info.super_class.exit(this.config_info.coll_obj);
        }        
    },
    show: function(show/*boolean*/, css_class) {
        this.tab.setActive(show, css_class);
//        if(show) {
//        	this.queryColloTypes(this.collometa_type_obj);
//        }
    },
    parseColloPatterns: function(obj) {
    	var o = obj || this.config_info.coll_obj.collocation.get('type');
    	var patterns = [];
		var group_arr = o.value.split(LLDL.param_arg_separator);
		for(var i=0; i<group_arr.length; i++) {
			var arr = group_arr[i].split(LLDL.param_nv_separator);
			if(arr[0]&&arr[1]) {
				var a = arr[1].split(',');
	    		patterns = patterns.concat(a);
			}
		}
		return patterns;
    },
	showSectionInfo: function(container) {
        //
        var collo_info = "";
        if(this.config_info.coll_obj.collocation.get('collocation').value !== '1') {
        	collo_info = "Collocations not enabled";
        } else {
        	var data = this.config_info.coll_obj.collocation.valSet();
        	for(var i=0; i<data.length; i++) {
        		var d = data[i];
        		if(d.name=='collocation') continue;
        		
        		collo_info += "<div>"+d.displayName+": ";
        		
        		if(d.name=='type') {
        			var arr = this.parseColloPatterns();
        			collo_info += arr.length+" patterns selected";
        		} else if(d.name=='activity') {
        			var act_titles = 'None selected';
        			if(d.value.length>0) {
        				act_titles = [];
        				var arr = d.value.split(',');
        				for(var k=0; k<arr.length; k++) {
        					act_titles.push(this.config_info.all_activity_map.get(arr[k]).title);
        				}
        			}
        			collo_info += act_titles.join(',');
        		} else {
	        		collo_info += ((d.value=='1')?'Yes':'No');
        		}
        		collo_info += "</div>";
        	}
        }
        var tr = LLDL.createEl('tr'); 
        var td_name = LLDL.createEl('td','','Collocations',this.tab.name_class); 
        var td_value = LLDL.createInnerHTML('td','',collo_info,this.tab.value_class);
        tr.appendChild(td_name); tr.appendChild(td_value); 
        container.appendChild(tr);
        
        return true;
    }	
}
LLDL.BuildCollection.CollectionImage = function(container, config) {
    this.name = 'CollectionImage';
    this.config_info = config;
    var o = {tab_id: this.name,
                   head_class: '',
                   body_class: 'tabbody',
                   tab_title: 'Images',
                   tab_body_name: this.name,
                   is_default: false};
    this.tab = new LLDL.BuildCollection.Tab(container, o);
    this.getSectionBody();
};
LLDL.BuildCollection.CollectionImage.prototype = {
    getSectionBody: function() {
        var div = LLDL.createEl('div','','Upload image files here ...', "title_div_class");
        this.tab.body.appendChild(div);
        
    },
    saveData: function() {
        
    },
    show: function(show/*boolean*/, css_class) {
        this.tab.setActive(show, css_class);        
    }
    
};
LLDL.BuildCollection.ActivityList = function(body_id) {
    this.body = LLDL.createEl('ul', body_id, '', 'activity_list_ul');
}
LLDL.BuildCollection.ActivityList.prototype = {
    getBody: function(activity_options/*comma seperated string*/, checked_activities/*comma seperated string*/, activity_obj_map) {
        var checked_list = checked_activities.split(/,/);
        var option_list = activity_options.split(/,/);
        var act_obj, activity, option, li_class, title_el, info_el, html, act_name, checked;
        for(var i=0; i<option_list.length; i++) {
            option = option_list[i];
//            p_class = li_class.replace(/Box/g, '');
            act_name = option_list[i];
            checked = (checked_list.indexOf(act_name) !== -1)? 'checked':'';
            act_obj = activity_obj_map.get(act_name);
            li_class = act_obj.color_theme;
            activity = LLDL.createEl('li', '', '', 'languageBox');
            html = "<span class='left0'><input type='checkbox' name='activity' " +
                    "value='"+act_name+"' "+checked+ " /></span>" +
                    "<span class='left0 bold'>"+act_obj.title+"</span>";
            title_el = LLDL.createInnerHTML('p', '', html, li_class);
            activity.appendChild(title_el);
            
            info_el = LLDL.createInnerHTML('div', '', act_obj.description, 'activity_description');
            activity.appendChild(info_el);
            this.body.appendChild(activity);
        }
        return this.body;
    },
    // Returns a list of checked activities (comma seperated)
    getList: function() {
        var checkbox_group = yud.getElementsBy(function(el){ return el.checked; }, "input", this.body);   
        if(!checkbox_group || checkbox_group.length===0) {
            return '';
        }
        var value_arr = [];
        for(var i=0; i<checkbox_group.length; i++) {
            value_arr.push(checkbox_group[i].value);
        }
        //if value_arr is an empty array, value_arr.join(",") results in "" (empty string [typeof which is string])
        //same result can be given by using either value_arr.toString() or value_arr.join() with no arguments
        return value_arr.join(',');     
    },
    // Set interface
    setList: function(checked_activities/*comma seperated string*/) {
    	var arr = checked_activities.split(/,/);
        yud.getElementsBy(function(el){ return true; }, "input", this.body, function(el) {
        	el.checked = (arr.indexOf(el.value) === -1)? null : 'checked';
        });
    }
}

