// namespace
var cart = {
	COLOR_HIGHLIGHT_ON_ADD : [2, 255, 53],
	COLOR_HIGHLIGHT_ON_DELETE : [255, 204, 204],
	
	ANIMATION_TIME_REGULAR : 1000,
	ANIMATION_TIME_FAST : 5,
	CAP_NUMBER_OF_SEQUENCES : 100
};

cart.Cart = function() {

    var rootTagId;
    var seqs = new cart.SelectedSequences();

    var acc = null;
    var toolId = 0;
    
    this.init = function(tagId) {
        rootTagId = tagId;
        var rootTag = dojo.byId(tagId);
	    if(!rootTag) { return; }
	    
        specifyCustomAccordionFunctions();

        // remove all child nodes.
        while(rootTag.hasChildNodes()) {
            rootTag.removeChild(rootTag.firstChild);
        }

        for(var seqId in seqs.getAll()) {
            var seq = seqs.get(seqId);

            addNode(rootTag, seq, false);
            
            // run callback functions to sync.
            for(var i = 0; i < seq.callbacks.length; i++) {
                //seq.callbacks[i]();
                ;
            }
        }

        updateLabel();
    }

	// add a selected sequence to the list.
	this.add = function(seqId, accession, molecule, callbackToSync, runEffect) {
	    var rootTag = dojo.byId(rootTagId);
	    if(!rootTag) { return; }

        var seq = new cart.Sequence(seqId, accession, molecule, callbackToSync);
        
        // check seq cap.
        if(!seqs.hasSame(seq)) {
        	if(seqs.getNum() >= cart.CAP_NUMBER_OF_SEQUENCES) {
        		throw new Error("The number of selected sequences cannot exceed "
        				+ cart.CAP_NUMBER_OF_SEQUENCES + ".");
        	}
        }
        
        if(seqs.hasSame(seq)) {
            seqs.update(seq);
            // notify a user there is already a same seq.
            for(var i = 0; i < rootTag.childNodes.length; i++) {
            	if(rootTag.childNodes[i].getAttribute("pid") == seqId) {
             		openAccordionPane(rootTag.childNodes[i]);
            		if(runEffect) {
            			effectOnAdd(rootTag.childNodes[i], cart.ANIMATION_TIME_REGULAR);
            		}
            		return;
            	}
            }
        } else {
            seqs.add(seq);
        }
        
	    addNode(rootTag, seq, runEffect);

        updateLabel();
	}

	var thisCart = this;

    var addNode = function(rootTag, seq, runEffect) {
	    var div = document.createElement("div");
	    var accDiv = document.createElement("div");
	    var clearDiv = document.createElement("div");
	    
	    accDiv.className = 'cartAccession';
	    accDiv.innerHTML = "<a href='javascript: void(0);' onclick='mySequenceManager.loadContent(\"/leftcontent/editSequence.php?id=" + seq.id + "\");'>" + seq.accession + "</a>";
	    clearDiv.setAttribute("style", "clear: both;");
	    
	    div.className = "selectedSequence";
        div.setAttribute("pid", seq.id);
        div.deleting = false; // a flag to avoid deleting the same div.
	    div.appendChild(accDiv);
	    
	    // add 'remove(unselect)' icon.
	    var img = document.createElement("img");
	    img.setAttribute("src", "/images/cancel_16.gif");
	    img.setAttribute("alt", "unselect");
	    img.className = 'cartDelete';
	    img.onclick = function() {
	    	hideddrivetip();
	    	thisCart.remove(seq.id, true);
	    }
	    img.onmouseover = function() {
	    	ddrivetip("Remove");
	    }
	    img.onmouseout = function() {
	    	hideddrivetip();
	    }
	    div.appendChild(img);
		div.appendChild(clearDiv);
		rootTag.appendChild(div);
        
		openAccordionPane(div);
		
        if(runEffect) {
            effectOnAdd(div, cart.ANIMATION_TIME_REGULAR);
        } else {
        	effectOnAdd(div, cart.ANIMATION_TIME_FAST);
        }
    }

	// delete a selected sequence from the list.
	this.remove = function(seqId, effect) {	
	    var rootTag = dojo.byId(rootTagId);
	    if(!rootTag) { return; }

        seq = seqs.get(seqId);
        seqs.remove(seqId);

	    for(var i = 0; i < rootTag.childNodes.length; i++) {
	        var childNode = rootTag.childNodes[i];
	        if(childNode.getAttribute("pid") != seqId
                    || childNode.deleting) {
	            continue;
	        }
	        
            // set a flag to avoid deleting the same div tag.
            childNode.deleting = true;

	        openAccordionPane(childNode);
	        
	        if(effect) {
	        	effectOnDelete(childNode);
	        } else {
	        	rootTag.removeChild(childNode);
	        }
	        break;
	    }

        updateLabel();
	}

	var effectOnAdd = function(obj, animationTime) {
		if(!obj.onEffect) {
			obj.onEffect = true;
		    dojo.lfx.combine (
		        dojo.lfx.fadeShow(obj, animationTime),
	            dojo.lfx.highlight(obj, cart.COLOR_HIGHLIGHT_ON_ADD, animationTime, null,
	            		function() { obj.onEffect = false; }
	            )
		    ).play();
		}
	}
	
	var effectOnDelete = function(obj, animationTime) {
	    dojo.lfx.combine (
	        dojo.lfx.highlight(obj, cart.COLOR_HIGHLIGHT_ON_DELETE, animationTime),
	        dojo.lfx.fadeHide(obj, animationTime, null, function() {
	            obj.parentNode.removeChild(obj);
	        })
	    ).play();
	}
	
	var openAccordionPane = function(obj) {
		if(dojo.widget.byId('selectedSequencesPane').selected) {
			if(!dojo.widget.byId('selectedSequencesPane').opening) {
				var parent = obj.parentNode;
				var parentBottom = parent.scrollTop + dojo.html.getBorderBox(parent).height;
				var nodeBottom = obj.offsetTop + dojo.html.getMarginBox(obj).height;
				if(parentBottom < nodeBottom || parent.scrollTop > obj.offsetTop){
					dojo.html.scrollIntoView(obj);
				}
			}
		} else {
			dojo.widget.byId('accordionMain').selectChildCustom(
				dojo.widget.byId('selectedSequencesPane')
			);
		}
	}

    var updateLabel = function() {
        var num = seqs.getNum();
	    var paneTagId = "selectedSequencesPane";
	
        var pane = dojo.widget.byId(paneTagId);
        var label = "Selected Sequences ("+num+")";
        pane.setLabel(label);
	}
    
    this.getSelectedSequences = function() {
    	return seqs.getAll();
    }
    
    this.getPids = function() {
    	var pids = seqs.getAllPids();
    	return pids.join(",");
    }
    
    this.hasSeqs = function() {
    	if(seqs.getNum() > 0) {
    		return true;
    	} else {
    		return false;
    	}
    }
    
    // for accordion container.
    var specifyCustomAccordionFunctions = function() {
        dojo.widget.AccordionPane.prototype.opening = false;

    	dojo.widget.AccordionContainer.prototype.selectChildCustom = function(page) {
			dojo.lang.forEach(this.children, function(child){
				child.setSelected(child==page);
			});
			// slide each pane that needs to be moved
			var y = 0;
			var anims = [];
			dojo.lang.forEach(this.children, function(child, idx){
				if(child.domNode.style.top != (y+"px")){
					child.opening = true;
					var callback = function() { child.opening = false; };
					anims.push(dojo.lfx.html.slideTo(child.domNode, {top: y, left: 0}, this.duration, null, callback));
				}
				y += child.selected ? dojo.html.getBorderBox(child.domNode).height : child.getLabelHeight();
			});
			dojo.lfx.combine(anims).play();
    	}
    }
    
    this.getAcc = function() {
    	return acc;
    }
    this.setAcc = function(_acc) {
    	acc = _acc;
    }
    
    this.clear = function() {
    	seqs.clear();
    	this.init(rootTagId);
    }
    
	// for backward compatibility.
    this.emulateMySequenceForm = function(formName) {
		var myform = createElementWithName("form", "emulatedMySequenceForm");
		myform.setAttribute("style", "display:none;");
		var inputAcc = createElementWithName("input", "acc");
		inputAcc.setAttribute("value", this.getAcc());
		myform.appendChild(inputAcc);
		
		var inputPageId = createElementWithName("input", "pageid");
		var pageid = getSessionVariable("last_page");
		inputPageId.setAttribute("value", pageid);
		myform.appendChild(inputPageId);
		
		//something like <input id="pid_35520" type="checkbox" accession="rs1805007" seqpid="35520" value="35520" name="pid[]"/>
		var selectedSeqs = this.getSelectedSequences();
		for(var seqpid in selectedSeqs) {
			var inputSeq = createElementWithName("input", "pid[]");
			inputSeq.setAttribute("seqpid", seqpid);
			inputSeq.setAttribute("value", seqpid);
			inputSeq.setAttribute("accession", selectedSeqs[seqpid].accession);
			myform.appendChild(inputSeq);
		}
		return myform;
    }
    
    this.importAndAdd = function(id, seqNo, type, effect) {
    	// Check if there is already a same accession number.
    	// Do check when 'accession' is given.
    	/*
    	if(accession) {
	    	var storedSeqs = seqs.getAll();
	    	for(var storedSeqId in storedSeqs) {
	    		if(storedSeqs[storedSeqId].accession != accession) {
	    			continue;
	    		}
    			if(confirm("Accession '" + accession + "' is already imported.\n"
    					+ "Do you want to import it again?")) {
    				break;
    			} else {
    				return;
    			}
	    	}
	    }
	    */
    	
       	if(seqs.getNum() >= cart.CAP_NUMBER_OF_SEQUENCES) {
       		throw new Error("The number of selected sequences cannot exceed "
       				+ cart.CAP_NUMBER_OF_SEQUENCES + "." + seqId);
        }
        
    	// set ajax url and parameters.
    	var url;
    	var content;
    	if(type) {
    		if(type.toLowerCase() == "friend") {
    			url = "/ajax/importFriendSequence.php";
    			content = { "pid": id };
    		} else if(type.toLowerCase() == "digest") {
    			url = "/ajax/importDigestSequence.php";
    			content = { "id": id, "seqno": seqNo };
    		} else {
    			return null;
    		}
    	} else {
    		return null;
    	}
    	
    	// import a friend/extracted sequence.
    	var result = null;
		dojo.io.bind({
	        url: url,
	        handler: function(type, data, event) {
	            if (type == 'error') {
	                //alert('Error getting the rating!');
	            } else {
	                //alert(data.comment);
	                result = data;
	            }
	        },
	        mimetype: 'text/json',
	        method: 'get',
	        sync: true,
	        error: function(type, error){ dojo.debug(error.message); },
	        timeoutSeconds: 60,
	        content: content
	    });
	    
	    if(result == null || result.error) {
	    	return null;
	    }
	    
	    this.add(result.pid, result.accession, result.molecule, null, effect);
    }
    
    this.getToolId = function() {
    	return toolId;
    }
    
    this.setToolId = function(_toolId) {
    	toolId = _toolId;
    }
}

