
// PARSING
//---------------------------------------------------------------

//  Graph plotter function take from 
//  From http://blog.hvidtfeldts.net/index.php/2011/07/plotting-high-frequency-functions-using-a-gpu/
var preFunction = "\n\
#ifdef GL_ES\n\
precision mediump float;\n\
#endif\n\
\n\
#define PI 3.14159265359\n\
\n\
uniform vec2 u_resolution;\n\
uniform vec2 u_mouse;\n\
uniform float u_time;\n\
\n\
float lineJitter = 0.5;\n\
float lineWidth = 7.0;\n\
float gridWidth = 1.7;\n\
float scale = 0.0013;\n\
float zoom = 2.5;\n\
vec2 offset = vec2(0.5);\n\
\n\
float rand (in float _x) {\n\
    return fract(sin(_x)*1e4);\n\
}\n\
\n\
float rand (in vec2 co) {\n\
    return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453);\n\
}\n\
\n\
float noise (in float _x) {\n\
    float i = floor(_x);\n\
    float f = fract(_x);\n\
    float u = f * f * (3.0 - 2.0 * f);\n\
    return mix(rand(i), rand(i + 1.0), u);\n\
}\n\
\n\
float noise (in vec2 _st) {\n\
    vec2 i = floor(_st);\n\
    vec2 f = fract(_st);\n\
    // Four corners in 2D of a tile\n\
    float a = rand(i);\n\
    float b = rand(i + vec2(1.0, 0.0));\n\
    float c = rand(i + vec2(0.0, 1.0));\n\
    float d = rand(i + vec2(1.0, 1.0));\n\
    vec2 u = f * f * (3.0 - 2.0 * f);\n\
    return mix(a, b, u.x) + \n\
            (c - a)* u.y * (1.0 - u.x) + \n\
            (d - b) * u.x * u.y;\n\
}\n\
\n\
float function(in float x) {\n\
    float y = 0.0;\n";

var postFunction = "\n\
    return y;\n\
}\n\
\n\
vec3 plot2D(in vec2 _st, in float _width ) {\n\
    const float samples = 3.0;\n\
\n\
    vec2 steping = _width*vec2(scale)/samples;\n\
    \n\
    float count = 0.0;\n\
    float mySamples = 0.0;\n\
    for (float i = 0.0; i < samples; i++) {\n\
        for (float j = 0.0;j < samples; j++) {\n\
            if (i*i+j*j>samples*samples) \n\
                continue;\n\
            mySamples++;\n\
            float ii = i + lineJitter*rand(vec2(_st.x+ i*steping.x,_st.y+ j*steping.y));\n\
            float jj = j + lineJitter*rand(vec2(_st.y + i*steping.x,_st.x+ j*steping.y));\n\
            float f = function(_st.x+ ii*steping.x)-(_st.y+ jj*steping.y);\n\
            count += (f>0.) ? 1.0 : -1.0;\n\
        }\n\
    }\n\
    vec3 color = vec3(1.0);\n\
    if (abs(count)!=mySamples)\n\
        color = vec3(abs(float(count))/float(mySamples));\n\
    return color;\n\
}\n\
\n\
vec3 grid2D( in vec2 _st, in float _width ) {\n\
    float axisDetail = _width*scale;\n\
    if (abs(_st.x)<axisDetail || abs(_st.y)<axisDetail) \n\
        return 1.0-vec3(0.65,0.65,1.0);\n\
    if (abs(mod(_st.x,1.0))<axisDetail || abs(mod(_st.y,1.0))<axisDetail) \n\
        return 1.0-vec3(0.80,0.80,1.0);\n\
    if (abs(mod(_st.x,0.25))<axisDetail || abs(mod(_st.y,0.25))<axisDetail) \n\
        return 1.0-vec3(0.95,0.95,1.0);\n\
    return vec3(0.0);\n\
}\n\
\n\
void main(){\n\
    vec2 st = (gl_FragCoord.xy/u_resolution.xy)-offset;\n\
    st.x *= u_resolution.x/u_resolution.y;\n\
\n\
    scale *= zoom;\n\
    st *= zoom;\n\
\n\
    vec3 color = plot2D(st,lineWidth);\n\
    color -= grid2D(st,gridWidth);\n\
\n\
    gl_FragColor = vec4(color,1.0);\n\
}";

/*
 *	Fetch for files
 */
