var debug = true;

function $(id) { return document.getElementById(id); }
function trim(str) { return str.replace("/^\s\s*/", '').replace("/\s\s*$/", ''); }
function valid(str) { if (str==undefined) return false; if (str.length==0) return false; return true;}
function isSliding() { var z = $("body").getAttribute("data-visible"); return $("table"+z).offsetLeft!=0; }

function cycleCol(el)
{
    var col = el.getAttribute("data-color");
    col++;
    col %= 31;
    el.setAttribute("data-color", col);
    if (col>16)
        col = 31-col;
    var hex = col.toString(16);
    el.style.color = "#"+hex+"0"+hex+"0"+hex+"f";
}

function onload()
{
    try { xmlHttp = new XMLHttpRequest(); }
    catch(e)
    {
        alert("Your browser doesn't support dynamic reload.");
        return;
    }

    /*
     alert("0 -- "+navigator.appCodeName+"\n"+
          "1 -- "+navigator.appName+"\n"+
          "2 -- "+navigator.appVersion+"\n"+
          "3 -- "+navigator.platform+"\n"+
          "4 -- "+navigator.userAgent);
          */
    loadPage("fact", 0, 0);
}

function onresize()
{
    var z = $("body").getAttribute("data-visible");
    doresize(z);
}

function loadPage(name, z, dz)
{
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open('POST', name+'.table', true);
    xmlHttp.onload = function ()
    {
        if (xmlHttp.status!=200)
        {
            alert("ERROR[0] - HTTP request '"+name+".table': "+xmlHttp.statusText+" ["+xmlHttp.status+"]");
            //setTimeout("loadPage('+name+')", 5000);
            /****** invalidate ******/
            return;
        }

        buildPage(name, xmlHttp.responseText, z, dz);
        changePage(z, z+dz);

        //changePage(name, xmlHttp.resposeText);
        //slideOut(name, xmlHttp.responseText);
        //displayPage(name, xmlHttp.responseText);
            //onresize(true);
    };

    xmlHttp.send(null);
}


