//GUI ELEMENTS
function createPopup(id,pos,left,tri,name,html,style){
	var result = ""
	var pop = document.createElement('div')
	pop.className="popup"
	pop.id=id
	if(left) pop.style.left = pos+(typeof pos == 'string'?"":"px")
	else pop.style.right = pos+(typeof pos == 'string'?"":"px")
	pop.innerHTML+='<div class="popup_point" style="left:'+tri+'px;"></div>'
	pop.innerHTML+='<div class="popup_task">'+name+'</div>'
	//pop.innerHTML+='<div style="position:relative;height:100%;background-color:blue">'+html+'</div>'
	pop.innerHTML+=html
	for(var x in style)pop.style[x] = style[x]
	$('#popup_collect').append(pop)
	
	closeAllPopups()
}
function openPopup(name){
	$('.popup').not('#'+name).hide()
	$('#'+name).toggle()
	$('#curtain').show()
}
function closeAllPopups(){
	$('.popup').hide()
	$('#curtain').hide()
}
function createDialog(id,pos,left,tri,name,html){ //incomplete completely
	var result = ""
	var pop = document.createElement('div')
	pop.className="dialog"
	pop.id=id
	if(left) pop.style.left = pos+"px"
	else pop.style.right = pos+"px"
	pop.innerHTML+='<div class="popup_point" style="left:'+tri+'px;"></div>'
	pop.innerHTML+='<div class="popup_task">'+name+'</div>'
	pop.innerHTML+=html
	$('#popup_collect').append(pop)	
	/*<div class="dialog" id="settings">
			<div id="taskbar">
				<div style='float:left'></div>
				<div style="text-align:center;padding-top:15px;">Settings</div>
				<div style='float:right'>
					<button onclick="$('#settings').slideToggle(150);$('#curtain').slideToggle(150);" class='task gray'>Close</button>
				</div>
			</div>
			Choose Theme: <select id="themelist"> </select><br>
			Font Size: <select id="fontsize"> </select><br>
		</div>*/
}
function toggleDialog(name){
	$('#'+name).slideToggle(150);$('#curtain').fadeToggle(150);
}
UI = {
	listSelected: function(id,select){ //returns the selectedindex of a list
		var sel = -1
		$('#'+id).children('div').each(function (i,elem){
			if(i==select) $(elem).click()
			if($(elem).hasClass('select')) sel = i
		})
		return sel
	},
	textValue: function(id,txt){ //returns/sets text value for field
		if($('#'+id).hasClass('none') && !txt) return ""
		var elem = document.getElementById(id)
		if(txt!=null){
			elem.value = txt
			$(elem).trigger('keydown')
			return txt
		}
		return document.getElementById(id).value
	},
	textValueHighlight: function(id,cls){$('#'+id).parent().addClass(cls)},
	setup: function(){
		//automatically style the text inputs
		$('input.bigtext').each(function (i,elem){
			var top = $(elem).hasClass('top')
			var btm = $(elem).hasClass('bottom')
			var text = '<div class="bigitem '+(top?"top ":"")+(btm?"bottom ":"")+'">'+elem.name+
					'<input type="text" id="'+elem.id+'" class="bigtext" data="'+$(elem).attr('data')+'"/></div><br/>'
			$(elem).before(text)
			$(elem).remove()
		})
		
		//add event listeners to text for watermarking
		$('input.bigtext').each(function (i,elem){
			$(elem).bind('keyup',function (){
				if($(this).val() == ""){
					$(this).val($(this).attr('data'))
					$(this).addClass('none')
					$(this).click()
				}
			})
			$(elem).bind('keydown',function (ev){
				$(this).removeClass('none')
				if($(this).val() == $(this).attr('data')) $(this).val('')
				if(ev.which == 9) $(this).trigger('keyup')
			})
			$(elem).bind('click',function (){
				if($(this).hasClass('none')){
					$(this).get(0).selectionStart = 0
					$(this).get(0).selectionEnd = 0
				}
			})
			$(elem).trigger('keyup')
		})
		
		//list generator
		$('select.big_list_select').each(function (i,elem){
			var text = '<div class="big_list_container" id="'+elem.id+'">'
			var len = $(elem).children('option').length-1
			var change = $(elem).get(0).onchange
			var select = $(elem).get(0).selectedIndex
			$(elem).children('option').each(function (j,item){
				text+='<div class="bigitem '+(j==0?"top ":"")+(j==len?"bottom ":"")+(j==select?"select ":"")+'">'+$(item).text()+
					'<span style="float:right; margin-top: -5px; '+(j==select?'':'display:none;')+'">&#10003;</span></div><br/>'
			})
			$(elem).before(text+"</div>")
			$(elem).remove()
			if(change) $("#"+elem.id).change(change)
		})
		//list events for selecting
		$('.big_list_container').each(function (i,elem){
			$(elem).children('div').click(function (){
				if(!$(this).hasClass('select')){
					$(this).parent().children('div').removeClass('select')
					$(this).parent().children('div').children('span').css('display','none')
					$(this).addClass('select')
					$(this).children('span').css('display','inline')
					$(this).parent().change()
				}
			})
			
		})
	},
	addArrayToList: function (id,arr,click,options){
		if(!options) options = {cls:"",append:false,noradius:false,select:false}
		if(!options.append) $('#'+id).html("")
		arr.each(function (i,item){
			if(!(typeof item == 'object')) item = {value:item, enable:true,click:false}
			var div = document.createElement('div')
			var enable = (typeof item == 'object' && !item.enable? false : true)
			div.className = "bigitem "+(!options.noradius && i==0?"top ":"")+(!options.noradius && i==arr.length-1?"bottom ":"") + (!enable ? "disable" : "")+" "+options.cls
			div.innerHTML = item.value+(item.enable?'<span style="float:right;">&gt;</span>':"")
			if(enable && !item.click) $(div).attr('onclick',click)
			else if(enable && item.click) $(div).attr('onclick',item.click)
			$('#'+id).append(div)
		})
	},
	addArrayToSelect: function (id,arr,click,options){ //TODO - change selected bit
		//if(!options) options = {cls:"",append:false,noradius:false,select:false}
		//if(!options.append) $('#'+id).html("")
		var len = arr.length-1
		arr.each(function (i,item){
			var text='<option '+(SET_THEME==i?'selected':'')+'>'+item+
					'</option>'
			$('#'+id).append(text)
		})
	}
}
KEYS = {
	update: function (multi){
		var mid = " "
		var tab = "--"
		var loc = DETECT.getLocation()
		if(multi){
			mid = "..."
			if($('#editor').val().substring(SELECT_ST,SELECT_EN).split('\n').length > 1) tab = "=="
		}
		$('#key_tabb').html("|<"+tab)
		$('#key_tabf').html(tab+">|")
		$('#key_brack').html('('+mid+')')
		$('#key_meth').html('{'+mid+'}')
		$('#key_arr').html('['+mid+']')
		$('#key_str').html('"'+mid+'"')
		switch(loc.type){
			case DETECT.NO: this.disableKeys(['bool','num','types','brack','ebr','arr','ear','str','static','void','final']); break;
			case DETECT.CL: this.disableKeys(['none','class','interface']); break;
			case DETECT.FN: this.disableKeys(['mod']); break;
		}
	},
	disableKeys: function(arr){
		$('button.key').removeClass('disabled');
		$('button.keyhalf').removeClass('disabled');
		$('button.key').removeAttr('disabled');
		$('button.keyhalf').removeAttr('disabled');
		arr.each(function (i,item){
			$('#key_'+item).attr('disabled','disabled');
			$('#key_'+item).addClass('disabled')
		})
	},
	pressKey: function (code){
		$('#editor').focus()
		var event = $.Event('keypress')
		event.which = code
		this.trigger(event,true)
	},
	insertKey: function (str){
		var elem = document.getElementById('editor')
		var text = $(elem).val()
		$(elem).val(text.substring(0,SELECT_ST)+str+text.substring(SELECT_EN))
		SELECT_ST = SELECT_ST+str.length
		SELECT_EN = SELECT_ST
		elem.selectionStart = SELECT_ST
		elem.selectionEnd = SELECT_EN
		elem.focus()
		//$(elem).trigger('mousemove')
		updateOverlay()
		newEdit()
	},
	doKey: function (code,shft){
		$('#editor').focus()
		var event = $.Event('keydown')
		event.keyCode = code
		event.shiftKey = shft
		this.trigger(event)
		event = $.Event('keyup')
		event.keyCode = code
		event.shiftKey = shft
		this.trigger(event)
	},
	trigger: function(event,update){
		$('#editor').trigger(event)
		if(update){
			updateOverlay()
			newEdit()
		}
	},
	tabBlock: function(elem,back){
		var text = $(elem).val()
		var a = SELECT_ST
		var b = SELECT_EN
		var block = text.substring(a,b)
		var lines = block.split('\n')
		if(lines.length > 1){
			var eol = text.substring(0,a-1).search(/\n[^\n]*$/)
			if(eol==-1) eol = 0
			if(back) block = text.substring(eol,b).replace(/(\n[ \t]*)\t/g,"$1")
			else block = text.substring(eol,b).replace(/(\n([ \t]*))/g,"$1\t")
			if(eol==0) block = "\t"+block
			$(elem).val(text.substring(0,eol)+block+text.substring(b))
			elem.selectionStart = a+1-(back?lines.length:0)
			elem.selectionEnd = b+(back?-lines.length:lines.length)
		}else {
			$(elem).val(text.substring(0,a)+"\t"+text.substring(b))
			elem.selectionStart = a+1
			elem.selectionEnd = a+1
		}
	},
	extendBuild: function(id,arr,up,noback){
		var bar = document.getElementById(id)
		var key = function (e){
			$('#editor').focus()
			$(bar).show()
			$('#key_bar').hide()
			printCmd(false)
			$('#editor').focus()
			e.preventDefault()
		}
		var hide = function (){
			$(this).hide()
			$('#key_bar').show()
			$('#editor').focus()
		}
		//s$('#key_'+id.replace("extend_","")).bind('mousedown',key)
		$('#key_'+id.replace("extend_","")).bind('click',key)
		
		var btn = document.createElement('button')
		btn.className = 'task key center gray display'
		btn.innerHTML = "< Back"
		btn.onclick = function (){
			$(this.parentNode).hide()
			$('#key_bar').show()
			$('#editor').focus()
		}
		$(bar).append(btn)
		var fun = up
		if(noback){fun = _.compose(btn.onclick,up)}
		
		arr.each(function (i,item){
			var btn = document.createElement('button')
			btn.className = 'task key center gray display'
			btn.innerHTML = item
			btn.id = "key_"+item
			btn.onclick = fun
			$(bar).append(btn)
		})
	},
	requestUnfocusPlz: function(){
		$("#content").height("100%")
		setTimeout(function (){$(window).resize()},50)
		FOC = false
	}
}
//DETECT LOCATION
DETECT = {
	NO: -1, CL: 0, FN: 1,
	lastLoc: null,
	getLocation: function(){
		if(this.lastLoc) return this.lastLoc
		if(!PROGRAM) return;
		var a = SELECT_ST
		var b = SELECT_EN
		var type = this.NO;
		var c, f
		PROGRAM.each(function (i,cls){ //loop each class to find current class cursor located in
			if(cls.range.from >= a || cls.range.to < a) return
			type = DETECT.CL
			c = cls
			for(var x in cls.funs){
				var done = cls.funs[x].each(function (j,fun){ //loop through each function to see if cursor in a fun
					if(!fun.range || fun.range.from >= a || fun.range.to < a) return
					type = DETECT.FN
					f = fun
					return true
				})
				if(done) return true
			}
		})
		this.lastLoc = {type: type, cls: c, fun: f}
		return this.lastLoc
	}
}
//EDITOR OPTIONS
var THEMES=[new THEME("Original","ghostwhite","black","blue","red","orange","darkred","gray","green"),
			new THEME("Night","rgb(20,20,20)","white","green","yellow","orange","red","gray","green")]