function fetchHTTP(url, methood) {
	var request = new XMLHttpRequest(), response;

	request.onreadystatechange = function () {
		if (request.readyState === 4 && request.status === 200) {
			response = request.responseText;
		}
	}
	request.open(methood ? methood : 'GET', url, false);
    request.overrideMimeType("text/plain");
	request.send(null);
	return response;
}

function randomString(length, chars) {
    var mask = '';
    if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz';
    if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    if (chars.indexOf('#') > -1) mask += '0123456789';
    if (chars.indexOf('!') > -1) mask += '~`!@#$%^&*()_+-={}[]:";\'<>?,./|\\';
    var result = '';
    for (var i = length; i > 0; --i) result += mask[Math.round(Math.random() * (mask.length - 1))];
    return result;
}

var billboards = {}; 
function loadMarkdown() {

    // parse CODE & CANVAS boxes
	var ccList = document.querySelectorAll(".codeAndCanvas");
    var id = "", 
        srcFile= "",
        str = ""
        imagesFiles = "",
        inject = "";

    var imgCounter = 0;
	for(var i = 0; i < ccList.length; i++){
		if (ccList[i].hasAttribute("data")){
			id = randomString(16, '#aA');
			srcFile = ccList[i].getAttribute("data");
            
            // load code
            str = fetchHTTP(srcFile);
            inject = '<div class="editor">\
            <canvas id ='+id+' class="canvas" data-fragment-url="'+srcFile+'" ';

            // load images
            imagesFiles = ccList[i].getAttribute("data-imgs");
            imgCounter = 0;
            if ( imagesFiles ){
                var imgUrls = imagesFiles.split('&');
                for(var j in imgUrls){
                    var ext = imgUrls[j].substr(imgUrls[j].lastIndexOf('.') + 1);
                    if (ext == "png" || ext == "jpg" || ext == "PNG" || ext == "JPG" ){
                        if(imgCounter === 0){
                            inject += 'data-textures="'
                        } else {
                            inject += ",";
                        }
                        inject += imgUrls[j];
                        imgCounter++;
                    }
                }
                if (imgCounter !== 0){
                    inject += '" ';
                }
            } 
            inject += ' width="250px" height="250px"></canvas>\
			</div>';

            // inject the code
            ccList[i].innerHTML = inject;

            // wakeup the code editor
			var demoEditor = ccList[i].getElementsByTagName("div");
			if(demoEditor[0]){
				var editor = CodeMirror(demoEditor[0],{
					value: str,
					viewportMargin: Infinity,
					lineNumbers: true,
					matchBrackets: true,
					mode: "x-shader/x-fragment",
					keyMap: "sublime",
					autoCloseBrackets: true,
					extraKeys: {"Ctrl-Space": "autocomplete"},
					showCursorWhenSelecting: true,
                    lineWrapping: true,
                    indentUnit: 4
				});

				editor.id = id;

                editor.on("cursorActivity", function(cm) {
                    var canvasToChange = document.getElementById(cm.id);
                    var height = cm.heightAtLine(cm.getCursor().line+1,'local')-canvasToChange.height;
                    if (height<0){
                        height = 0.0;   
                    }
                    canvasToChange.style.top = (height).toString()+"px";
                });

				editor.on("change", function(cm, change) {
					billboards[cm.id].load(cm.getValue());
                    billboards[cm.id].render(true);
				});
			}
		}
	}

    // parse Simple FUNCTIONS
    var fList = document.querySelectorAll(".simpleFunction");
    for(var i = 0; i < fList.length; i++){
        if (fList[i].hasAttribute("data")){
            id = randomString(16, '#aA');
            var funct = fList[i].getAttribute("data");
  
            // compose glslCanvas
            fList[i].innerHTML = '<div class="function">\
            <canvas id ='+id+' class="canvas" data-fragment="'+preFunction+funct+postFunction+'" width="800px" height="240px" ></canvas>\
            </div>\
            <p class="caption">Graph plotter by <a href="http://blog.hvidtfeldts.net/index.php/2011/07/plotting-high-frequency-functions-using-a-gpu/">Mikael Hvidtfeldt Christensen</a> (2011)<p>';

            // wakeup the code editor
            var demoEditor = fList[i].getElementsByTagName("div");
            if(demoEditor[0]){
                var editor = CodeMirror(demoEditor[0],{
                    value: funct,
                    viewportMargin: Infinity,
                    lineNumbers: false,
                    matchBrackets: true,
                    mode: "x-shader/x-fragment",
                    keyMap: "sublime",
                    autoCloseBrackets: true,
                    extraKeys: {"Ctrl-Space": "autocomplete"},
                    showCursorWhenSelecting: true,
                    indentUnit: 4
                });
                editor.id = id;

                editor.on("change", function(cm, change) {
                    billboards[cm.id].load(preFunction+cm.getValue()+postFunction);
                    billboards[cm.id].render(true);
                });
            }
        }
    }

	// Load codes tags that have "src" attributes
	var list = document.getElementsByTagName("code");
	for(var i = 0; i < list.length; i++){
		if (list[i].className == "language-glsl" || 
			list[i].className == "language-bash" || 
			list[i].className == "language-cpp" || 
			list[i].className == "language-html" ||
            list[i].className == "language-processing" ){
			hljs.highlightBlock(list[i]);
		}
	}
}