function buildPage(name, text, oldz, dz)
{
    var fname = dz==0 ? "fact" : $("table"+oldz).getAttribute("data-file");

    var z = oldz + dz;

    var lines = text.split('\n');

    if (lines.length==0)
    {
        alert("buildPage - received data empty.");
        return;
    }

    var table = $("table"+z);
    if (table != undefined)
        $("body").removeChild(table);

    table = document.createElement("table");
    table.setAttribute("class",       "tborder");
    table.setAttribute("id",          "table"+z);
    table.setAttribute("border",      "0");
    table.setAttribute("cellspacing", "0");
    table.setAttribute("cellpadding", "6");
    table.setAttribute("width",       "100%");
    table.setAttribute("style",       "overflow:hidden;position:fixed;top:0px;left:"+window.innerWidth+"px;");

    // -----------------------------------------------------

    var th = document.createElement("thead");
    th.setAttribute("colspan", "3");
    th.setAttribute("width",   "100%");
    table.appendChild(th);

    var htr = document.createElement("tr");
    th.appendChild(htr);

    var htd = document.createElement("td");
    htd.setAttribute("class",   "thead");
    htd.setAttribute("colspan", "3");
    htd.setAttribute("width",   "100%");
    htr.appendChild(htd);

    // -------------

    var htab = document.createElement("table");
    htab.setAttribute("width", "100%");
    htd.appendChild(htab);

    var hhtr = document.createElement("tr");
    htab.appendChild(hhtr);

    var htd0 = document.createElement("td");
    var htd1 = document.createElement("td");
    var htd2 = document.createElement("td");
    var htd3 = document.createElement("td");
    htd0.setAttribute("class", "tcell1");
    htd1.setAttribute("class", "tcell2");
    htd2.setAttribute("class", "tcell1");
    htd2.setAttribute("width", "1px");
    htd3.setAttribute("class", "tcell1");
    htd3.setAttribute("width", "1px");
    hhtr.appendChild(htd3);
    hhtr.appendChild(htd0);
    hhtr.appendChild(htd1);
    hhtr.appendChild(htd2);

    var div0 = document.createElement("div");
    var div1 = document.createElement("div");
    var div2 = document.createElement("div");
    var div3 = document.createElement("div");
    div0.setAttribute("style", "font-size:x-large;");
    div2.setAttribute("class", "icon_white");
    div2.setAttribute("onclick","this.style.backgroundColor='rgba(0,0,0,0.77)'; loadPage('"+fname+"',"+z+","+(-dz)+");");
    div2.setAttribute("style", "background-position:-396px 50%;");
    div3.setAttribute("class", "icon_white");
    div3.setAttribute("onclick","this.style.backgroundColor='rgba(0,0,0,0.77)'; loadPage('fact',"+z+","+(-z)+");");
    div3.setAttribute("style", "background-position:-575px 50%;");

    var sp0 = document.createElement("span");
    var sp1 = document.createElement("span");
    var sp2 = document.createElement("span");
    sp0.setAttribute("id", "ldot" +z);
    sp1.setAttribute("id", "title"+z);
    sp2.setAttribute("id", "rdot" +z);
    sp0.setAttribute("data-color", "3");
    sp2.setAttribute("data-color", "3");
    sp0.appendChild(document.createTextNode(" \u2022 "));
    sp1.appendChild(document.createTextNode(lines[0]));
    sp2.appendChild(document.createTextNode(" \u2022 "));

    div0.appendChild(sp0);
    div0.appendChild(sp1);
    div0.appendChild(sp2);

    div1.setAttribute("style", "font-size:small;");
    div1.setAttribute("id", "reporttime"+z);
    div1.appendChild(document.createTextNode("---"));

    htd0.appendChild(div0);
    htd1.appendChild(div1);
    if (dz!=0/* && z+dz!=0*/)
        htd2.appendChild(div2); // back
    if (lines[0]!="FACT")
        htd3.appendChild(div3); // home

    // -----------------------------------------------------

    var tbody = document.createElement("tbody");
    table.appendChild(tbody);

    // -----------------------------------------------------

    var tf = document.createElement("tfoot");
    table.appendChild(tf);

    var ftr = document.createElement("tr");
    tf.appendChild(ftr);

    var ftd = document.createElement("td");
    ftd.setAttribute("class",   "tfoot");
    ftd.setAttribute("width",   "100%");
    ftd.setAttribute("colspan", "3");
    ftr.appendChild(ftd);

    var ftab = document.createElement("table");
    ftab.setAttribute("width", "100%");
    ftd.appendChild(ftab);

    var ftd0 = document.createElement("td");
    var ftd1 = document.createElement("td");

    ftd0.setAttribute("class", "tcell1");
    ftd1.setAttribute("class", "tcell2");

    ftab.appendChild(ftd0);
    ftab.appendChild(ftd1);

    var fdiv0 = document.createElement("div");
    var fdiv1 = document.createElement("div");

    fdiv0.setAttribute("style", "font-size:x-large;");
    fdiv1.setAttribute("style", "font-size:small;");
    fdiv1.setAttribute("id",    "localtime"+z);

    fdiv0.appendChild(document.createTextNode("logbook"));
    fdiv1.appendChild(document.createTextNode("loading..."));

    ftd0.appendChild(fdiv0);
    ftd1.appendChild(fdiv1);

    $("body").appendChild(table);

    var counter = 1;
    for (var i=1; i<lines.length; i++)
    {
        lines[i] = trim(lines[i]);

        if (lines[i].length==0 || lines[i][0] == '#')
            continue;

        var cols = lines[i].split(':');
        if (cols.length != 3 && cols.length !=4)
        {
            alert("Size mismatch #"+i+": '"+lines[i]+"' N(cols)="+cols.length);
            continue;
        }

        var check = cols[1].split("=");

        if (check.length>1 && (check[0]=="camera" || check[0]=="hist"))
        {
            var data = cols[1].substring(check[0].length+1).split("/");

            var tr = document.createElement("tr");
            tr.setAttribute("class", "row");
            //tr.setAttribute("style", "margin:0;padding:0;");

            var td = document.createElement("td");
            td.setAttribute("class",   "container");
            td.setAttribute("id",      "container");
            //td.setAttribute("onclick", "save();");
            td.setAttribute("colspan", "3");
            tr.appendChild(td);

            var canv = document.createElement("canvas");
            canv.setAttribute("id",     "canvas"+z);
            canv.setAttribute("width",  "1");
            canv.setAttribute("height", "1");
            canv.setAttribute("data-type", check[0]);
            canv.setAttribute("data-file", data[0]);
            canv.setAttribute("data-data", cols[1].substring(check[0].length+data[0].length+2));
            canv.setAttribute("style", "display:none;");
            td.appendChild(canv);

            var img = document.createElement("img");
            img.src = "dummy.png";//needed in firefox
            img.setAttribute("id",    "image"+z);
            img.setAttribute("style", "width:1px;height:1px;");
            td.appendChild(img);

            tbody.appendChild(tr);
            continue;
        }

        var tr = document.createElement("tr");
        tr.setAttribute("class", "row");
        if (valid(cols[0]))
            tr.setAttribute("onclick", "this.style.background='#ccb'; loadPage('"+cols[0]+"',"+z+",-1);");
        if (valid(cols[3]))
            tr.setAttribute("onclick", "this.style.background='#ccb'; loadPage('"+cols[3]+"',"+z+",+1);");
        //tr.setAttribute("id",    cols[0]+"_row");

        var td0 = document.createElement("td");
        td0.setAttribute("class", "tcol0");
        if (valid(cols[0]))
        {
            var sp = document.createElement("div");
            sp.setAttribute("class", "icon_black");
            sp.setAttribute("style", "background-position: -144px 50%;");
            td0.appendChild(sp);
        }
        tr.appendChild(td0);

        var td1 = document.createElement("td");
        td1.setAttribute("class", "tcol1");
        td1.setAttribute("width", "100%");
        tr.appendChild(td1);

        var td2 = document.createElement("td");
        td2.setAttribute("class", "tcol2");
        td2.setAttribute("width", "18px");
        if (valid(cols[3]))
        {
            var sp = document.createElement("div");
            sp.setAttribute("class", "icon_black");
            sp.setAttribute("style", "background-position: -108px 50%;");
            td2.appendChild(sp);
        }
        tr.appendChild(td2);

        var tab = document.createElement("table");
        tab.setAttribute("width", "100%");
        td1.appendChild(tab);

        var innertr = document.createElement("tr");
        tab.appendChild(innertr);

        var cell1 = document.createElement("td");
        cell1.setAttribute("class", "tcell1");
        //cell1.setAttribute("id",    cols[0]+"_title");
        cell1.appendChild(document.createTextNode(cols[1]));

        var cell2 = document.createElement("td");
        cell2.setAttribute("class", "tcell2");
        cell2.setAttribute("id",    "data"+counter);
        cell2.setAttribute("data-form",  cols[2]);
        cell2.appendChild(document.createTextNode("---"));

        innertr.appendChild(cell1);
        innertr.appendChild(cell2);

        tbody.appendChild(tr);

        counter++;
    }

    // ---------------------------------------

    tr = document.createElement("tr");
    tr.setAttribute("class", "row");

    if (debug == true)
    {
        td = document.createElement("td");
        td.setAttribute("id", "debug"+z);
        td.setAttribute("colspan", "3");
        tr.appendChild(td);
    }

    tbody.appendChild(tr);

    // ---------------------------------------

    table.setAttribute("data-file", name);
    doresize(z);
}

