 if(!console)var console={log:function(){}};
 
(function($) {
  $.randomize = function(arr) {
     for(var j, x, i = arr.length; i; j = parseInt(Math.random() * i), x = arr[--i], arr[i] = arr[j], arr[j] = x);
     return arr;
  };
})($);

(function( $ ) {
	$.fn.dragAndDrop = function(params) {
		if(!params)params={};
		var defaults={
			data:"data",
			componentstyle:{position:"relative"},
			choicestyle:{color:"#444444"},
			labelstyle:{color:"#877b72"},
			feedback:window["feedback_modal"],
			maxattempts:2
		};
		
		if($(this).find("#reveal").length)defaults.maxattempts=10000;
		//this is still overridable from the params input
		
		//dereference params
		params=$.extend(true,{},defaults,params);
		var data=window[params.data];
		if(!params.maxcorrect){
			params.maxcorrect=(data.droppableareas.length>data.choices.length)?data.choices.length:data.droppableareas.length;
		}
		if(typeof(params.feedback)==="string"){
			if(typeof(window["feedback_"+params.feedback])==="function"){
				params.feedback=window["feedback_"+params.feedback];
			}else if(typeof(window[params.feedback])==="function"){
				params.feedback=window[params.feedback];
			}else{
				console.log("unrecognised feedback function "+params.feedback);
			}
		}
		return this.each(function() {
			var hook, hooks, me=this;
			this.hooks=function(name){
				if(this[name])return this[name];else return this[name]={};
			}
			this.hook=function(){
				for (var f in this[arguments[0]]){
					this[arguments[0]][f](arguments)
				}
			}
			
			// Get choices using data from data.js
			var choices=[];
			if($.isArray(data.choices))
			{
				$.each(data.choices, function(key, item) {
				choice_num = key + 1;
				if(item.text){
					choices.push("<a id=\"choice"+choice_num+"\" href=\"javascript:void(0)\" draggable=\"false\" class=\"choice\"><span>"+ item.text+"</span></a>");	
				}
				});
			}
			
			//do a quick shuffle
			$.randomize(choices);
			// Display choices using data from data.js
			for (var choice in choices){
				$(this).find(".choices").append(choices[choice]);
			}
				
			$(this).find('.choice').draggable({
				containment: me,
				cursor: 'move',
				stack: '.choice',
				revert: true,
				start:function(event,ui){
					if(ui.helper.parents(".revealcorrect").length)return false;
				}
			}).each(function(){
				this.addEventListener("dragstart",function(e){
					var evt = e || window.event;
					// Needed on any timeline images to get round bug in FF that makes an
					// image draggable once again when style -moz-user-select: none; is applied
					// even though element has draggable=false. (interestingly it's not there
					// if the file is .xhtml)
					evt.preventDefault ? evt.preventDefault() : evt.returnValue = false;
				})
			});
			
			// Display labels and set css from data.js
			if($.isArray(data.labels))
			{
				$.each(data.labels, function(key, item) {
					label_num = key + 1;
					var div=$(document.createElement("div")).attr("id","labeltext"+label_num).addClass("label");
					if(item.html)div.html(item.html);
					if(item.className)div.addClass(item.className);
					$(me).find(".targets").append(div);
					for (var i in item){
						if(i=="html")continue;
						if(i=="className")continue;
						$(me).find("#labeltext"+label_num).css(i,item[i]);
					}		
				});
			}		
			
			// Apply locations of droppable areas from data.js (in css)
			if($.isArray(data.droppableareas))
			{
				$.each(data.droppableareas, function(key, item) {
					droppable_num = key + 1;
					var target=(item.target)?item.target:".targets";
					var droppablearea= $(document.createElement("div")).attr("id","droppable-area"+droppable_num);
					if(!params.columnmap)droppablearea.addClass("choice"+droppable_num);
					droppablearea.addClass("droppable");
					droppablearea.append("<a href='javascript:void(0)' draggable='false'></a>");
					$(me).find(target).append(droppablearea);
					if(item.top)$(me).find("#droppable-area"+droppable_num).css("top",item.top);
					if(item.left)$(me).find("#droppable-area"+droppable_num).css("left",item.left);		
				});
				
			}
			
			function repopulateemptytargets(){
				//global tidy up fix if a choice is moved away from a target
				//then reset the anchor for keyboard access
				var droppables=$(me).find(".droppable");
				for(var d=0;d<droppables.length;d++){
					if(!$(droppables[d]).find("a").length){
						$(droppables[d]).append("<a href='javascript:void(0)' draggable='false'></a>");
					}
					//me represents the element that was bound to the draganddrop.  It might be a child
					//of the inline class or the one that actaully has the class
					if($(me).parents(".inline").length || $(me).hasClass("inline")){
						if($(droppables[d]).find("a").html()==""){
							$(droppables[d]).removeClass("filled");
							$(droppables[d]).parent().css({minWidth:"180px",width:"auto"});
						}
					}
				}
			}			
			//target	
			// if class of droppable, then make droppable	  
			$(this).find(".droppable").droppable({
				 // Event triggered when an accepted draggable(choice) is dropped on the droppable	
				 drop:function(event, ui){
					if($(this).hasClass("revealcorrect"))return false;
					//var defaultwidth=ui.draggable[0].defaultwidth;
					ui.draggable.css({top:"0px",left:"0px"});//lock in place
					// Return choice back to choices div if in current target (droppable)
					$(me).find(".choices").append($(this).find(".choice").css({left:"",top:""}).removeClass("selected"));//chuck out any choices that were already there and put back into top list
					// Add draggable html to droppable
					$(this).html(ui.draggable).addClass("filled");//.css({minWidth:0,width:defaultwidth+10}).parent().css({minWidth:0,width:defaultwidth+15});//add to target
					repopulateemptytargets();
					resizetarget(this);
				 }
			});
			
			var resizetarget=function(elem){
				if($(elem).parents(".inline").length){					
					if($(elem).parents(".targets").length){
						var width=(parseInt($(elem).css("width").replace("px",""))+10)+"px";
						$(elem).parents("span").css({width:width,minWidth:"0px"});
					}
				}
			};
			
			//allow drop back into choices
			$(this).find(".choices").droppable ({
				drop:function(event, ui){
					ui.draggable.css({top:"0px",left:"0px"});
					$(this).append(ui.draggable);  
					repopulateemptytargets();
				}
			});
			
			// If target is clicked (tapped)
			var targetclicktapkeydown=function(e){
				if(e.keyCode==9)return true;//let the tab key past
				if($(this).hasClass("revealcorrect"))return false;
				if(e.type=="keydown"){
					if(e.keyCode!=32)return;//only allow CR key
				}
				
				// Is a choice selected from the choices at the top
				if($(me).find(".choices a.selected").length){
					// Is there already a choice in the target? If so then chuck out
					$(me).find(".choices").append($(this).find(".choice").css({left:"",top:""}).removeClass("selected"));//chuck out
					// Add html of the 'selected' choice in the list at the top
					$(this).html($(me).find(".choices a.selected"));//append
					$(this).addClass("filled");
					resizetarget(this);
				// If target is selected
				}else if($(this).hasClass("selected")){
					$(me).find(".choices").append($(this).find(".choice").css({left:"",top:""}).removeClass("selected"));//chuck out
					// select first of the items from the choices
					$(this).html($(me).find(".choices a").eq(0));//append
					$(this).addClass("filled");
					resizetarget(this);
				}
				$(me).find(".targets div").removeClass("selected");
				$(this).addClass("selected");
				$(this).find("a").focus();
			};
			$(this).find(".targets div.droppable").click(targetclicktapkeydown);
			$(this).find(".targets div.droppable").keydown(targetclicktapkeydown);
			
			
			// Add 'selected' to choice selected
			$(this).find(".choices a").click(function(){
				if($(this).parents(".targets").length)return;
				if($(this).hasClass("selected")){
					$(me).find(".choices a").removeClass("selected");
				}else{
					$(me).find(".choices a").removeClass("selected");
					$(this).addClass("selected");
					$(this).focus();
				}
			});
			
			if(params.componentstyle)$(this).css(params.componentstyle);
			if(params.choicesstyle)$(this).find(".choices").css(params.choicesstyle);	
			if(params.targetsstyle)$(this).find(".targets").css(params.targetsstyle);	
			if(params.choicestyle)$(this).find(".choice").css(params.choicestyle);
			if(params.targetstyle)$(this).find(".target").css(params.targetstyle);
			if(params.labelstyle)$(this).find(".label").css(params.labelstyle);
			if(params.feedbackstyle)$(this).find(".feedback").css(params.feedbackstyle);
			
			if(params.targetmap){
				for (i=0;i< params.targetmap.length;i++){
					var classnames="",madata=[];
					for (j=0;j<params.targetmap[i].length;j++){
						classnames+="choice"+params.targetmap[i][j]+" ";
						madata.push(params.targetmap[i][j]);
					}
					for (j=0;j<params.targetmap[i].length;j++){
						$(this).find(".choice"+params.targetmap[i][j]).addClass(classnames);
						$(this).find("#choice"+params.targetmap[i][j]).addClass("multianswer").data("multianswer",madata);
					}
				}
			
			}
			
			if(params.columnmap){
				for(var columnid in params.columnmap){
					console.log(columnid,params.columnmap[columnid]);
					var str="";
					for (i=0;i<params.columnmap[columnid].length;i++){
						str+=" choice"+params.columnmap[columnid][i];
						$(this).find("#choice"+params.columnmap[columnid][i]).addClass("multianswer").data("multianswer",params.columnmap[columnid]).data("column",columnid);
					}
					$("."+columnid+" > div").addClass(str+" multianswer");
					
				}
			}
					
			//explicitly lock the height of choices to the calculated start value
			$(this).find(".choices").css({height:$(this).find(".choices").css("height")});
			$(this).find(".targets").css({height:$(this).find(".targets").css("height")});
			
			//explicitly lock the height and width of targets to the calculated start value
			var widthheight=[];
			$(this).find(".targets").find(".droppable").each(function(){
				var width=(parseInt($(this).css("width").replace("px",""))-3)+"px";
				var height=(parseInt($(this).css("height").replace("px",""))-0)+"px";
				widthheight.push({width:width,height:height});
			});
			i=0;
			$(this).find(".targets").find(".droppable").each(function(){
				$(this).css(widthheight[i]);
				i++;
			});
			
			$(this).find("#content").click(function(){
				$("#feedback").css({display:"none"});
				if(window.frameElement)window.frameElement.height=(Number($("body").css("height").replace("px",""))+50)+"px";
			});
			$(this).find("#content").keydown(function(){
				$("#feedback").css({display:"none"});
				if(window.frameElement)window.frameElement.height=(Number($("body").css("height").replace("px",""))+50)+"px";
			});
			
			var attempts=0,countofcorrect=0,maxattempts=2;
			if (params.maxattempts)maxattempts=params.maxattempts;
			
			function reveal(){
				$(me).find(".feedback").css({display:"none"});
				revealfeedback({me:me,reveal:true});
				$(me).find("#labeltext"+(countofcorrect+8)).css({display:"block"});
				
				$(me).find(".choice").each(function(){
					if($(this).hasClass("multianswer")){
						if(params.targetmap){
							madata=$(this).data("multianswer");
							for(i=0;i<madata.length;i++){
								var choiceid="#droppable-area"+madata[i];
								if(!$(me).find(choiceid+" a").html()){
									$(me).find(choiceid).html(this).addClass("filled");//add to target;
								}
							}
						}else if(params.columnmap){
							madata=$(this).data("column");
							//am I still in choices?
							if($(this).parents(".choices").length){
								var targets=$("."+madata);
								for (i=0;i<targets.length;i++){
									if(!$(targets[i]).find("a").html()){
										$(targets[i]).find("a").replaceWith(this);
										return;
									}
								}
							}
						}
					}else{
						var id=$(this).attr("id");
						$(me).find("."+id).html(this).addClass("filled");//add to target;
					}
					resizetarget($(this).parent());//"this" is the anchor tag within the droppable zone (which is the parent).
				});	
				repopulateemptytargets();
			}
			
			function throwout(){
				countofcorrect=0;
				var feedbackdata={me:me,attempts:attempts,maxattempts:params.maxattempts,maxcorrect:params.maxcorrect,correct:[],incorrect:[],notanswered:[],incorrectmore:[]};
				$(me).find(".choices .choice").each(function(){
					feedbackdata.notanswered.push(parseInt(this.id.replace("choice","")));
				});
				$(me).find(".droppable").each(function(){
					var choice=$(this).find(".choice").attr("id");
					if(choice){
						choiceid=parseInt(choice.replace("choice","")),
						dropid=parseInt(this.id.replace("droppable-area","")),
						parentid=$(this).parent().attr("class");
						if($(this).hasClass(choice)){
							feedbackdata.correct.push(choiceid);
							countofcorrect++;
						}else{
							//chuck out
							if(!params.leaveincorrect){
								feedbackdata.incorrectmore.push([choiceid,dropid,parentid]);
								feedbackdata.incorrect.push(choiceid);
								$(this).find(".choice").after("<a href='javascript:void(0)'></a>");
								$(me).find(".choices").append($(this).find(".choice"));
							}
						}
					}
				});	
				$(me).find(".choice").removeClass("selected");
				params.feedback(me,feedbackdata);
				repopulateemptytargets();
			}
			
			var highlightcorrect=function(){
				if(params.highlightcorrect!=false){
					$(".targets .droppable").each(
						function(){
							if($(this).has(".choice").length){
								$(this).addClass("revealcorrect");
							}
						});		
				}	
			};

			var reset=function(){
				$(me).find(".choices").append($(me).find(".choice"));
				$(me).find(".filled").removeClass("filled");
				$(me).find(".revealcorrect").removeClass("revealcorrect");
				if(params.autosave)save();
				attempts=0;
				$(me).find("#submit").val(submitname).unbind("click").click(submitfunc).prop("disabled",false);		
			};
			$(this).find("#reset").click(reset);
			
			var submitname="Submit";
			var submitfunc=function(e){
				e.stopPropagation();
				attempts++;
				if(attempts>maxattempts)return;
				submitname=$(this).val();
				throwout();
				highlightcorrect();
				$(me).find(".selected").removeClass("selected");
				var label=$(me).find("#labeltext"+(countofcorrect+1)),
				html=label.html();
				if(attempts<maxattempts){
					$(me).find("#labeltext"+(countofcorrect+1)).css({display:"block"});
				}
				if(attempts==maxattempts){
					//reveal();
					revealfunc(e);
					if(params.autoresetbtn){
						$(me).find("#submit").val("reset").unbind("click").click(function(){
							reset();
						});	
					}
				}
				if(params.autosave)save();
			}
			
			$(this).find("#submit").click(submitfunc);
			
			function load(rslt){
				var names=["d"];
				VLE.get_server_data(true,names,
					function(values){
						if(values.d){
							var d=JSON.parse(values.d);
							for(var c in d){
								if(c=="flags"){
									for(var f in d[c]){
										//tut tut but it keeps it simple will not work with strings-save strings with quotes
										eval(f+"="+d[c][f]);
									}
									continue;
								}
								if($("#"+d[c]).hasClass("choices")){
									$("#"+d[c]).append($("#"+c));
								}else{
									$("#"+d[c]).html("").append($("#"+c));
								}
							}
							
						}
						if(resetflag){
							var reset=(params.resetbuttonname)?params.resetbuttonname:"Reset";
							$(me).find("#reveal").val(reset).addClass("reset");
							resetflag=true;						
						}
					},
					function(){console.log("load failed",arguments)})
			}
			
			var clearmsg=function (){
				$("#msg").html("");
			};
			
			function save(){
				var rslt={};
				$(me).find(".choice").each(function(){
					rslt[this.id]=$(this).parent()[0].id;
				});
				rslt.flags={};
				rslt.flags.resetflag=resetflag;
				rslt.flags.revealbuttonname="'"+revealbuttonname+"'";
				rslt=JSON.stringify(rslt);
				rslt={d:rslt};
				VLE.set_server_data(true,rslt,
				function(){
					console.log("save ok");
					$("#msg").html("<span class='success'>Data successfully saved</span>");
					this.st=setTimeout(function(){clearmsg()},5000)
				},
				function(){console.log("save failed")});			
			}
			
			$(this).find("#save").click(function(){
				save();
			});
			
			$(this).find("#restart").click(function(){
				reset();
			});
			
			$(me).find("#submit").prop("disabled",false);//fix for firefox which stores disabled state in form data
			var revealbuttonname,
			resetflag=false,
			resetfunc=function(){
					$(".choices").append($(".choice"));
					$(me).find("#reveal").val(revealbuttonname).removeClass("reset");
					$(me).find("#submit").prop("disabled",false);
					$(me).find(".revealcorrect, .selected").removeClass("revealcorrect").removeClass("selected");
					$(me).find(".filled").removeClass("filled");
					$(me).find("span").each(function(){this.style=""});
					$(me).find("span").each(function(){this.removeAttribute("style")});
					attempts=0;
					resetflag=false;			
			},
			revealfunc=function(e){
					var reset=(params.resetbuttonname)?params.resetbuttonname:"Reset";
					e.stopPropagation();
					throwout();
					highlightcorrect();
					reveal();
					revealbuttonname=$(me).find("#reveal").val();
					$(me).find("#reveal").val(reset).addClass("reset");
					$(me).find("#submit").prop("disabled","disabled");
					$(me).find(".selected").removeClass("selected");
					resetflag=true;			
			};
			$(this).find("#reveal").click(function(e){
				if($(this).hasClass("reset")){
					resetfunc();
				}else{
					revealfunc(e);
				}
			});
			if(window.frameElement)window.frameElement.height=(Number($("body").css("height").replace("px",""))+50)+"px";
			load();
		});
	};
}( jQuery ));