var SET_THEME=0;
var UI_REG = ""
function THEME(name,back,norm,key,fun,str,num,cus,com){
	this.name=name
	this.back=back
	this.key=key
	this.fun=fun
	this.str=str
	this.num=num
	this.cus=cus
	this.norm=norm
	this.com = com
}
function CURTHM(){return THEMES[SET_THEME]}
function updateTheme(id){
	SET_THEME=id
	localStorage.setItem('JIM-THEME',id)
}
function getTheme(){
	SET_THEME=localStorage.getItem('JIM-THEME')
	if(SET_THEME==null) SET_THEME=0
	else parseInt(SET_THEME)
}
function listTheme(id){
	SET_THEME=localStorage.getItem('JIM-THEME')
	if(SET_THEME==null) SET_THEME=0
	else parseInt(SET_THEME)
	
	var themes = []
	THEMES.each(function (i,item){themes.push(item.name)})
	
	UI.addArrayToSelect('theme_list',themes, function(){})
}

var SET_SIZE=0;
function updateSize(id){
	SET_SIZE=10+2*id
	localStorage.setItem('JIM-SIZE',SET_SIZE)
}
function getSize(){
	SET_SIZE=localStorage.getItem('JIM-SIZE')
	if(SET_SIZE==null) SET_SIZE=14
	else parseInt(SET_SIZE)
	$('#editor').css({"font-size":SET_SIZE+"px"})
	$('#code').css({"font-size":SET_SIZE+"px"})
	$('#lines').css({"font-size":SET_SIZE+"px"})
	$('#fontwidth').css({"font-size":SET_SIZE+"px"})
	FONT_WIDTH=$('#fontwidth').width()/6
	FONT_HEIGHT=$('#fontwidth').height()
}
function listSize(id){
	SET_SIZE=localStorage.getItem('JIM-SIZE')
	if(SET_SIZE==null) SET_SIZE=20
	else parseInt(SET_SIZE)
	var result = ""
	for(var i = 10; i < 32; i+=2) result+="<option "+(SET_SIZE==i?"selected":"")+">"+i+"</option>"
	$("#fontsize").html(result)
	$("#fontsize").bind('change', function (e){updateSize(this.selectedIndex)})
}