function doresize(z)
{
    // 393 / 482    488/482 / 200   200+482-488
    var img  = $("image"+z);
    var canv = $("canvas"+z);
    if (img == undefined || canv == undefined)
        return;

    var h = $("table"+z).offsetHeight;
    if (h == 0)
        return;

    var W = window.innerWidth;
    var H = window.innerHeight;

    var ih = H - h + parseInt(img.style.height, 10);

    img.style.width = W +"px";
    img.style.height= ih+"px";

    canv.width  = W;
    canv.height = ih;

    // ------ debug -----
    if (debug == true)
    {
        $('debug'+z).innerHTML = "";
        $('debug'+z).innerHTML += "|W="+W +"/"+H;
        $('debug'+z).innerHTML += "|H="+h+"/"+$("table"+z).offsetHeight+"/"+img.offsetHeight;
        $('debug'+z).innerHTML += "|I="+img.style.height+"+"+H+"-"+h;
    }
}

var intervalSlide = null;

function changePage(oldz, newz)
{
    // No page displayed yet
    if (oldz==newz)
    {
        $("table"+newz).style.left="0px";
        $("body").setAttribute("data-visible", newz);

        doresize(0);

        //setInterval(refresh_text, 1000);
        //setInterval(refresh_graphics, 5000);

        refresh_text();
        refresh_graphics();
        return;
    }

    //intervalSlide = setInterval("doSlideOut("+z+")", 25);

    //var k = (z+1)%2;
    //$("table"+k).style.display="";
    //$("table"+z).style.display="";
    //$("table"+k).style.zIndex="0";
    //$("table"+z).style.zIndex="1";
    //$("table"+k).style.left=0;
    //$("table"+z).style.left=0;
    //$("table"+k).style.backgroundColor = "#ffffff";
    //$("table"+z).style.backgroundColor = "#ffffff";
    //doresize(k);
    //intervalSlide = setInterval("doSlide("+z+",1)", 50);

    if (newz>oldz)
        $("table"+newz).style.left=window.innerWidth+"px";
    else
        $("table"+newz).style.left=(-window.innerWidth-1)+"px";

    //window.clearTimeout(timeoutText);
    //window.clearTimeout(timeoutGraphics);

    $("body").setAttribute("data-visible", newz);
    intervalSlide = setInterval(doShift, 75, oldz, newz);
}

