var App = {}
if(typeof window === "undefined") App.NodeJS = true
else{
    App.Browser = {OS:navigator.platform, touch:false}
    if($.browser.mozilla) App.Browser.Engine = "moz"
    if($.browser.webkit) App.Browser.Engine = "webkit"
    if('ontouchmove' in window) App.Browser.touch = true
}

App.UI = {}
App.UI.Layout = {}
App.UI.Layout.init = function(page_title){ //set up html for CoreIQ with root page
    document.body.style.overflow = "hidden"
    document.body.style.backgroundColor = "#F0F0F0";
    document.title = page_title
    
    var curtain = document.createElement("div") //semi black curtain for popups/dialogs
    curtain.onclick = function(){
        App.UI.Popup.close()
        App.UI.Dialog.close()
    }
    curtain.id = "curtain"
    var popups = document.createElement("div")
    popups.id = "popup_collect"
    
    $(document.body).append(curtain)
    $(document.body).append(popups)
    
    var root = new App.UI.Layout.Page("root",page_title)
    root.showPage(true)
    App.UI.Layout.RootPage = root
    
    var btn_back = new App.UI.Button("< Back", function(){window.history.back()})
    root.getTaskbar().addButton(btn_back)
    
    return root
}
App.UI.Layout.Page = function(name, page_title){
    var elem = document.createElement("div")
    elem.className = "content"
    elem.id = "page_"+name
    elem.style.display = "none"
    elem.style.left = "100%"
    
    var data = document.createElement("div")
    data.className = "content_data"
    elem.appendChild(data)
    
    var bottom_bars = document.createElement("div")
    bottom_bars.className = "bottom_bars"
    elem.appendChild(bottom_bars)
    
    var taskbar_create = function(btm){ 
        var bar = document.createElement("div")
        var title
        if(!btm){
            bar.id = "taskbar"
            bar.innerHTML = "&nbsp;"
            title = document.createElement("div")
            title.id = "task_title_div"
            title.innerHTML = (page_title?page_title:"")
            $(bar).append(title)
        }else bar.className = "bottombar"
        
        var rightBtns = document.createElement("div")
        rightBtns.id = "taskbar_right"
        rightBtns.style.cssFloat = "right"
        $(bar).append(rightBtns)
        
        var visible = false
        
        return {
            show:function(){$(bar).show(); if(bar.className != "bottombar") data.className = "content_data"},
            hide:function(){$(bar).hide(); if(bar.className != "bottombar") data.className = "content_data nobar"},
            get:function(){return bar},
            addButton:function(btn,right,prepend){
                if(btm) $(btn.get()).addClass("find")
                else $(btn.get()).removeClass("find")
                
                if(right) $(rightBtns).prepend(btn.get())
                else {
                    if(prepend) $(bar).prepend(btn.get())
                    else $(bar).append(btn.get())
                }
                return this
            },
            addTextfield:function(tf,right){
                if(right) $(rightBtns).prepend(tf.get())
                else $(bar).append(tf.get())
            },
            addLabel:function(l,right){
                if(right) $(rightBtns).prepend(l.get())
                else $(bar).append(l.get())
            },
            changeTitle:function(t){return this.setTitle(t)},
            setTitle:function(t){if(title) title.innerHTML = t; return this},
            linkToButton:function(btn){
                btn.changeClick(function(){$(bar).slideToggle(150)})
            },
        }
    }
    var taskbar = taskbar_create()
    
    $(elem).append(taskbar.get())
    $(document.body).prepend(elem)
    
    var back, visible = false
    if($(".content").length == 1) back = true
    
    var page = this
    this.get = function(){return elem}
    this.getTaskbar = function(){return taskbar},
    this.addBottomBar = function(){
        var btm = taskbar_create(true)
        bottom_bars.appendChild(btm.get())
        return btm
    }
    this.display = function(){elem.style.display = "block"}
    this.hide = function(){elem.style.display = "none"}
    this.showPage = function(noanim){
        if(visible) alert("Page already displayed ")
        elem.style.display = "block"
        if(!back){
            back = new App.UI.Button("Back",function(){page.closePage()})
            taskbar.addButton(back,false,true)
        }
        
        $(".content:visible").each(function(i,item){
            var w = this.style.left || "0%"
            w = parseInt(w.substring(-1))
            w -= 100
            if(noanim) this.style.transition = "left 0s"
            else this.style.transition = "left 0.7s "
            
            item.style.left = w + "%"
        })
        
        if(noanim) elem.style.transition = "left 0s"
        else elem.style.transition = "left 0.7s "
        
        visible = true
        elem.style.left = "0%"
        setTimeout(function(){$(window).resize()}, 100)
    }
    this.closePage = function(noanim){
        $(".content:visible").each(function(i,item){
                var w = this.style.left || "0%"
                w = parseInt(w.substring(-1))
                w += 100
                //if(noanim) this.style.transition = "left 0s"
                //else this.style.transition = "left 0.7s "
                item.style.left = w + "%"
        })
        setTimeout(function (){page.hide();visible=false}, 700)
    }
    this.linkToButton = function(btn){
        btn.changeClick(function(){page.showPage()})
    }
    this.addElement = function(e){
        return this.addComponent(e)
    }
    this.addComponent = function(e){
        data.appendChild(e.get())
        $(window).resize()
        return this
    }
    this.appendHTML = function(html){
        data.innerHTML += html
        return this
    }
    this.appendChild = function(child){
        data.appendChild(child)
        return this
    }
    this.clear = function(){data.innerHTML = ""}
    this.setBackground = function(color){data.style.backgroundColor = color.toString(); return this}
    this.setBackgroundImage = function(url){
	    data.style.backgroundImage = "url('"+url+"')"
	    data.style.backgroundSize = "contain"
	    data.style.backgroundRepeat ="no-repeat"
	    data.style.backgroundPosition = "center"
	    return this
	}
    this.deleteComponent = function (obj) {
     	data.removeChild(obj.get())
     }
    this.bind = function(type,f,args){
        elem["on"+type] = function(event){
            event.preventDefault()
            event.stopPropagation()
            f(event,args)
        }
    }
    
}
App.UI.Button = function(text,click,color){
    var type = 0
    if(typeof text == "function"){color = click; click = text; text = null}
    if(click instanceof App.Color || typeof click == "number") {color = click; click = null}
    if(typeof color == "number"){type = color; color = null}
    
    var container = new App.UI.Component()
    container.setSize("","")
    var elem = document.createElement("button")
    if(type == 0) elem.className = "task display"
    
    elem.innerHTML = text
    container.appendChild(elem)
    
    var btn = this
    this.getText = function(){return text},
    this.get = function(){return container.get()},
    this.changeClick = function(click){elem.onclick = function(event){click(btn,event)}},
    this.changeText = function(t){text=t;elem.innerHTML = text},
    this.changeColor = function(color){//background-image: -moz-linear-gradient(top,lightgreen,limegreen,green);
        elem.style.backgroundImage="-"+App.Browser.Engine+"-linear-gradient(top,"+color.lighten().toString()+","+color.toString()+","+color.darken().toString()+")"
    }
    this.disable = function(){container.setOpacity(0.5);  elem.disabled = "disabled"},
    this.enable = function(){container.setOpacity(1); elem.disabled = null}
    
    this.setHeight = function(h){
        if(typeof h == "number") elem.style.height = h+"px"
        else elem.style.height = h
        return this
    }
    this.setSize = function(w,h){
        this.setWidth(w); this.setHeight(h);
        container.setSize(w,h)
        return this
    }
    this.setWidth = function(h){
        if(typeof h == "number") elem.style.width = h+"px"
        else elem.style.width = h
        return this
    }
    this.setBackgroundImage = function(img){
        elem.style.backgroundSize = "100% 100%"
        elem.style.backgroundImage = "url('"+img+"')"
        elem.className = ""
        return this
    }
    
    this.extendWith(container)
        
    if(!color) color = App.Color.Gray
    if(type == 0) this.changeColor(color)
    else if(type == 2){
    	container.get().className = "bigitem bottom top btn blue"
    }
    if(click) this.changeClick(click)
}
App.UI.Textfield = function(text,change){//<input type="text" onkeyup="UI_REG=this.value;updateOverlay();"/>
    if(text == null) text = ""
    if(typeof text == "function"){change=text, text = null}
    
    var field = this
    var div = document.createElement("div")
    div.style.display = "inline-block"
    div.style.marginRight = "-10px"
    var elem = document.createElement("input")
    elem.className = "textfield"
    elem.type = "text"
    
    elem.value = text
    elem.style.paddingRight = "25px"
    div.appendChild(elem)
    
    var del = document.createElement('button')
    del.className = "deletebtn"
    del.innerHTML="x"
    del.tabIndex = -1
    $(del).bind('click',function (e){$(elem).val("");$(elem).trigger('keyup');$(elem).trigger('change');$(elem).focus()})
    $(div).append(del)
    
    this.get = function(){return div},
    this.getText = function(){return elem.value},
    this.changeKeyup = function(click){elem.onkeyup = function(event){change(field,event)}; return this},
    this.setText = function(t){elem.value = text; return this},
    this.disable = function(){elem.disabled = "disabled", del.disabled = "disabled"},
    this.enable = function(){$(elem).removeAttr("disabled");$(del).removeAttr("disabled")}
    this.focus = function(){elem.focus()}
    
    if(change) this.changeKeyup(change)
}
App.UI.Component = function(){
    var elem = document.createElement("div")
    elem.className = "component"
    
    var visible = true, component = this, children = [], properties = {}, aspect

    $(window).resize(function(){
        if(aspect == null) return;
        
        var width = $(elem).width()
        var height = Math.min(width*aspect,$(window).height())
        $(elem).height(height)
    })
    //METHODS
    this.get = function(){return elem}
    this.setSpan = function(a){elem.style.width = a/12*100+"%"; return this}
    this.setAbsolute = function(a){
        if(a) elem.style.position = "absolute"
        else elem.style.position = "block"
        return this
    }
    this.setPosition = function(top, left, bottom, right){
        elem.style.top = top; elem.style.bottom = bottom
        elem.style.left = left; elem.style.right = right
        return this
    }
    this.setMargin = function(top, left, bottom, right){
        elem.style.marginTop = top; elem.style.marginBottom = bottom
        elem.style.marginLeft = left; elem.style.marginRight = right
        return this
    }
    this.setHeight = function(h){
        if(typeof h == "number") elem.style.height = h+"px"
        else elem.style.height = h
        return this
    }
    this.setSize = function(w,h){
        this.setWidth(w); this.setHeight(h)
        return this
    }
    this.setWidth = function(h){
        if(typeof h == "number") elem.style.width = h+"px"
        else elem.style.width = h
        return this
    }
    this.setFullscreen = function(full){
        if(full) elem.style.height = "100%"
        else elem.style.height = ""
        return this
    }
    this.setPadding = function(top, bottom, left, right){
        if(bottom == null && left == null && right == null) elem.style.padding = top
        else if(left == null && right == null) elem.style.padding = top + " " + bottom
        else {
            elem.style.paddingTop = top; elem.style.paddingBottom = bottom
            elem.style.paddingLeft = left; elem.style.paddingRight = right
        }
        return this
    }
    this.setAlign = function(align){
        if(align == 0) elem.style.textAlign = "left"
        else if(align == 1) elem.style.textAlign = "center"
        else elem.style.textAlign = "right"
        return this
    }
    this.setVerticalAlign = function(align){
        if(align == 0) elem.style.verticalAlign = "top"
        else if(align == 1) elem.style.verticalAlign = "middle"
        else elem.style.textAlign = "bottom"
        return this
    }
    this.setColor = function(color){elem.style.color = color.toString(); return this}
    this.setBackground = function(color){elem.style.backgroundColor = color.toString(); return this}
    this.setBackgroundImage = function(img){elem.style.backgroundImage = "url('"+img+"')"; return this}
    this.setFont = function(f, s, w){elem.style.fontFamily = f; elem.style.fontSize = s; elem.style.fontWeight = w; return this}
    this.setFontSize = function(s){elem.style.fontSize = s; return this}
    this.setBlock = function(block){
        if(block) elem.style.display = "block"
        else elem.style.display = "inline-block"
        return this
    }
    this.setAutoSize = function(){this.setSize("",""); return this}
    this.setOpacity = function(op){if(op != null) elem.style.opacity = op; return elem.style.opacity}
    
    this.addHTML = function(html,truncate){if(truncate) elem.innerHTML = ""; elem.innerHTML += html; return this}
    this.clear = function(){elem.innerHTML = ""; return this}
    this.appendChild = function(child){children.push(child); elem.appendChild(child); return this}
    this.addComponent = function(comp){elem.appendChild(comp.get()); return this}
    this.show = function(){elem.style.display = "inline-block"; return this}
    this.hide = function(){elem.style.display = "none"; return this}
    this.toggle = function(){
        if(visible) elem.style.display = "none"
        else elem.style.display = "inline-block"
        visible = !visible
        return this
    }
    this.opacity = function(op){if(op != null) elem.style.opacity = op; return elem.style.opacity} //decreped
    this.isVisible = function(){return visible}
    this.bind = function(type,f,args){
        elem["on"+type] = function(event){
            event.preventDefault()
            event.stopPropagation()
            f(component,event,args)
        }
    }
    this.setClass = function(name){elem.className = "component "+name; return this}
    this.setProperty = function(prop, value){properties[prop] = value; return this}
    this.getProperty = function(prop){return properties[prop]}
    this.clear = function(){elem.innerHTML = ""; return this}
    this.getX = function(){return elem.offsetLeft}
    this.getY = function(){return elem.offsetTop}
    this.enableScrolling = function(){elem.style.maxHeight = "100%"; elem.style.overflowY = "auto";elem.style.overflowX = "none"; return this;}
    this.deleteComponent = function (obj) {
    	elem.removeChild(obj.get())
    }
    this.setAspectRatio = function(a){aspect = 1/a; $(window).resize(); return this}
    
    this.setSpan(12); this.setFullscreen(true)
}
App.UI.Component.fromHTMLById = function(id){
    var comp = new App.UI.Component()
    comp.addHTML(document.getElementById(id).innerHTML)
    return comp
}
App.UI.Editor = function(text){
    var HIGHLIGHTS,SELECT_ST = 0, SELECT_EN = 0;
    var FONT_WIDTH = 18
    var PATTERNS = []
    var updateOverlay = function (elem){
        if(!elem) elem = editor
        var code = elem.value
        var over = ""
        var last = 0
        HIGHLIGHTS=[]
        
        PATTERNS.each(function(i,item){
            var reg = item.getRegex()
            if(typeof reg == "function") reg = reg()
            if (reg.source == "") return;
            var col = item.getTextColor()
            var high = item.getHighlightColor()
            customMatch(code,reg,"<font style='"+(col?("color: "+col.toString()+";"):"")+(high?("background-color: "+high.toString()+";"):"")+"'>","</font>")
        })
        
        HIGHLIGHTS.each(function (i,item){
                var parts = code.substring(last,item.st).replace(/\</g,"&lt;").replace(/\>/g,"&gt;")
                over+=parts+item.a+code.substr(item.st,item.len).replace(/\</g,"&lt;").replace(/\>/g,"&gt;")+item.b
                last = item.st+item.len
        })
        over+=code.substring(last).replace(/\</g,"&lt;").replace(/\>/g,"&gt;")
        color.innerHTML = over.replace(/\t/g,(" ").repeat(8)).replace(/ /g," ")+"<br>"
        editor.style.height = $(color).height()+22+"px"
        addLineNum(code)
    }
    var addLineNum = function(code){
        var UI_LINE=1
        var UI_LINE_HTML=""
        var lines=code.split("\n")
        var fold = Math.floor(($(editor).width() )/FONT_WIDTH)
        var chs = 0;
        lines.each(function (i,item){
                var txt = item.replace(/\t/g,(" ").repeat(8)).splitN(fold)
                UI_LINE_HTML+=UI_LINE.toString().pad(3,"&nbsp;",true)+"<br>"
                for(var j = 0; j < txt.length-1; j++){
                        UI_LINE_HTML+="&nbsp;&nbsp;&nbsp;<br>"
                }
                chs++
                UI_LINE++
        })
        lines_div.innerHTML = UI_LINE_HTML
    }
    var customMatch = function(text,r,a,b,arr){
        var tmp = text.searchAll(r,a,b);
        tmp.each(function (i,item){
                addToHigh(item)
                if(arr!=null) arr.push(item)
        })
    }
    var addToHigh = function(elem){
        var done;
        for(var i = 0; i < HIGHLIGHTS.length; i++){
                var item = HIGHLIGHTS[i]
                if(elem.st <= item.st){
                        if(elem.st==item.st && elem.len==item.len) HIGHLIGHTS.splice(i,1,elem)
                        else HIGHLIGHTS.splice(i,0,elem)
                        done=i;
                        break;
                }else if(item.st+item.len>=elem.st) {
                        item.len=elem.st-item.st
                        var str=item.str.substring(item.len+elem.len)
                        item.str=item.str.substring(0,item.len)
                        if(elem.st+item.len+str.length > elem.st+elem.len) { //highlight adding is in the middle of another
                                HIGHLIGHTS.splice(i+1,0,elem,{st:elem.st+elem.len,len:str.length,str:str,a:item.a, b:item.b})
                                done=i;
                                break;
                        }
                }
        }
        if(done==null) {HIGHLIGHTS.push(elem);done=HIGHLIGHTS.length-1}
        
        for(var i = done+1; i < HIGHLIGHTS.length; i++){ //merges the matches together
                item = HIGHLIGHTS[i]
                if(elem.st+elem.len> item.st) { //highlight adding is in the middle of another
                        item.len=elem.st-item.st
                        var str=item.str.substring(item.len+elem.len)
                        item.str=item.str.substring(0,item.len)
                        var alt = {st:elem.st+elem.len,len:str.length,str:str,a:item.a, b:item.b}
                        HIGHLIGHTS.splice(i,1,alt)
                }else break
        }
    }   
    
    if(!text) text = ""
    
    var container = new App.UI.Component()
    container.setSpan(12)
    container.setFullscreen(true)
    container.enableScrolling(true)
    
    var editor = document.createElement("textarea")
    editor.wrap = "hard"
    editor.autocapitalize = "off"
    editor.autocorrect = "off"
    editor.spellcheck = "false"
    editor.innerHTML = text
    editor.className = "editor"
    if(navigator.appCodeName == "Mozilla" && navigator.vendor != "Google Inc.") $(editor).css({left:-2, top:-2})
    editor.onkeyup = function(){
        updateOverlay(editor)
    }
    editor.onkeydown = function(e){
        if(e.which == 13) editor.style.height = $(editor).height()+50+"px"
    }
    container.appendChild(editor)
    
    var color = document.createElement("div")
    color.className = "code"
    container.appendChild(color)
    
    var lines_div = document.createElement("div")
    lines_div.className = "lines"
    container.appendChild(lines_div)
    
    var edit = this
    this.get = function(){return container.get()},
    this.getText = function(){return editor.value},
    //this.changeKeyup:function(click){elem.onclick = click},
    this.setText = function(t){editor.value = t; updateOverlay(); return this;},
    this.addPattern = function(pattern){PATTERNS.push(pattern);updateOverlay(editor); return this},
    this.refresh = function(){updateOverlay(editor); return this;},
    this.setColor = function(col){editor.style.color = col.toString(); color.style.color = col.toString(); updateOverlay(); return this;},
    this.setBackground = function(col){editor.style.backgroundColor = col.toString(); return this;},
    this.disable = function(){editor.disabled = "disabled"; color.style.opacity = 0.7; editor.style.opacity = 0.2; return this},
    this.enable = function(){editor.disabled = ""; color.style.opacity = 1; editor.style.opacity = 1; return this},
    this.bind = function(type,f,args){
        editor["on"+type] = function(event){
            event.preventDefault()
            event.stopPropagation()
            f(edit,event,args)
        }
    }
    this.setFontsize = function(s){
	FONT_WIDTH = s - 2
	editor.style.fontSize = s + "px";
	color.style.fontSize = s + "px";
	lines_div.style.fontSize = s + "px";
	updateOverlay();
	return this;
    }
    
    this.extendWith(container)
    
    updateOverlay(editor)
}
App.UI.Editor.Pattern = function(reg,color,highlight){
    this.getRegex = function(){return reg},
    this.getTextColor = function(){return color},
    this.getHighlightColor = function(){return highlight}
}