//AUTOCOMPLETE

var AUTOCOMPLETE, PRELOAD, FOUND_AUTO
var FOUND_SELECT=0
var TABBING = []
var DEF_AUTO = [new AUTO("for","0","($int i = 0$; $i < 10$; $i++$){\n\r$statements$\n}$$",null,"true"),
		new AUTO("while","0","($false$){\n\r$statements$\n}$$",null,"true"),
		new AUTO("if","0","($true$){\n\r$/*statements*/$\n}$$",null,"true"),
		new AUTO("if","0","($true$){\n\r$/*if-true*/$\n}else{\n\r$/*if-false*/$\n}$$",null,"true")]
var PREAUTO, PREBLOCK

				
function AUTO(match,parent,data,repeat,vis,stat,type,hide){
	this.match=match
	this.parent=parent
	this.data=data
	this.repeat=repeat
	this.vis = vis
	this.static = stat
	this.type = type
	this.hide = hide
	if(AUTOCOMPLETE) this.id = ''+UID()+AUTOCOMPLETE().count()
}
function preloadAuto(){
	if(!PREAUTO){
		AUTOCOMPLETE = new TAFFY()
		var prog = []
		for(var x in lib.java.lang) prog.push(lib.java.lang[x])
		populateAuto(prog,null,null,true)
		PREAUTO = AUTOCOMPLETE().get()
		AUTOCOMPLETE = new TAFFY()
	}
	return PREAUTO
}
function populateAuto(prog,cl,p,force,hide){
	if(!force && cl==null) {
		prog = prog.concat([])
		AUTOCOMPLETE = new TAFFY({})
		if(prog.length > 0){ //add import classes to auto list
			var c = new J_CLASS("","",true,[],[],true,prog[0].imports)
			importClasses(c,c)
			for(var i = 0; i < c.impcls.length-1; i++){
				if(c.impcls[i] instanceof J_FOLDER) continue;
				prog.push(c.impcls[i])
			}
		}
	}
	var LIST = AUTOCOMPLETE
	prog.each(function (i,item){
		if(!item) return;
		if(cl!=null && item.name!=cl) return ;
		var t = new AUTO(item.name,(p==null?"0":p),"$$",false,"true","true",null,(hide?true:false))
		if(cl==null) AUTOCOMPLETE.insert(t)
		else t = {id:p}
		for(var x in item.funs){
			item.funs[x].each(function (j,fun){
				var args=""
				fun.args.each(function (_,arg){args+=",$/*"+arg.type+" "+arg.name+"*/$"})
				var f = new AUTO(fun.name,t.id,"("+args.substring(1)+")"+(fun.type=="void"?";":"")+"$$",false,fun.vis?"true":"false",fun.static?"true":"false",(fun.type=="void"?null:fun.type))
				LIST.insert(f)
			})
		}
		
		item.vars.each(function (j,fun){
			var f = new AUTO(fun.name,t.id,"$$",false,fun.vis?"true":"false",fun.static?"true":"false",fun.type)
			LIST.insert(f)
		})
		//insert imported classes if not there
		var c = {name:item.name,impcls:[],imports:item.imports};
		importClasses(c,c);
		_.each(c.impcls,function(item){
			if(AUTOCOMPLETE({parent:"0", match:item.name}).count() == 0)
				populateAuto([item],null,null,true,true)
		})
		
	})
}