function doShift(oldz, newz)
{
    var t0 = $("table"+oldz);
    var t1 = $("table"+newz);

    if (t0.style.display=="none")
    {
        clearInterval(intervalSlide);
        $("body").removeChild(t0);
        return;
    }

    var x0 = t0.offsetLeft;
    var x1 = t1.offsetLeft;

    var W = window.innerWidth;

    if (newz<oldz)
    {
        x0 += W/5;
        x1 += W/5;
    }

    if (newz>oldz)
    {
        x0 -= W/5;
        x1 -= W/5;
    }

    if ((newz<oldz && x1>=0) || (newz>oldz && x1<=0))
    {
        t0.style.display="none";
        x1 = 0;
    }

    t0.style.left = x0+"px";
    t1.style.left = x1+"px";
}

/*
function doSlide(z, dir)
{
    var k = (z+1)%2;

    var W = window.innerWidth;

    var tz = $("table"+z);
    var tk = $("table"+k);

    var xz = tz.offsetLeft;
    var xk = tk.offsetLeft;

    var ixz = parseInt(xz, 10);
    var ikz = parseInt(xk, 10);

    ixz += dir*W/10;
    ikz -= dir*W/10;

    tz.style.left = parseInt(ixz, 10)+"px";
    tk.style.left = parseInt(ikz, 10)+"px";

    if (ixz>W/2)
    {
        clearInterval(intervalSlide);

        $("table"+k).style.zIndex="1";
        $("table"+z).style.zIndex="0";

        $("body").setAttribute("data-visible", k);
        doresize(k);

        intervalSlide = setInterval("doSlide("+z+",-1)", 50);
    }
    if (ikz>0)
    {
        clearInterval(intervalSlide);

        tz.style.left = 0;
        tk.style.left = 0;

        tz.style.display="none";
    }
}


function doSlideOut(z)
{
    var table = $("table"+z);

    var W = window.innerWidth;
    var x = table.offsetLeft;

    var ix = parseInt(x, 10);
    if (ix>W)
    {
        clearInterval(intervalSlide);

        table.style.display="none";

        z = (z+1)%2;
        table = $("table"+z);

        table.style.display="";
        table.style.left = window.innerWidth+"px";

        $("body").setAttribute("data-visible", z);
        doresize(z);

        intervalSlide = setInterval("doSlideIn("+z+")", 25);
        return;
    }

    ix += W/10;
    table.style.left=ix+"px";
}

function doSlideIn(z)
{
    var table = $("table"+z);

    var W = window.innerWidth;
    var x = table.offsetLeft;

    var ix = parseInt(x, 10);

    ix -= W/10;
    if (ix<0)
        ix = 0;

    table.style.left=ix+"px";

    if (ix<=0)
    {
        clearInterval(intervalSlide);
        return;
    }
}
*/

var timeoutText = null;