App.Color = function(r,g,b,a){
    this.r = r; this.g = g; this.b = b; this.a = a
    this.toString = function(){return "rgba("+this.r+","+this.g+","+this.b+","+this.a/255+")"}
    this.lighten = function(){return new this.constructor(Math.min(this.r+50,255), Math.min(this.g+50,255), Math.min(this.b+50,255), this.a)}
    this.darken = function(){return new this.constructor(Math.min(this.r-50,255), Math.min(this.g-50,255), Math.min(this.b-50,255), this.a)}
}
App.Color.Red = new App.Color(255,40,40,255)
App.Color.Green = new App.Color(50,204,50,255)
App.Color.Blue = new App.Color(0,191,255,255)
App.Color.Gray = new App.Color(105,105,105,255)
App.Color.Orange = new App.Color(255,204,51,255)
App.Color.White = new App.Color(255,255,255,255)
App.Color.Black = new App.Color(0,0,0,255)
App.Color.Transparent = new App.Color(0,0,0,0)

App.UI.Layout.Align = {}
App.UI.Layout.Align.LEFT = 0
App.UI.Layout.Align.CENTER = 1
App.UI.Layout.Align.RIGHT = 2

App.UI.Button.MOBILE = 0
App.UI.Button.CUSTOM = 1
App.UI.Button.BIGITEM = 2

App.KeyCode = {ENTER:13}