function revealfeedback(feedbackdata){
	if($(feedbackdata.me).find("#revealfeedback").length){
		$(feedbackdata.me).find("#revealfeedback").css({display:"block"});
		if(window.frameElement)window.frameElement.height=(Number($("body").css("height").replace("px",""))+50)+"px";
	}			
}

function feedback_generic(feedbackdata){
	var hint="",numbers=["None","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen","Twenty"];
	
	//console.log(feedbackdata.attempts,feedbackdata.maxattempts,feedbackdata.attempts==feedbackdata.maxattempts)
	if(feedbackdata.attempts==feedbackdata.maxattempts){
		hint="<br/>The correct answers have been filled in for you.";
	}
	switch(feedbackdata.correct.length){
		case feedbackdata.maxcorrect:
			return "All of your answers are correct";
		break;
		case 0:
			return "None of your answers are correct"+hint;
		break;
		case 1:
			return "One of your answers is correct"+hint;
		break;
		default:
			return numbers[feedbackdata.correct.length]+" of your answers are correct"+hint;
		
	}
}

function feedback_modal(me,feedbackdata){
	
	var msg = feedback_generic(feedbackdata);
	//do not stack dialogs
	//console.log("feedback_modal",$( "#feedback" ).length);
	if($( "#feedback" ).length)return;
	$(me).find("#content").append('<div id="feedback" class="modal" title="error">'+msg+'<br/><br/><input type=button value=\'close\'></div>');
	$(me).find( "#feedback" ).dialog({
	  //height: 120,
	  modal: true
	}).css({textAlign:"center"}).click(function(e){
		e.stopPropagation();
		$("#feedback").remove();
	});
	$(".ui-dialog-titlebar").remove();

	if(feedbackdata.maxcorrect==feedbackdata.correct.length)revealfeedback(feedbackdata);
}

function feedback_dropdown(me,feedbackdata){
	var msg = feedback_generic(feedbackdata);
	$(me).find("#feedback").remove();
	$(me).find("#content").append('<div id="feedback" style="display:block" class="dropdown" title="error">'+msg+'<br/><br/></div>');
	if(window.frameElement)window.frameElement.height=(Number($("body").css("height").replace("px",""))+20)+"px";
}