function refresh_text()
{
    var z=$("body").getAttribute("data-visible");
    var table = $("table"+z);

    // Is sliding or no file defined?
    var fname = table.getAttribute("data-file");
    if (isSliding() || !valid(fname))
    {
        timeoutText = setTimeout(refresh_text, 1000);
        return;
    }

    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open('POST', fname+'.txt', true);
    xmlHttp.onload = function ()
    {
        if (xmlHttp.status!=200)
        {
            alert("ERROR[1] - HTTP request '"+fname+".txt': "+xmlHttp.statusText+" ["+xmlHttp.status+"]");
            timeoutText = setTimeout(refresh_text, 10000);
            return;
        }

        if (!isSliding())
        {
            cycleCol($("ldot"+z));
            update_text(fname, xmlHttp.responseText);
        }
        timeoutText = setTimeout(refresh_text, 3000);
    };
    xmlHttp.send(null);
}

function strike(e, status)
{
    if (!e)
        return;

    if (!status)
        e.style.textDecoration="line-through";
    else
        e.style.textDecoration="";
}

function gray(id, str)
{
    var e = $(id);
    if (!e)
        return;

    if (valid(str))
    {
        e.style.color="#000";
        e.style.textDecoration="";
    }
    else
    {
        e.style.color="#daa";
        e.style.textDecoration="line-through";
    }

}

var date0 = null;

function update_text(fname, result)
{
    var z=$("body").getAttribute("data-visible");
    var table = $("table"+z);

    if (table.getAttribute("data-file") != fname)
        return;

    var tokens = result.split('\n');

    // ----------------------------------------------------

    var  time = $("reporttime"+z);
    var ltime = $("localtime"+z);

    var date1 = new Date();

    if (tokens[0].length!=13)
    {
        if (date0 != null)
            strike(time, date0.getTime()+60000>date1.getTime());
        // FIXME: Reset display to "---" values -- no connection
        return;
    }

    var date2 = new Date();
    date2.setTime(tokens[0]);

    strike(time, date2.getTime()+60000>date1.getTime());

    date0 = date2;

    var utc = date0.toUTCString();

    time.innerHTML =
        "&#8226;&nbsp;"+utc.substr(utc.length-12, 8)+"&nbsp;UTC&nbsp;&#8226;"
    ltime.innerHTML =
        "&#8226;&nbsp;"+date1.toLocaleString()+"&nbsp;&#8226;";

    // ----------------------------------------------------

    var p = table.tBodies.length==3 ? 1 : 0;
    var tbody = table.tBodies[p];

    for (var line=1; line<tokens.length; line++)
    {
        var c = tbody.rows[line-1].cells[1];
        if (c == undefined)
            continue;

        var e = c.childNodes[0].rows[0].cells[1];
        if (e == undefined)
            continue;

        var form = e.getAttribute("data-form");
        if (form==undefined)
            continue;

        var cols = tokens[line].split('\t');
        for (var col=1; col<cols.length; col++)
            form = form.replace("\$"+(col-1), cols[col].length==0 ? "--" : cols[col]);

        if (cols.length<=1)
            form = "---";

        var newe = document.createElement("div");
        newe.innerHTML = form;
        e.replaceChild(newe, e.lastChild);

        e.parentNode.parentNode.parentNode.parentNode.style.background=cols[0];
    }
}

// http://billmill.org/static/canvastutorial/index.html
// http://www.netmagazine.com/tutorials/learning-basics-html5-canvas
// http://www.alistapart.com/articles/responsive-web-design/

function refresh_graphics()
{
    var z = $("body").getAttribute("data-visible");

    var canvas = $("canvas"+z);

    // Is sliding or no data file defined?
    var fname = canvas==null ? "" : canvas.getAttribute("data-file");
    if (isSliding() || !valid(fname))
    {
        timeoutGraphics = setTimeout(refresh_graphics, 1000);
        return;
    }

    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open('POST', fname, true);
    xmlHttp.onload = function()
    {
        if (xmlHttp.status!=200)
        {
            alert("ERROR[2] - Request '"+fname+"': "+xmlHttp.statusText+" ["+xmlHttp.status+"]");
            timeoutGraphics = setTimeout(refresh_graphics, 10000);
            //****** invalidate ******
            return;
        }

        if (!isSliding())
        {
            cycleCol($("rdot"+z));
            process_eventdata(xmlHttp.responseText);
        }
        timeoutGraphics = setTimeout(refresh_graphics, 5000)
    };
    xmlHttp.send(null);
}