function checkAuto(e,t,click){
	if(click!=null) t = document.getElementById('editor')
	var a = t.selectionStart
	var b = t.selectionEnd
	if(click==null && e.keyCode==13) a--

	var txt = t.value.substring(0,a)
	var find = txt.search(/[a-zA-Z0-9_\.]+$/)
	if(find > -1){ //some bit found that needs autoing
		var check = txt.substring(find)
		var subs = check.split(".")
		var current = "0"
		var vis = true
		var info = ""
		var loc = DETECT.lastLoc
		var COMP = TAFFY({})
		if(loc.type == DETECT.NO){ //autocomplete for imports
			
		}
		if(loc.cls){
			COMP.insert(AUTOCOMPLETE().get())
			COMP.insert(preloadAuto())
			var id = AUTOCOMPLETE({match:loc.cls.name}).first().id
			var group = AUTOCOMPLETE({parent:id}).get()
			group.each(function (i,item){var a = new AUTO(item.match,"0",item.data,item.repeat,item.vis,item.static,item.type);a.id = item.id;COMP.insert(a)})
		}
		if(loc.fun){
			COMP.insert(DEF_AUTO)
			loc.fun.vars.concat(loc.fun.args).each(function (i,item){var a = new AUTO(item.name,"0","$$",false,true,true,item.type);COMP.insert(a)})
		}
		for(var i = 0; i < subs.length-1; i++){ //traverses dot tree (System.out. etc)
			var tmp = COMP({parent:current})
			var type = COMP({id:current}).first().type
			if(current!=0 && type && !primType(type)) tmp=COMP({parent:"0", match:type, hide:false})
			else tmp = tmp.filter({match:subs[i]})
			
			if(tmp.count()==0) {listComplete([]);return false;} //no match so dont continue search
			info+=subs[i]+"."
			current = tmp.first().id
			vis = false
		}
		vis = false
		if(click!=null || e.keyCode==13){ //cliked/keypressed to add auto text so do it...
			var match = FOUND_AUTO.get()[FOUND_SELECT]
			if(click!=null) match=FOUND_AUTO.get()[click]
			var start = t.value.substring(0,find).length+info.length+match.match.length
			var final = t.value.substring(0,find)+info+match.match
			var lines = match.data.split("\n")
			final += lines[0]
			lines.splice(0,1)
			lines.each(function (i,part){final = autoIndent(null,final)+part})
			
			final = t.value.substring(0,find)+info+match.match+fillTabbing(final.substring(start),start)
			t.value = final+t.value.substring(b)
			t.focus()
			tabNext(t)
			listComplete([])
			updateOverlay()
			return true; //has done a replace
		}
		var found = COMP({parent:current})
		var type = COMP({id:current}).first().type
		if(found.first().repeat) found=COMP({parent:found.first().data})
		if(type && !primType(type)) {
			var id = COMP({parent:"0",match:type}).first().id
			found = COMP({parent:id})
		}

		found = found.filter({match:{left:subs.slice(-1)[0]}, vis:{regex:(vis?/^(true)|(false)$/:/^true$/)}}).order('match')
		listComplete(found)
		FOUND_SELECT=0
	}else {listComplete([]);return false;} 
}
function fillTabbing(data,start){
	var t = []
	var tabs = data.searchAll(/\$[^\$]*\$/,"<font style='background-color: rgba(100,255,240,1);border-radius: 10px;'>","</font>")
	tabs.each(function (i,item){item.st+=start-(2*i); item.len-=2; item.str=item.str.replace(/\$([^\$]*)\$/g,"$1");t.push(item)})
	TABBING = t.concat(TABBING)
	return data.replace(/\$([^\$]*)\$/g,"$1").replace(/\r/g,"\t")
}
function tabNext(t){
	if(TABBING.length > 0){
		var next = TABBING.splice(0,1)[0]
		t.setSelectionRange(next.st,next.st+next.len)
	}
}
function updateTabLocation(ins,add,ret){
	var t = document.getElementById('editor')
	var a = SELECT_ST-1
	var b = SELECT_EN-1
	var len = a-b
	var total = ins + len
	
	
	for(var i = 0; i < TABBING.length; i++){
		var tab = TABBING[i]
		if(a < tab.st && b < tab.st) tab.st+=(add!=null?total:total)+(add?-1:0)
		else {
			TABBING.splice(i,1)
			i--
		}
	}
}
function listComplete(list){
	FOUND_AUTO=list
	var result = ""
	FOUND_AUTO.each(function (r,i){
		var click = " onclick='checkAuto(null,null,"+i+")' "
		result += '<div class="autoitem'+(i==FOUND_SELECT?" autoselect":"")+'" + '+click+'>'+r.match+r.data.replace(/\$([^\$]*)\$/g,function (s,a){return (a==""?a:"&lt;"+a+"&gt;")}).replace(/\r/g,"\t").replace(/(\/\*)|(\*\/)/g,"")+'</div>'
	})
	if(result=="") $('#autolist').hide()
	else $('#autolist').show()
	$('#autolist').html(result)
}
function posAuto(){
	var t = document.getElementById('editor')
	var a = t.selectionStart
	var b = t.selectionEnd
}
function autoUpdateSelect(){
	$('.autoitem').removeClass('autoselect')
	$($('.autoitem').get(FOUND_SELECT)).addClass('autoselect')
}