function loadCanvas() {
    var canvas = document.getElementsByClassName("canvas");
    for (var i = 0; i < canvas.length; i++){
        if (canvas[i].id === "custom") {
            canvas[i].id = randomString(16, '#aA');
        }
        billboards[canvas[i].id] = new GlslCanvas(canvas[i]);
    }       
}

function insertAfter(newElement,targetElement) {
    var parent = targetElement.parentNode;
    if (parent.lastChild == targetElement) {
        parent.appendChild(newElement);
    } else {
        parent.insertBefore(newElement,targetElement.nextSibling);
    }
}

function captionizeImages() {
    if (!document.getElementsByTagName) 
        return false;

    if (!document.createElement) 
        return false;
    
    var images = document.getElementsByTagName("img");
    if (images.length < 1) 
        return false; 

    for (var i=0; i<images.length; i++) {
        var title = images[i].getAttribute("alt");

        if (title != ""){
            var divCaption = document.createElement("div");
            divCaption.className = "caption";
            var divCaption_text = document.createTextNode(title);
            divCaption.appendChild(divCaption_text);
            var divContainer = document.createElement("div");
            divContainer.className="imgcontainer";
            images[i].parentNode.insertBefore(divContainer,images[i]);
            divContainer.appendChild(images[i]);
            insertAfter(divCaption,images[i]);
        }
    }
}

// NAVIGATION
//-----------------------------------------------------------------------

function FormatNumberLength(num, length) {
    var r = "" + num;
    while (r.length < length) {
        r = "0" + r;
    }
    return r;
}

function checkUrl(url) {
    var request = false;
    if (window.XMLHttpRequest) {
            request = new XMLHttpRequest;
    } else if (window.ActiveXObject) {
            request = new ActiveXObject("Microsoft.XMLHttp");
    }

    if (request) {
            request.open("GET", url);
            if (request.status == 200) { return true; }
    }

    return false;
}

function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

function previusPage() {
	var path = window.location.pathname;

	var n = parseInt( path.match( /[0-1].(?!.*[0-1])/ )[0] );
    var url;
	n -= 1;
    if(n < 0){
        url = "../";
    } else {
        url = "../" + FormatNumberLength(n,2) + "/";
    }

    var language = getParameterByName('lan');
    if (language !== ""){
        url += "?lan="+language;
    }

	window.location.href =  url;
}

function homePage() {
	window.location.href = "../";
}

function nextPage() {
	var path = window.location.pathname;

	var n = parseInt( path.match( /[0-1].(?!.*[0-1])/ )[0] );
	n += 1;
	var url = "../" + FormatNumberLength(n,2) + "/";

    var language = getParameterByName('lan');
    if (language !== ""){
        url += "?lan="+language;
    }

	window.location.href =  url;
}

function translate() {

}

/**
 * Provides requestAnimationFrame in a cross browser way.
 */
window.requestAnimFrame = (function() {
    return  window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
                return window.setTimeout(callback, 1000/60);
         };
})();

/**
 * Provides cancelRequestAnimationFrame in a cross browser way.
 */
window.cancelRequestAnimFrame = (function() {
    return  window.cancelCancelRequestAnimationFrame ||
            window.webkitCancelRequestAnimationFrame ||
            window.mozCancelRequestAnimationFrame ||
            window.oCancelRequestAnimationFrame ||
            window.msCancelRequestAnimationFrame ||
            window.clearTimeout;
})();

window.onload = function(){
	loadMarkdown();
    captionizeImages();

    loadCanvas();
};