function hueToRGB(hue)
{
    hue /= 3;
    hue %= 6;

    if (hue<1) return parseInt(255*hue,     10);
    if (hue<3) return parseInt(255,         10);
    if (hue<4) return parseInt(255*(4-hue), 10);

/*
    if (hue<1*5/4) return parseInt(255*hue*4/5);
    if (hue<2*5/4) return parseInt(255);
    if (hue<3*5/4) return parseInt(255*(3*5/4-hue)*4/5);
*/
/*
    if (hue<1.5) return parseInt(255*hue/1.5);
    if (hue<3.0) return parseInt(255);
    if (hue<4.5) return parseInt(255*(4.5-hue)/1.5);
*/
    return 0.
}

function hueToHex(flt)
{
    var s = hueToRGB(flt).toString(16);
    return s.length==2 ? s : "0"+s;
}

function HLStoRGB(hue)
{
    hue *= 14;

    var sr = hueToHex(20-hue);
    var sg = hueToHex(14-hue);
    var sb = hueToHex(26-hue);

    return sr+sg+sb;
}


function color(col)
{
    if (col==65533)
        col = 0;

    var hue = col/128;
    return HLStoRGB(hue);
}

function toHex(str, idx)
{
    var ch = str[idx].toString(16);
    return ch.length==2 ? ch : "0"+ch;
}

function drawHex(ctx, x, y, col)
{
    ctx.fillStyle = "#"+color(col);

    ctx.save();

    ctx.translate(x, y);
    ctx.scale(1/2, 1/3);

    ctx.beginPath();
    ctx.moveTo( 1,  1);
    ctx.lineTo( 0,  2);
    ctx.lineTo(-1,  1);
    ctx.lineTo(-1, -1);
    ctx.lineTo( 0, -2);
    ctx.lineTo( 1, -1);
    ctx.fill();

    ctx.restore();
}

function drawDisc(ctx, x, y, r, col)
{
    ctx.fillStyle = "#"+color(col);

    ctx.save();

    ctx.translate(x, y);

    ctx.beginPath();
    ctx.arc(0, 0, r, 0, Math.PI*2, true);
    ctx.fill();

    ctx.restore();
}

function beginDrawCam(scale)
{
    var z    = $("body").getAttribute("data-visible");
    var canv = $("canvas"+z);

    var w = Math.min(canv.width/scale, canv.height/scale);

    var ctx = canv.getContext("2d");

    ctx.save();
    ctx.translate(canv.width/2, canv.height/2);
    ctx.scale(w*2, w*2);

    return ctx;
}

function position(s, ring, i)
{
    switch (s)
    {
    case 0: this.x =  ring     - i*0.5;  this.y =       + i; break;
    case 1: this.x =  ring*0.5 - i;      this.y =  ring    ; break;
    case 2: this.x = -ring*0.5 - i*0.5;  this.y =  ring - i; break;
    case 3: this.x = -ring     + i*0.5;  this.y =       - i; break;
    case 4: this.x = -ring*0.5 + i;      this.y = -ring    ; break;
    case 5: this.x =  ring*0.5 + i*0.5;  this.y = -ring + i; break;
    }

    this.d = function() { return this.x*this.x + this.y*this.y*3/4; }
}

function drawFullCam(data)
{
    var ctx = beginDrawCam(80.5);
    ctx.rotate(Math.PI/2);

    ctx.scale(1, Math.sqrt(3)/2);

    drawHex(ctx, -0.5, 0, data.charCodeAt(0));

    var cnt  = 1;
    for (var ring=1; ring<24; ring++)
    {
        for (var s=0; s<6; s++)
        {
            for (var i=1; i<=ring; i++)
            {
                var pos = new position(s, ring, i);
                if (pos.d() - pos.x > 395.75)
                    continue;

                drawHex(ctx, pos.x-0.5, -pos.y, data.charCodeAt(cnt++));
            }
        }
    }

    drawHex(ctx, -6.5,  22, data.charCodeAt(1438));
    drawHex(ctx, -6.5, -22, data.charCodeAt(1439));

    ctx.restore();
}

function drawCam(data)
{
    var ctx = beginDrawCam(27);
    ctx.rotate(Math.PI/6);
    ctx.scale(1, Math.sqrt(3)/2);

    drawHex(ctx, 0, 0, data.charCodeAt(0));

    var cnt = 1;
    for (var ring=1; ring<=7; ring++)
    {
        for (var s=0; s<6; s++)
        {
            for (var i=1; i<=ring; i++)
            {
                var pos = new position(s, ring, i);
                if (pos.d() > 44)
                    continue;

                if (ring==7)
                {
                    if (i==6 && (s==0 || s==3))
                        continue;
                    if (i==1 && (s==1 || s==4))
                        continue;
                }

                drawHex(ctx, pos.x, pos.y, data.charCodeAt(cnt++));
            }
        }
    }

    ctx.restore();
}