//FIND AND REPLACE
var SEARCH=[]
var SEARCH_ID=0
function moveSearch(next){
	if(SEARCH.length==0) return ;
	if(next) SEARCH_ID++
	else SEARCH_ID--
	if(SEARCH_ID)
	SEARCH_ID = Math.mod(SEARCH_ID,SEARCH.length)
	var edit = document.getElementById('editor')
	edit.focus()
	edit.setSelectionRange(SEARCH[SEARCH_ID].st,SEARCH[SEARCH_ID].st+SEARCH[SEARCH_ID].len)
}
function replaceAllText(){
	var rep = $('#text_rep').val()
	if(UI_REG=="") return ;
	var txt = $('#editor').val().replace(new RegExp(UI_REG,"g"),rep)
	$('#editor').val(txt)
	$('#editor').trigger('keyup')
}
function replaceNextText(rep){
	if(SEARCH.length==0 || UI_REG=="") return ;
	if(SEARCH_ID==-1) SEARCH_ID=0
	var rep = $('#text_rep').val()
	var txt = $('#editor').val()
	var item = SEARCH[SEARCH_ID]
	$('#editor').val(txt.substring(0,item.st)+rep+txt.substring(item.st+item.len))
	var tmp = SEARCH_ID
	$('#editor').trigger('keyup')
	SEARCH_ID = tmp
	if(SEARCH.length > 0){
		if(SEARCH_ID >= SEARCH.length) SEARCH_ID=0
		var edit = document.getElementById('editor')
		edit.focus()
		edit.setSelectionRange(SEARCH[SEARCH_ID].st,SEARCH[SEARCH_ID].st+SEARCH[SEARCH_ID].len)	
	}
}
//COLLAB FUNCTIONS
var COLLAB = false
var JOINED = false
var SELECT_ST=0
var SELECT_EN=0;
var JOIN_LAST = new Date()
function masterCollab(){
	COLLAB = !COLLAB
	$('#collab_master').toggleClass('green')
	collabChange()
	$('#editor').focus()
}
function joinCollab(){
	var edit = document.getElementById('editor')
	JOINED = !JOINED
	//ERRORS=[]
	TABBING=[]
	$('#collab_join').toggleClass('green')
	if(JOINED) {
		joinRefresh()
		if(!COLLAB) edit.setAttribute('readonly','')
	}else {
		edit.removeAttribute('readonly')
		updateOverlay()
	}
}
function collabChange(){
	var edit = document.getElementById('editor')
	$.ajax({
		url: 'http://localhost:8080/JIM/set.php?session=1&callback=sessionGet',
		dataType: 'jsonp',
		data: {code:edit.value.replace(/\\/g,"\\\\"), start:edit.selectionStart, end:edit.selectionEnd, output:$('#cmd').val(), up:new Date().getTime()}
	});
}
function joinRefresh(){
	$.ajax({
		url: 'http://localhost:8080/JIM/get.php?session=1&callback=sessionGet',
		dataType: 'jsonp',
		data: {last:JOIN_LAST.getTime()},
		success: CSG
	});
}
function CSG(data){
	if(!JOINED) return ;
	if(data.u==null && (!COLLAB || (COLLAB && LAST_EDIT < JOIN_LAST.getTime()))){
		JOIN_LAST=new Date();
		var edit = document.getElementById('editor')
		edit.value = data.data
		edit.focus()
		if(!COLLAB) $('#cmd').val(data.output)
		var a = parseInt(data.start)
		var b = parseInt(data.end)
		var style = 'background-color: cornflowerblue; border-right: 2px solid black; margin-right: -2px;'
		if(a==b) style = 'border-left: 2px solid black; margin-left: -2px;'
		TABBING=[{st:a,len:b-a,str:data.data.substring(a,b),a:"<font style='"+style+"'>",b:"</font>"}]
		updateOverlay()
	}else if(data.u==null) {
		JOIN_LAST=new Date()
		document.getElementById('editor').setSelectionRange(SELECT_ST,SELECT_EN)
	}
	if(JOINED) setTimeout(joinRefresh,0)
}