cart.SelectedSequences = function() {
	
	var seqs = {};
	
	this.add = function(seq) {
        if(seqs[seq.id]) {
            seqs[seq.id].update(seq);
        } else {
            seqs[seq.id] = seq;
        }
	}

    this.get = function(id) {
        return seqs[id];
    }

    this.getAll = function() {
        return seqs;
    }
	
	this.getAllPids = function() {
    	var objs = this.getAll();
    	var pids = new Array();
    	for (key in objs) {
    		pids.push(key);
    	}
    	return pids;
    }
    
    this.update = function(seq) {
        this.add(seq);
    }

    this.remove = function(id) {
        delete seqs[id];
    }

    this.clear = function() {
        seqs = {};
    }

	this.hasSame = function(seq) {
        if(seqs[seq.id]) {
            return true;
        } else {
            return false;
        }
	}

    this.getNum = function() {
        //alert(seqs.length);
        //return seqs.length;
        var count = 0;
        for(var key in seqs) {
            count++;
        }
        return count;
    }
}

cart.Sequence = function(id, accession, molecule, callbackToSync) {
	this.id = id;
	this.accession = accession;
	this.molecule = molecule;

    // tag IDs associated with the sequence.
    this.callbacks = [callbackToSync];
    
    this.update = function(seq) {
        if(this.id != seq.id)
            return;

        this.accession = seq.accession;
        for(var i = 0; i < seq.callbacks.length; i++) {
            this.callbacks.push(seq.callbacks[i]);
        }
    }
}

// use only one cart.
cart.cart = new cart.Cart();
getCart = function() {
	return cart.cart;
}