function drawCamLegend(canv)
{
    var vals = canv.getAttribute("data-data").split("/");
    var diff = vals[1]-vals[0];

    var cw = canv.width;
    var ch = canv.height;

    var ctx = canv.getContext("2d");

    ctx.font         = "8pt Arial";
    ctx.textAlign    = "right";
    ctx.textBaseline = "top";

    for (var i=0; i<9; i++)
    {
        ctx.strokeStyle = "#"+color(16*i);
        ctx.strokeText((vals[0]-diff*(i-8)/8)+vals[2], cw-5, 135-i*15);
    }
}

function drawGraph(canv, data)
{
    var cw = canv.width;
    var ch = canv.height;

    var ctx = canv.getContext("2d");

    var vals = canv.getAttribute("data-data").split("/");

    var dw =  3;    // tick width

    var fs = 8;  // font size

    ctx.font      = fs+"pt Arial";
    ctx.textAlign = "right";

    var dim0 = ctx.measureText(vals[0]);
    var dim1 = ctx.measureText(vals[1]);

    var tw = vals.length>=2 ? Math.max(dim0.width, dim1.width)+dw+2 : 0;

    var ml = vals.length>=2 ? 5+tw   : 10; // margin left
    var mr = 10;                           // margin right

    var mt = vals.length>=2 ? fs/2+5 : 5; // margin top
    var mb = vals.length>=2 ? fs/2+4 : 5; // margin bottom

    var nx = 20;
    var ny = 10;

    var w = cw-ml-mr;
    var h = ch-mt-mb;

    ctx.strokeStyle = "#808080";

    // --- data ---
    ctx.beginPath();
    ctx.moveTo(ml, ch-mb-data.charCodeAt(0)/128*h);
    for (var i=1; i<data.length; i++)
        ctx.lineTo(ml+w/(data.length-1)*i, ch-mb-data.charCodeAt(i)/128*h);

    // --- finalize data ---
    ctx.lineTo(cw-mr, ch-mb);
    ctx.lineTo(ml,    ch-mb);
    ctx.fillStyle = "#"+color(100);
    ctx.stroke();
    ctx.fill();

    ctx.strokeStyle = "#000000";

    ctx.beginPath();

    // --- axes ---
    ctx.moveTo(ml,    mt);
    ctx.lineTo(ml,    ch-mb);
    ctx.lineTo(cw-mr, ch-mb);

    for (var i=0; i<nx; i++)
    {
        ctx.moveTo(ml+w/nx*i, ch-mb-dw);
        ctx.lineTo(ml+w/nx*i, ch-mb+dw);
    }
    for (var i=0; i<ny; i++)
    {
        ctx.moveTo(ml-dw, mb+h/ny*i);
        ctx.lineTo(ml+dw, mb+h/ny*i);
    }
    ctx.stroke();
    ctx.closePath();

    if (vals.length>=2)
    {
        ctx.textBaseline = "bottom";
        ctx.strokeText(vals[0], ml-dw-2, ch-1);

        ctx.textBaseline = "top";
        ctx.strokeText(vals[1], ml-dw-2, 0);
    }
}

function process_eventdata(result)
{
    var z = $("body").getAttribute("data-visible");
    var canv = $("canvas"+z);
    if (canv == undefined)
        return;

    var type = canv.getAttribute("data-type");

    var ctx = canv.getContext("2d");
    ctx.clearRect(0, 0, canv.width, canv.height);

    switch (type)
    {
    case "hist":   drawGraph(canv, result); break;
    //case "camera": drawCam(result);     break;
    case "camera": drawFullCam(result); drawCamLegend(canv); break;
    }

    $("image"+z).src = canv.toDataURL("image/png");
}

/*
function save()
{
    var z = $("body").getAttribute("data-visible");

    var canvas = $("canvas"+z);
    var img    = canvas.toDataURL("image/png");

    img = img.replace("image/png", "image/octet-stream");

    document.location.href = img;
}
*/
window['onload'] = onload;