//DROPBOX TEST
/*var client = new Dropbox.Client({key:"hUmpjjJ1WEA=|gotCaFDIpixalMxAZvBlBWd4bGMZzpCEvY4/BqR4ag==", sandbox:true});
var DROPBOX_OK = false
function initDropbox(callback){
	client.authDriver(new Dropbox.Drivers.Redirect({rememberUser: true, useQuery: true}));
	client.authenticate(function(error, client) {
		if (error) {
			alert("an error"+error)
			return ;
		}
		$('#btn_dropbox').toggleClass('green')
		DROPBOX_OK = true
		callback()
	});
}
function saveToDropbox(url,content){
	if(!DROPBOX_OK){
		alert("Dropbox is not authorized, setup in settings")
		return ;
	}
	client.writeFile(url, content, function(error, stat) {
		if (error) {
			alert("Error sycing file to dropbox: "+error)
			return ;
		}
		alert("file saved ok")
	});
}
function dropboxDir(url,callback){
	if(!DROPBOX_OK){
		alert("Dropbox is not authorized, setup in settings")
		return ;
	}
	client.mkdir(url, function(error, stat) {
		if (error) {
			alert("Error syncing project folder to dropbox: "+error)
			return ;
		}
		if(callback) callback()
	});
}
DROPBOX = {
	request: function (req,a,b,c){
		if(!DROPBOX_OK){
			alert("Dropbox is not authorized, setup in settings")
		}else {
			switch(req){
				case 'list': this.listContents(a,b)
				case 'get': this.getFile(a,b)
			}
		}
	},
	listContents: function (url,callback){
		client.metadata(url,{readDir:true},function(e,s,d){if(e) alert('error'); else callback(e,s,d)})
	},
	getFile: function (url,callback){
		client.readFile(url,function(e,d,m){if(e) alert('error'+JSON.stringify(e)); else callback(d,m)})
	}
}
function dropboxUpdate(id){
	var file = DB_FILES({id:CURRENT_FILE}).first()
	saveToDropbox(DB_FILES({id:CURRENT_PROJECT}).first().name+"/"+file.name,file.doc)
}
*/
//PDF FILE OUTPUT
function outputPDF(){
	var doc = new jsPDF()
	doc.setFontSize(10)
	$('#code').html().replace(/<br>/g,"").split('\n').each(function (i,item){
		var last = 0
		var CHARS = 0
		
		item.searchAll(/(<font style=\"color: [a-z]+;\">)|(<\/font>)/).each(function (j,col){
			var bit = item.substring(last,col.st)
			
			doc.text(10+CHARS*2, 10+i*4, bit)
			last = col.st+col.len
			
			CHARS+=bit.length
			if(col.str=="</font>") doc.setFontColor(0,0,0)
			else{
				var c = getRGB(col.str.replace(/<font style=\"color: ([a-z]+);\">/,"$1"))
				doc.setFontColor(c.r,c.g,c.b)
			}
		})
		var bit = item.substring(last)
		doc.text(10+CHARS*2, 10+i*4, bit)
	})
	doc.setProperties({title:"hello", subject:"heya"})
	var fileName = "testFile"+new Date().getSeconds()+".pdf";
	var pdfAsDataURI = doc.output('datauri', {"fileName":fileName});
	$('#debug').html('<a href="'+pdfAsDataURI+'"> pdf test </a>')
}

function getRGB(color){
	switch (color) {
		case "blue": return new COLOR(0,0,255); break;
		case "red": return new COLOR(255,0,0); break;
		case "green": return new COLOR(0,255,0); break;
		case "orange": return new COLOR(255,165,0); break;
		case "darkred": return new COLOR(139,0,0); break;
		case "gray": return new COLOR(100,100,100); break;
	}
	return new COLOR(0,0,0)
}
function COLOR(r,g,b){
	this.r = r
	this.g = g
	this.b = b
}
//PROGRESS REPORT
var REPORT = {}
REPORT.getTotalProgress = function (){return REPORT.getFolderProgress(lib)}
REPORT.getFolderProgress = function (f,l){
	if(f.is == "0") return l+": "+REPORT.getClassProgress(f)+"\n"
	var str = ""
	for(x in f) str+=REPORT.getFolderProgress(f[x],(l?l+".":"")+x)
	return str
}
REPORT.getClassProgress = function (s){
	var l = 0
	var c = 0
	for(var x in s.funs){
		s.funs[x].each(function (i,item){
			if(item.name == "UNSUP") return;
			if(item.stats.length > 0 && item.stats[0].fun == "UNSUP") c++
			l++
		})
	}
	return ((l-c)/l*100).toFixed(2)+"%"
}
//
GUI = {
	javaDocs: {
		currentFolder: "",
		popupStack: [],
		classTemp:[],
		objList:[],
		id:"javadocs",
		isOpen: false,
		open: function (){
			if(this.isOpen && this.id == "javadocs_side"){
				GUI.SideBar.toggle()
				this.isOpen = false
				return;
			}
			if($(document).width() > 1200){
				this.id = "javadocs_side"
				GUI.SideBar.toggle()
			}else{
				this.id = "javadocs"
				openPopup('popup_docs')
			}
			this.isOpen = true
			this.init()
		},
		helpDoc:{"Java":{
				"Getting Started":"<p>Java is a cross compatible language that is object oriented and typed. It has been designed to run on multiple platforms from one compiled file. </p><p></p>",
				"Classes":"<p>A class is an object template that specifies fields which store the objects current state and methods which define its interactions.</p><pre>public class Car{\n\tint final numWheels = 4;\n\tint speed = 0;\n\tint gear = 1;\n}</pre>",
				"Methods":"<p>Methods are a set of statements that are executed in order to perform a specific task.</p><p>The have the following properties:<ul><li>Access: set of keywords that define under what conditions the method can be accessed</li><li>Return type: The expected type that is returned when the function is executed</li></ul></p>",
				"Variables":"<p>Variables are used to store the objects current state. Statements can access these values and under some conditions can reassign them</p>",
				"Data Types":{
					"Overview":"<p></p>",
					"Primitive Types":"<p></p>",
					"Object Types":"<p></p>",
				},
				"Control Blocks":"<p></p>",
				"Arrays":"<p></p>",
				"":"<p></p>",
			},"Editor":{
				"Execution":"The Java code is automatically executed after 2 seconds of no typing..."
			}, "File Storage":{
				"Creating A File":"<p>To create a new file, navigate to the <i>File</i> menu and click the + button</p><p>Enter the name of the file to create and choose type of file</p>",
				"Organise Files":"<p>Open the <i>File</i> menu to show the list of files for the current project</p><p>Click the right arrow to view file options which provides two options:</p><p><ul><li>Click file name to rename and press enter to confirm</li><li>Press the X button to delete the file (cannot delete currently open file)</li></ul></p>"
			}},
		init: function(){
			UI.addArrayToList(this.id,["Help"],null,{cls:"thin", noradius:true})
			this.listHelp(null,true)
			UI.addArrayToList(this.id,["Java Libraries"],null,{cls:"thin", append:true, noradius:true})
			this.listFolder("java",true,true)
			UI.addArrayToList(this.id,["Project Classes"],null,{cls:"thin", append:true, noradius:true})
			this.listProject()
			this.saveState()
		},
		listProject: function(){ //lists the current projects classes
			var list = []
			PROG = []
			appendLocalClasses(PROG,CURRENT_PROJECT)
			PROG = _.sortBy(PROG,function(item){return item.name})
			_.each(PROG,function(v){
				list.push('<span class="doc class"></span>'+v.name)
			})
			UI.addArrayToList(this.id,list,"var name = $(this).text();name = name.substr(0,name.length-1);var cls = PROG.each(function (i,item){if(item.name == name) return item});GUI.javaDocs.listClass(cls)"				
			,{cls:'thin', append:true, noradius:true})
		},
		listHelp: function(path,append){ //lists the help topics in a folder
			var obj = this.helpDoc
			if(path) _.each(path.split("."),function(item,k){obj = obj[item]})
			var list = []
			var click = "var name = $(this).text();name = name.substr(0,name.length-1);GUI.javaDocs.listHelp(name)"
			
			if(path) list.push({value:'&lt; '+path.split('.').slice(-1)[0], enable:true, click:"GUI.javaDocs.goBack()"})
			if(typeof obj == 'string') list.push({value:'<span class="javadoc details">'+obj+'</span>', enable:false, click:null})
			else _.each(obj,function(v,k){list.push({value:'<span class="doc help"></span>'+(path?'<span style="display:none">'+path+'.</span>':'')+k, enable:true, click:click})})
			UI.addArrayToList(this.id,list,null,{cls:'thin', append:append, noradius:true})
			this.saveState()
		},
		listFolder: function(folder,append,noback){ //lists the classes in an import folder
			this.currentFolder = folder
			this.objList = []
			var list = []
			var obj = lib
			var parts = folder.split(".")
			parts.each(function(i,item){obj = obj[item]})
			if(obj.is!=null) {list = this.listClass(obj);return;}
			
			var classes= [], folders = []
			_.each(obj,function(item,k){if(item.is!=null) classes.push(k); else folders.push(k)})
			keys = folders.sort().concat(classes.sort())
			
			for(var i = 0; i < keys.length; i++){
				x = keys[i]
				var img = 'class'
				if(obj[x] instanceof J_FOLDER) img = 'folder'
				list.push('<span class="doc '+img+'"></span><span style="font-weight:300">'+folder+'.</span>'+x)
			}
			if(!noback) list.unshift({value:'<span style="font-size:125%;font-weight:500">&lt; '+parts[parts.length-1]+'</span>', enable:true, click:"GUI.javaDocs.goBack()"})
			
			UI.addArrayToList(this.id,list,"var name = $(this).text();name = name.substr(0,name.length-1);GUI.javaDocs.listFolder(name)"
			,{cls:'thin', append:append, noradius:true})
			if(!append) this.saveState()
		},
		listClass: function(cls){ //shows the variables and functions in a class
			this.classTemp.push(cls)
			this.objList.push([])
			var count = 0
			list = [{value:'<span style="font-size:125%;font-weight:500">&lt; '+cls.name+'</span>', enable:true, click:"GUI.javaDocs.goBack()"}]
			var docs = this.processJavaDoc(cls.comment)
			list.push({value:'<span class="javadoc details">'+docs.desc+'</span>', enable:false})
			_.each(cls.vars,function(v){
				if(!v.vis) return;
				GUI.javaDocs.objList.slice(-1)[0].push(v)
				list.push({value:'<span class="doc var"></span>'+v.name,enable:true,click:"GUI.javaDocs.showDetails(GUI.javaDocs.classTemp,false,"+count+")"})
				count++
			})
			_.each(cls.funs,function(f,k){
				if(k == "f_UNSUP") return ;
				for(var i = 0; i < f.length; i++) {
					if(!f[i].vis) continue
					GUI.javaDocs.objList.slice(-1)[0].push(f[i])
					list.push({value:'<span class="doc fun"></span>'+f[i].name+getFunArgs(f[i].args,true)+'</span>', enable:!(f[i].stats[0] && f[i].stats[0].fun == "UNSUP")
						  , click:"GUI.javaDocs.showDetails(GUI.javaDocs.classTemp,true,"+count+")"})
					count++
				}
			})
			UI.addArrayToList(this.id,list,null,{cls:'thin', append:false, noradius:true})
			this.saveState()
		},
		goBack: function(){ //goes back one state in the popup
			this.popupStack.pop()
			var html = this.popupStack[this.popupStack.length-1]
			this.classTemp.pop()
			this.objList.pop()
			$('#'+this.id).html(html)
		},
		saveState: function(){this.popupStack.push($('#'+this.id).html())},
		showDetails: function(cls,f,obj){ //shows a function or variables details
			obj = GUI.javaDocs.objList.slice(-1)[0][obj]
			list = [{value:'&lt; '+obj.name, enable:true, click:"GUI.javaDocs.goBack()"}]
			var docs = this.processJavaDoc(obj.comment)
			list.push({value:'<span class="javadoc details">'+docs.desc[0]+'</span>', enable:false})
			var click = function(){
				var index = GUI.javaDocs.classTemp.length;
				while(index--) if(GUI.javaDocs.classTemp[index]) break;
				var cl = GUI.javaDocs.classTemp[index];
				var c = {name:cl.name,impcls:[],imports:cl.imports,funs:cl.funs,vars:cl.vars};
				PROG=[];
				appendLocalClasses(PROG,CURRENT_PROJECT);
				for(a in lib.java.lang) PROG.push(lib.java.lang[a]);
				importClasses(c);
				GUI.javaDocs.listClass(classSearch(this.innerHTML,clsPack(c)));
			}
			var str = click.toString().replace(/\n/g,"")
			str = str.substring(str.match(/[^\{]*\{/)[0].length)
			str = str.substring(0,str.length-1)
			click = 'onclick="'+str+'"'
			if(f){
				var a = '<span class="javadoc subtitle">Arguments</span><br/><br/>'
				
				
				for(var i = 0; i < obj.args.length; i++){
					a+='<span '+click+' class="doc obj">'+obj.args[i].type+'</span> '+obj.args[i].name+(docs.param['p_'+obj.args[i].name]?'<span class="javadoc param"> - '+docs.param['p_'+obj.args[i].name]+'</span>':'')+'<br/><br/>'
				}
				if(obj.args.length == 0) a+='No arguments required'
				list.push({value:'<span class="javadoc details">'+a+'</span>', enable:false})
				list.push({value:'<span class="javadoc details">returns <span '+click+' class="doc obj">'+obj.type+'</span>'+(docs.return[0]?' <span class="javadoc param"> - '+docs.return[0]+'</span>':'')+'</span>', enable:false})
			}else{
				var a = 'Type: <span '+click+' class="doc obj">'+obj.type+'</span><br/><br/>'
				list.push({value:'<span class="javadoc details">'+a+'</span>', enable:false})
			}
			UI.addArrayToList(this.id,list,null,{cls:'thin', append:false, noradius:true})
			this.saveState()
			this.classTemp.push(null)
			this.objList.push(null)
		},
		processJavaDoc: function(comment){ //parses a java doc comment to create object with appropriate descriptions based on tags
			if(comment == null || comment.charAt(0) != "*") return {desc:["No description provided"], param:{}, author:[], version:[], return:[]}
			
			var result = {desc:[], param:[], author:[], version:[], return:[]}
			var part = ""
			var tag = "desc"
			var lines = comment.split("\n")
			for(var i = 0; i < lines.length; i++){
				var line = lines[i]
				var pre = line.match(/^[ \t]*(\*)?[ \t]*/)
				if(pre) line = line.substring(pre[0].length)
				var t = GUI.javaDocs.getTagType(line)
				if(t.tag){ //new tag defined so save old
					if(!result[tag]) result[tag] = []
					result[tag].push(part)
					part = ""
					tag = t.tag
					line=t.line
				}
				part+=line
			}
			result[tag].push(part)
			
			var param = {}
			for(var i = 0; i < result.param.length; i++){ //reorders param structure
				var name;
				result.param[i] = result.param[i].replace(/^[ \t]*([a-zA-Z0-9][a-zA-Z0-9_]*)/,function (s,a){name = a;return ""})
				if(name) param['p_'+name] = result.param[i]
			}
			result.param = param
			if(result.desc[0].trim() == "") result.desc[0] = "No description provided"
			return result
		},
		getTagType: function(line){ //returns tag name from begining of a line
			var tag;
			line = line.replace(/^@[ \t]*([a-zA-Z]*)/,function (s,a){tag = a;return ""})
			return {tag:tag, line:line}
		}
	},
	SideBar:{
		toggle: function(){
			$('#editor_container').toggleClass('sidebaropen',300)
			$('#content').toggleClass('sidebaropen',300)
			$('#sidebar').toggle('slide',{direction:'right'},300)
			setTimeout(function(){$(window).resize()},700)
		}
	}
}
