/* global THREE */

"use strict";
///////////////////////////////////////////////UT/////////////////////////////////////////////////////////

var vpi = Math.PI;

var pi = vpi;

var arrowth = torad(180 - 17);
var epsilon = 1E-15;
var ccursor = "default";


function fullscreen(){
    if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement ) {
            if (document.documentElement.requestFullscreen) {
                document.documentElement.requestFullscreen();
            } else if (document.documentElement.mozRequestFullScreen) {
            document.documentElement.mozRequestFullScreen(); // Firefox
            } else if (document.documentElement.webkitRequestFullscreen) {
                document.documentElement.webkitRequestFullscreen(); // Chrome and Safari
            } else if (document.documentElement.msRequestFullscreen) {
                document.documentElement.msRequestFullscreen(); // IE
            }

        //Toggle fullscreen on, exit fullscreen
        } else {

            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.msExitFullscreen) {
                document.msExitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            }  
}
}

function download(filename, text) {
    var element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
}
// eg  download ("hello.txt","[a,b,c]")
function readfile(filename, callfunc) {
    var xhr = new XMLHttpRequest();
//xhr.open("GET", "/bar/foo.txt", true);
    xhr.open("GET", filename, true);
    xhr.onload = function (e) {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
/// console.log(xhr.responseText);
//return xhr.responseText;
                callfunc(xhr.responseText)
            } else {
//console.error(xhr.statusText);
                alert("error read " + name)
            }
        }
    };


    xhr.onerror = function (e) {
        console.error(xhr.statusText);
    };
    xhr.send(null);

}

function callfuncalert(st) {
    download("hello from js", st);
}
////readfile("js/agogoi.js",callfuncalert);
function bezier(t, pts, offset, res) {
    var k0 = Math.pow(1 - t, 3);
    var k1 = 3 * t * Math.pow(1 - t, 2);
    var k2 = 3 * (1 - t) * t * t;
    var k3 = Math.pow(t, 3);
    res[0] = k0 * pts[0 + offset] + k1 * pts[2 + offset] + k2 * pts[4 + offset] + k3 * pts[6 + offset];
    res[1] = k0 * pts[1 + offset] + k1 * pts[3 + offset] + k2 * pts[5 + offset] + k3 * pts[7 + offset];
}

function crossproduct(a1, a2, a3, b1, b2, b3) {
    return([a2 * b3 - a3 * b2, a3 * b1 - a1 * b3, a1 * b2 - a2 * b1])
}

function setarrowth(deg) {
    arrowth = torad(180 - deg);
}
//  use with to decimal for display
function step(n, astep) {
    if (astep === 0)
        return toround(n);
    return Math.round(n / astep) * astep;

}
function Task(type, period, life) {
    this.t = 0;
    this.period = period;
    this.life = life;
    this.type = type;
}
Task.prototype.update = function () {
    if (this.life > 0)
        this.life -= this.dt;
    this.act();
}
Task.prototype.act = function () {
    var frm = this.form;
    var t = this.t;
    frm.x += 0.4;
    frm.y += 0.3;
}

function lerp(a, b, t){
return a + (b - a) * t
}
function todeg(v) {
    return v * 180 / vpi;
}
function torad(v) {
    return v * vpi / 180;
}
// from -pi to pi
function anglefix(th) {
    if (th > vpi)
        return th - 2 * vpi;
    if (th < -vpi)
        return th + 2 * vpi;
    return th;
}
function angleabs(th) {
    var res = th;
    if (th < 0)
        res = 2 * Math.PI + th;
    return res;
}
function length(x1, y1, x2, y2) {

    return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
function angle(x1, y1, x2, y2) {

    return Math.atan2(y2 - y1, x2 - x1);
}
function atan2(y, x) {

    return Math.atan2(y, x);
}
function distancenom(x0, y0, x1, y1, x2, y2) {

    return Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1);//////length(x1,y1,x2,y2);
}
function distancepointline(x0, y0, x1, y1, x2, y2) {
    var tol = 0.1;
    var le = length(x1, y1, x2, y2);
    if (le < tol)
        return length(x0, y0, x1, y1);
    return distancenom(x0, y0, x1, y1, x2, y2) / le;

}
function insegment(x0, y0, x1, y1, x2, y2, tol) {

    if (length(x0, y0, (x1 + x2) / 2, (y1 + y2) / 2) > length(x1, y1, x2, y2) / 2)
        return false;
    tol = tol || 1;

    return distancepointline(x0, y0, x1, y1, x2, y2) < tol;


}
function insegmentpolar(x0, y0, x, y, r, th, tol) {
    return insegment(x0, y0, x, y, x + r * cos(th), y + r * sin(th), tol)
}


//var pm={x:444,y:444,r:64,w:164,h:164,ticks:5,min:0,max:20,value:0,dmin:3*Math.PI/4,dmax:9*Math.PI/4,dvalue:3*Math.PI/4};
// from value to dev
function random(v1, v2) {
     
    return v1 + (v2 - v1) * Math.random();
}
function getdev(p) {
    var dv = p.dmin + (p.value - p.min) / (p.max - p.min) * (p.dmax - p.dmin);

    return dv;

}
function map(min, max, value, dmin, dmax) {
    var dv = dmin + (value - min) / (max - min) * (dmax - dmin);

    return dv;

}


function getvalue(p) {
    var value = p.min + (p.dvalue - p.dmin) / (p.dmax - p.dmin) * (p.max - p.min);
    return value;

}


function getallmethods(obj) {
/// array
    var ar = Object.getOwnPropertyNames(obj);
    return ar;
}

function getallproperties(obj) {
/// array
    var ar = Object.keys(obj);
    return ar;
}
function jsoncopy(src) {
    return JSON.parse(JSON.stringify(src));
}
function jsonstringify(src) {
    return JSON.stringify(src);
}
var Value = function (v) {
    this.value = v;
    this.min = v;
    this.max = v;
    this.prev = v;
    this.first = v;

}

function rk4(x, v, fvel, facc, h, t)
{

    var k1 = fvel(x, v, t);
    var l1 = facc(x, v, t);
    var k2 = fvel(x + h * k1 / 2, v + h * l1 / 2, t + h / 2);
    var l2 = facc(x + h * k1 / 2, v + h * l1 / 2, t + h / 2);
    var k3 = fvel(x + h * k2 / 2, v + h * l2 / 2, t + h / 2);
    var l3 = facc(x + h * k2 / 2, v + h * l2 / 2, t + h / 2);
    var k4 = fvel(x + h * k3, v + h * l3, t + h);
    var l4 = facc(x + h * k3, v + h * l3, t + h);
    x = x + h * (k1 + 2 * k2 + 2 * k3 + k4) / 6;
    v = v + h * (l1 + 2 * l2 + 2 * l3 + l4) / 6;
    return [x, v];
}

function changecursor(nc) {

    if (nc !== ccursor) {
        document.body.style.cursor = nc;
        ccursor = nc;
    }


}
function getepsilon() {
    return epsilon;
}

function equals(a, b, tol) {
    return((abs(a) - abs(b)) < abs(tol))
}
function iszero(n) {
    return Math.abs(n) < epsilon;
}

function toggle(x) {

    if (x.style.display === "none") {
        x.style.display = "block";
    } else {
        x.style.display = "none";
    }
}
function showelement(x) {


    x.style.display = "block";



}
function hideelement(x) {


    x.style.display = "none";



}
function printto(id, st) {
    var el = document.getElementById(id);
    el.innerHTML = st;
}


function getelement(st) {
    return document.getElementById(st);
}
function scaleelement(el, wi, hi) {

    var st = 'scale(' + wi + ',' + hi + ')';
    el.style.transform = st;
    el.style['-o-transform'] = st;
    el.style['-webkit-transform'] = st;
    el.style['-moz-transform'] = st;
}
///
/// math


function getpolar(x, y, r, th, array) {

    array[0] = x + r * cos(th);
    array[1] = y + r * sin(th);

}
function abs(n) {
    return Math.abs(n)
}
function sin(n) {
    return Math.sin(n)
}
function cos(n) {
    return Math.cos(n)
}
function tan(n) {
    return Math.tan(n)
}

function todecimal(n, digits) {


    return n.toFixed(digits)

///return num.toLocaleString();
}

function toround(n) {
    return Math.round(n);

}

function sign(x) {
    if (x > 0)
        return 1;
    if (x < 0)
        return -1;
    return 0;
}

function toint(x) {
    return parseInt(x);
}

function tofloat(str) {
    return parseFloat(str);
}

function rgb(r, g, b) {
    return ("rgb(" + r.toString() + "," + g.toString() + "," + b.toString() + ")");
}

function rgba(r, g, b, a) {
    return ("rgba(" + r.toString() + "," + g.toString() + "," + b.toString() + "," + a.toString() + ")");
}

function concat() {
    var st = "";
    for (var i = 0; i < arguments.length; i++) {
        st += " " + arguments[i];
    }
    return st;
}
;
//// dom elements support
function getattr(el, str) {
    return el.getAttribute(str);
}

function setattr(el, str) {
    el.setAttribute(str);
}
/// string for id comma sep childs
function appendchilds() {
    var el = getelement(arguments[0]);
    for (var i = 1; i < arguments.length; i++) {
        el.appendChild(arguments[i]);
    }
}

function setbackimage(el, str) {
    el.style.backgroundImage = "url(" + str + ")";
}

function setbackcolor(el, str) {
    el.style.backgroundColor = str;
}

function setelementpos(d, x_pos, y_pos) {
    d.style.position = "absolute";
    d.style.left = x_pos + 'px';
    d.style.top = y_pos + 'px';
}
/////----------------- global functions 
/// ed loaders 
//
function loadgltf(frm, str) {



    var loader = new THREE.GLTFLoader();

// Optional: Provide a DRACOLoader instance to decode compressed mesh data
//THREE.DRACOLoader.setDecoderPath( '/examples/js/libs/draco' );
//loader.setDRACOLoader( new THREE.DRACOLoader() );

// Load a glTF resource

    loader.load(
// resource URL'models/gltf/duck/duck.gltf'
            str,
// called when the resource is loaded
            function (gltf) {
                alert(str)
///frm.scene.add(gltf.scene);

                gltf.animations; // Array<THREE.AnimationClip>
                var object = gltf.scene; // THREE.Scene
                gltf.scenes; // Array<THREE.Scene>
                gltf.cameras; // Array<THREE.Camera>
                gltf.asset; // Object
////// 
                var animations = gltf.animations;

                if (animations && animations.length) {

                    frm.mixer = new THREE.AnimationMixer(object);

                    for (var i = 0; i < animations.length; i++) {

                        var animation = animations[ i ];

                        animation.duration = 233;//sceneInfo.animationTime

                        var action = frm.mixer.clipAction(animation);


                        action.play();

                    }

                }

                frm.scene.add(object);





            },
// called while loading is progressing
            function (xhr) {

                console.log((xhr.loaded / xhr.total * 100) + '% loaded');

            },
// called when loading has errors
            function (error) {
                alert("gltfe error")
//console.log( 'An error happened' );

            }
    );

}

//////  3 d    g e o m e t r y /////////////////////////////////////////////////
function arrow(length) {
//var dir = new THREE.Vector3(0, 0, 1);
//normalize the direction vector (convert to vector of length 1)
//dir.normalize();
    var origin = new THREE.Vector3(0, 0, 0);
    length = length || 1;
    return new THREE.Arrow(0, 0, 1, origin, length, 0x336633, 0.08, 0.04, 0.01);
}
function arrow2(len, width, headlen) {


    return new Arrow2(new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 0), len, width, headlen);
}
function plane(w, h, mat) {


    var geometry = new THREE.PlaneGeometry(w, h);
    return new THREE.Mesh(geometry, mat);

}
function sphere(radius, s1, s2, mat) {
    var geometry = new THREE.SphereBufferGeometry(radius, s1, s2);
    return new THREE.Mesh(geometry, mat);
}

function box(x1, y1, z1, mat) {
    var geometry = new THREE.BoxGeometry(x1, y1, z1);
    return new THREE.Mesh(geometry, mat);
}

function cylinder(radtop, radbot, height, segments, mat) {
    var geometry = new THREE.CylinderBufferGeometry(radtop, radbot, height, segments);
//geometry.translate(0, +height/2, 0);
    return new THREE.Mesh(geometry, mat);
}

function line(mat) {
    var geometry = new THREE.Geometry();
    geometry.vertices.push(new THREE.Vector3(0, 0, 0));
    geometry.vertices.push(new THREE.Vector3(1, 0, 0));
    return new THREE.Line(geometry, mat);
}

function lineupdate(aline) {
    aline.geometry.verticesNeedUpdate = true;
    if (aline.material.isLineDashedMaterial) {
        aline.computeLineDistances();
        aline.geometry.lineDistancesNeedUpdate = true;
    }
}

function lineset(aline, x1, y1, z1, x2, y2, z2) {
    aline.geometry.vertices[0].set(x1, y1, z1);
    aline.geometry.vertices[1].set(x2, y2, z2);
    lineupdate(aline)
}

function linestart(aline, x1, y1, z1) {
    aline.geometry.vertices[0].set(x1, y1, z1);
    lineupdate(aline)
}

function lineend(aline, x1, y1, z1) {
    aline.geometry.vertices[1].set(x1, y1, z1);
    lineupdate(aline)
}

function ngon(radius, num, mat) {
    var geometry = new THREE.Geometry();
    for (var i = 0; i <= num; i++) {
        var th = i * 2.0 * Math.PI / num;
        var x = radius * Math.cos(th);
        var y = radius * Math.sin(th);
        geometry.vertices.push(new THREE.Vector3(x, y, 0));
    }
    return new THREE.Line(geometry, mat);
}

function helix(radius, num, turns, mat) {
    var geometry = new THREE.Geometry();
    for (var i = 0; i <= num * turns; i++) {
        var th = i * 2.0 * Math.PI / num;
        var x = radius * Math.cos(th);
        var y = radius * Math.sin(th);
        geometry.vertices.push(new THREE.Vector3(x, y, 1 * i / turns / num));
    }
    return new THREE.Line(geometry, mat);
}

function concat() {
    var st = "";
    for (var i = 0; i < arguments.length; i++) {
        st += " " + arguments[i];
    }
    return st;
}
;
//// path gen
//
/// returns loops+1 * move to 

function springout(len, r, loops, d2) {
    var p = [];
    var x = 0;
    var y = 0;

    var d = len / (loops + 1);
    var d1 = d / d2;


    x += d / 2; // continue
    var i;
    for (i = 0; i < loops; i++) {
        p.push(x, y - r); //move to
        p.push(x + d1, y - r, x + d / 2 + d1, y + r, x + d / 2, y + r);
        x += d;
    }

    p.push(x, y - r); // move to 
    p.push(x + d1, y - r, x + d / 2, y - d1, x + d / 2, y);// bezier Curve start
    return p;

}
function springin(len, r, loops, d2) {
    var p = [];
    var x = 0;
    var y = 0;

    var d = len / (loops + 1);
    var d1 = d / d2;
    p.push(x, y); // move to 
    p.push(x, y - d1, x + d / 2 - d1, y - r, x + d / 2, y - r);// bezier Curve start

    x += d;
    var i;
    for (i = 0; i < loops; i++) {
        p.push(x, y + r); //move to
        p.push(x - d1, y + r, x + d / 2 - d1, y - r, x + d / 2, y - r);
        x += d;
    }

    return p;

}
function drawspringin(ctx, len, r, loops, x, y, th, d2) {
    var p = springin(len, r, loops, d2);

    var tr = new Transform();

    tr.translate(x, y);
    tr.rotate(th);
    p = tr.transformPolygon(p);
    var i, j;
    for (j = 0; j <= loops; j++) {
        i = 8 * j;
        ctx.beginPath();
        ctx.moveTo(p[i], p[i + 1]);
        ctx.bezierCurveTo(p[i + 2], p[i + 3], p[i + 4], p[i + 5], p[i + 6], p[i + 7]);
        ctx.stroke();
    }


}
function drawspringout(ctx, len, r, loops, x, y, th, d2) {
    var p = springout(len, r, loops, d2);
    var tr = new Transform();

    tr.translate(x, y);
    tr.rotate(th);
    p = tr.transformPolygon(p);
    var i, j;
    for (j = 0; j <= loops; j++) {
        i = 8 * j;
        ctx.beginPath();
        ctx.moveTo(p[i], p[i + 1]);
        ctx.bezierCurveTo(p[i + 2], p[i + 3], p[i + 4], p[i + 5], p[i + 6], p[i + 7]);
        ctx.stroke();
    }


}
function drawspring(ctx, len, r, loops, x, y, th, d2) {
    drawspringin(ctx, len, r, loops, x, y, th, d2);
    drawspringout(ctx, len, r, loops, x, y, th, d2);



}

///////////---------drawing functions -------------------------

function subimage(ctx,imres,n,cols,rows,w,h){
   if(!imres.image) return;
   var row=toint(n/cols);
   var col=n-row*cols;
   var sx=col*w;
   var sy=row*h;
   ctx.drawImage(imres.image,sx,sy,w,h,0,0,w,h);
    
    
}
function linedash(ctx, ar) {
    ctx.setLineDash(ar);
}
function strokestyle(ctx, stst) {
    ctx.strokeStyle = stst;
}
function fillstyle(ctx, fst) {
    ctx.fillStyle = fst;
}
// if one parameter both stroke and fill same 
function styles(ctx, stst, fst) {
    ctx.strokeStyle = stst;

    ctx.fillStyle = fst || stst;
}

function linewidth(ctx, lw) {
    ctx.lineWidth = lw;
}


function wraptext(ctx, text, x, y, maxWidth, lineHeight) {
    var words = text.split(' ');
    var line = '';

    for (var n = 0; n < words.length; n++) {
        var wo = words[n];
        if (wo === "#") {
            words[n] = '';

            ctx.fillText(line, x, y);
            line = '';
            y += lineHeight;

        }
        var testLine = line + words[n] + ' ';
        if (wo === "#")
            testLine = line;
        var metrics = ctx.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > maxWidth && n > 0) {
            ctx.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
        } else {
            line = testLine;
        }
    }
    ctx.fillText(line, x, y);
}
function drawroundrect(ctx, x, y, width, height, radius, filled, strokestyle, fillstyle) {
// filled =0 only line 1 only fill 2 both
    ctx.beginPath();

    if (strokestyle)
        ctx.strokeStyle = strokestyle;
    if (fillstyle)
        ctx.fillStyle = fillstyle;
    ctx.moveTo(x, y + radius);
    ctx.lineTo(x, y + height - radius);
    ctx.arcTo(x, y + height, x + radius, y + height, radius);
    ctx.lineTo(x + width - radius, y + height);
    ctx.arcTo(x + width, y + height, x + width, y + height - radius, radius);
    ctx.lineTo(x + width, y + radius);
    ctx.arcTo(x + width, y, x + width - radius, y, radius);
    ctx.lineTo(x + radius, y);
    ctx.arcTo(x, y, x, y + radius, radius);
    ctx.closePath();
    if (filled === 0 || filled === 2)
        ctx.stroke();
    if (filled === 1 || filled === 2)
        ctx.fill();
}

function settransform(ctx, tr) {
    ctx.setTransform(tr.m[0], tr.m[1], tr.m[2], tr.m[3], tr.m[4], tr.m[5]);
}

function drawline(ctx, x1, y1, x2, y2, linestyle) {
    if (linestyle)
        ctx.strokeStyle = linestyle;
    ctx.beginPath();

    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
}

function drawpolar(ctx, x, y, r, thrad) {
    ctx.beginPath();

    ctx.moveTo(x, y);
    ctx.lineTo(x + r * Math.cos(thrad), y + r * Math.sin(thrad));
    ctx.stroke();
}

function drawvector(ctx, x1, y1, x2, y2) {
    var thrad = Math.atan2(y2 - y1, x2 - x1);
//var r=Math.hypot(y2-y1,x2-x1);
    var r = Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
    drawpolar(ctx, x1, y1, r, thrad);
    drawpolar(ctx, x2, y2, 16, thrad + arrowth);
    drawpolar(ctx, x2, y2, 16, thrad - arrowth);
}

function drawvectorpolar(ctx, x, y, r, thrad, linestyle) {
    drawvector(ctx, x, y, x + r * Math.cos(thrad), y + r * Math.sin(thrad));
}

function drawrect(ctx, x1, y1, w, h, filled) {
    filled = filled || 0;
    ctx.beginPath();
//if (linestyle) ctx.strokeStyle = linestyle;
    ctx.rect(x1, y1, w, h);
    if (filled === 1 || filled === 2)
        ctx.fill();
    if (filled === 0 || filled === 2)
        ctx.stroke();
//ctx.stroke();
}



function drawarcfilled(ctx, xo, yo, r, st, en, anticlock, linestyle) {
    ctx.beginPath();
    ctx.moveTo(xo, yo);
    if (linestyle)
        ctx.fillStyle = linestyle;
    ctx.arc(xo, yo, r, st, en, anticlock);
    ctx.fill();
}
///////////////////////new 


function drawarc(ctx, xo, yo, r, st, en, anticlock, closed, filled) {
    ctx.beginPath();
    filled = filled || 0;
    closed = closed || 0;
//if (linestyle) ctx.strokeStyle = linestyle;
    if (closed)
        ctx.moveTo(xo, yo)
    ctx.arc(xo, yo, r, st, en, anticlock);
//ctx.stroke();
    if (closed)
        ctx.closePath();
    if (filled === 1 || filled === 2)
        ctx.fill();
    if (filled === 0 || filled === 2)
        ctx.stroke();

}
function drawcircle(ctx, xo, yo, r) {
    drawarc(ctx, xo, yo, r, 0, 2 * Math.PI, false, false, 0, 1);
}

function drawcirclefilled(ctx, xo, yo, r, linestyle) {
    drawarcfilled(ctx, xo, yo, r, 0, 2 * Math.PI, false, linestyle);
}
// fill text centered at x y 
function drawtext(ctx, text, x, y, size, centerleft) {
    size = size || 20;
    centerleft = centerleft || false;
    ctx.font = size + "px Helvetica";
    ctx.textAlign = "center";

    if (centerleft)
        ctx.textAlign = "left";

    ctx.textBaseline = "middle";

    ctx.fillText(text, x, y);
}
// draw polygon p [x,y,x,y]
//filled =0 stroke 1 filled 2 str & filled
//percent 
function drawpolygon(ctx, p, filled, closed, percent, st, len) {

    var filled = filled || 0;
    var closed = closed || 0;
    var percent = percent || 1.0;
    var st = st || 0;
    var len0 = percent * p.length / 2
    if (len !== undefined)
        len0 = len / 2;
    ctx.beginPath();
    ctx.moveTo(p[st], p[st + 1]);
    var i;
    for (i = 1; i < len0; i++) {
        ctx.lineTo(p[st + i * 2], p[st + i * 2 + 1]);
    }
    if (closed)
        ctx.closePath();
    if (filled === 1 || filled === 2)
        ctx.fill();
    if (filled === 0 || filled === 2)
        ctx.stroke();
}
function drawarrow(ctx, x, y, len, th, arh, d, filled) {
    if (len < 0.01)
        return;
//var arh=appw/50;
// var d=arh/3;
    var ars = len - arh;
    var d2 = 2 * d;
    if (ars < 0)
        ars = 0;
    var tr = new Transform();
    var p = [];

    tr.translate(x, y);
    tr.rotate(th);


    p.push(0, 0, 0, d, ars, d, ars, d + d2, len, 0, ars, -d - d2, ars, -d, 0, -d, 0, 0);
    p = tr.transformPolygon(p);
    drawpolygon(ctx, p, filled);
}
// center xo yo , half len
function drawdistance(ctx, x, y, len, th, arh, d, filled) {
    drawarrow(ctx, x, y, len, th, arh, d, filled);
    drawarrow(ctx, x, y, len, th + Math.PI, arh, d, filled);
}

var Particle = {
    m: 1, x: 110, y: 110,
    xp: 110, yp: 110,
    vxp: 10, vyp: 10,
    vx: 10, vy: 10, v: 140, dir: 1.7, K: 11,
    rx: 2,
    ry: 2,
    fs: 0.1, fsmax: 0.2, drag: 0.1,
    r: 111, g: 111, b: 111


}
// dw dh image width use when particles in eimitter
var ParticleSystem = {
    dw: 0, dh: 0,

    image: undefined,
    images: [],
    shape: "rect,oval,line",

    t: 0, rate: 55,
    n: 13,
    ndis: 100,
    nactive: 0,
    size1: 1, size2: 10, life1: 3, life2: 6,
    stream: "0:burst 1 stream",
    drag: 0,
    gry: 10, grx: 0,
    v1: 33, v2: 66, th1: 0.0, th2: Math.PI * 2,

    r1: 0, g1: 0, b1: 0,
    r2: 222, g2: 256, b2: 222,
    emx1: 0, emy1: 0, emx2: 166, emy2: 3,
    emtype: "rect,oval,line",
    em: [0, 0, 100, 0],
    p: [],
    x1: 0, y1: 0, x2: 640, y2: 480,radius:128
    


}
function emit(ps, p) {
    particleInit(p, ps);

    
}
function psStep(ps, dt) {
    var i;
    ps.t += dt;
    if (ps.nactive < ps.p.length) {

        var cp = ps.nactive;
        var ni = toint(ps.t * ps.rate);
// printto("debug",concat (ps.t,ni))

        for (i = 0; i < ni - cp; i++) {
            if (ps.p.length > ps.nactive) {
                ps.nactive++;
                emit(ps, ps.p[cp + i]);

            }

        }

    }
    for (i = 0; i < ps.p.length; i++) {
        var p = ps.p[i];
        p.t += dt;
        if (p.t > p.life) emit(ps, p);
        p.x += p.vx * dt;
///p.vy += 0.1 ;//gravity
        p.y += (p.vy ) * dt;
        var tt=p.t / p.life ;
        p.size=(ps.size1+(ps.size2-ps.size1)*tt)/100;
        p.image = ps.images[ toint(tt* ps.images.length)];
    }

}
function particleInit(p, ps) {
    var th = random(ps.th1, ps.th2);
    var v = random(ps.v1, ps.v2);

    p.vx = v * Math.cos(th);
    p.vy = v * Math.sin(th);
    p.life = random(ps.life1, ps.life2);
    p.r = random(ps.r1, ps.r2);
    p.g = random(ps.g1, ps.g2);
    p.b = random(ps.b1, ps.b2);
    p.life = random(ps.life1, ps.life2);
    p.t = 0;
    p.x = lerp(ps.x1,ps.x2,random(0,1));
    p.y =  lerp(ps.y1,ps.y2,random(0,1));
}
function psInit(ps) {
    var i;
    ps.p = [];
    for (i = 0; i < ps.n; i++) {
        var np = jsoncopy(Particle);
        ps.p.push(np);
        np.x = random(ps.x1, ps.x2);
        np.y = random(ps.y1, ps.y2);
        particleInit(np, ps);
        np.t = 1e33;
    }



}
function psStepBounce(ps, dt) {
    var i;
    for (i = 0; i < ps.p.length; i++) {
        var p = ps.p[i];
        p.x += p.vx * dt;
        p.y += p.vy * dt;
        if (p.x > ps.x2) {
            p.x = ps.x2;
            p.vx = -1 * p.vx;

        }
        if (p.y > ps.y2) {
            p.y = ps.y2;
            p.vy = -1 * p.vy;
        }
        if (p.x < ps.x1) {
            p.x = ps.x1;
            p.vx *= -1;

        }

        if (p.y < ps.y1) {
            p.y = ps.y1;
            p.vy *= -1;

        }
    }

}

function psDraw(ps, frm) {
    var i;

    for (i = 0; i < ps.nactive; i++) {

        var p = ps.p[i];

        styles(frm.ctx, "black", "white")
       // frm.drawimageto(ps.image, p.x, p.y);
frm.drawimagetr  (p.image,p.x, p.y,0, p.size,p.size,ps.radius,ps.radius)
}

}
function psStepgas(ps, dt) {
    ps.nactive = ps.ndis;
    var i, te;
    if (Math.random() > 0.9) {
//te=p.vx;
//  p.vx=p.vy;
//  p.vy=te;

// p.vx*=-1;
//   p.vy*=-1;
        var n1 = toint(random(ps.ndis));
        var n2 = toint(random(ps.ndis));
        te = ps.p[n1].vx;
        ps.p[n1].vx = ps.p[n2].vx;
        ps.p[n2].vx = te;
        te = ps.p[n1].vy;
        ps.p[n1].vy = ps.p[n2].vy;
        ps.p[n2].vy = te;

    }
    for (i = 0; i < ps.p.length; i++) {
//for (i = 0; i < ps.ndis; i++) {
        var p = ps.p[i];


        p.x += p.vx * dt;
        p.y += p.vy * dt;
        if (p.x > ps.x2) {
            p.x = ps.x2;
            p.vx = -1 * p.vx;

        }


        var yz = 25 - 0.0025 * Math.pow(p.x - 0.5 * ps.x2, 2);
        if (p.y > ps.y2 + yz) {

            p.yz = yz;
//if ((ps.y>ps.y2+yz)&& p.vy>0) 


            p.y = ps.y2 + yz;
            p.vy = -1 * p.vy;



        }
        if (p.x < ps.x1) {
            p.x = ps.x1;
            p.vx *= -1;

        }

        if (p.y < ps.y1) {


            p.y = ps.y1;
            p.vy *= -1;

        }
    }

}



var Curve = {
    label: "T1",
    x: [],
    y: [],
    ls: "blue",
    fs: "#FFB8EB",
    filled: 0,
    lw: 1.5,
    dotp: [],
    dotsize: 4,
    drawdots: true
}


var Graph = {
    label: "general",
    x0: 200,
    y0: 300,
    axisx: undefined,
    axisy: undefined,
    ls: "black",
    fs: "black",
    lw: 1.5,
    lsgrid: "cyan",
    lwgrid: 1,
    curves: [],
    cpx: 0, cpy: 0,
    cpsize: 8,
    cpsdraw: true,
    cpscoordsdraw: true

}

function graphInit(gr, label) {
    gr.label = label;
    gr.axisx = jsoncopy(Axis);
    gr.axisy = jsoncopy(Axis);
    gr.axisx.graph = gr;
    gr.axisy.graph = gr;
    gr.axisx.fsde = 14;
    gr.axisy.fsde = 14;

}
function graphDraw(gr, frm) {

    frm.ctx.lineWidth = gr.lw;
    var ticks3 = toint(gr.axisy.len1 / gr.axisy.gridlen / gr.axisy.ppv);
    var ticks4 = toint(gr.axisy.len2 / gr.axisy.gridlen / gr.axisy.ppv);

    gr.axisx.len3 = ticks3 * gr.axisy.gridlen * gr.axisy.ppv;// 
    gr.axisx.len4 = ticks4 * gr.axisy.gridlen * gr.axisy.ppv;//  

    ticks3 = toint(gr.axisx.len1 / gr.axisx.gridlen / gr.axisx.ppv);
    ticks4 = toint(gr.axisx.len2 / gr.axisx.gridlen / gr.axisx.ppv);

    gr.axisy.len3 = ticks3 * gr.axisx.gridlen * gr.axisx.ppv;// 
    gr.axisy.len4 = ticks4 * gr.axisx.gridlen * gr.axisx.ppv;//  


    axisxDraw(gr, frm);
    axisyDraw(gr, frm);

/// draw curves

    var i, j;
    for (i = 0; i < gr.curves.length; i++) {
        var cc = gr.curves[i];
        frm.ctx.lineWidth = cc.lw;
//for(j=0;j<cc.x.length;j++){

//    frm.drawtext(concat(toint(cc.x[j]),toint(cc.y[j])),i*64,96+j*13,12);
// }

        styles(frm.ctx, cc.ls, cc.fs);
        if (cc.filled === 0) {
            for (j = 0; j < cc.x.length; j++) {

                if (j > 0)
                    frm.drawline(cc.x[j - 1], cc.y[j - 1], cc.x[j], cc.y[j])

            }
        }
        if (cc.filled === 1) {

            frm.drawcurve(cc.x, cc.y, 1, false);

        }



    }

}
function graphSetCurve(gr, crv, arx, ary) {
    crv.x = [];
    crv.y = [];
    var i;
    for (i = 0; i < arx.length; i++) {
        var xx = gr.x0 + arx[i] * gr.axisx.ppv;
        var yy = gr.y0 - ary[i] * gr.axisy.ppv;
        crv.x.push(xx);
        crv.y.push(yy);
    }
}
function graphPoint(gr, frm, x, y, rx, ry) {
    frm.ctx.lineWidth = gr.lw;
    var xx = gr.x0 + x * gr.axisx.ppv;
    var yy = gr.y0 - y * gr.axisy.ppv;
//styles(frm.ctx,"red","yellow")
    frm.drawrect(xx - rx / 2, yy - ry / 2, rx, ry, 2);


}

function graphNewCurve(gr) {
    var nc = jsoncopy(Curve);
    gr.curves.push(nc);
    return nc;
}
function graphAddCurve(gr, arx, ary, pos) {

    var scx = gr.axisx.ppv;
    var scy = gr.axisy.ppv;

    var nc = jsoncopy(Curve);

    var i;
    for (i = 0; i < arx.length; i++) {
        nc.x.push(arx[i] * scx + gr.x0);
        nc.y.push(-ary[i] * scy + gr.y0);
    }

    if (!pos)
        gr.curves.push(nc);
    else
        gr.curves.splice(pos, 0, nc);


    return nc;

}

/// ppv pix per value 
// all attrs in logical units
// value len to add to value 0
var Axis = {
    len3: 1200,
    len4: 1200,
    graph: undefined,
    label: "Vlit",
    len1: 320,
    ppv: 300 / 20,
    gridlen: 5,
    valuelen: 5,

    value0: 0,

    fontsize: 14,
    fsde: 14


}
function axisSet(ax, label, len1, len2, ppv, gridlen, value0, valuelen) {
    ax.label = label;
    ax.len1 = len1;
    ax.len2 = len2;
    ax.ppv = ppv;
    ax.gridlen = gridlen;
    ax.value0 = value0;
    ax.valuelen = valuelen;

}
function axisxDraw(gr, frm) {

    var ax = gr.axisx;
    var fsde = ax.fsde;
    var x0 = gr.x0;
    var y0 = gr.y0;

/// draw 1 ticks
    var i, xs, ys;
    var gridpix = ax.gridlen * ax.ppv;
    var ticks1 = toint(ax.len1 / gridpix);
    var ticks2 = toint(ax.len2 / gridpix);
    var ticklen = ax.gridlen * ax.ppv;
    var valuestep = toint(ax.valuelen / ax.gridlen);
    frm.styles(gr.lsgrid, gr.fs);
    frm.drawtext(ax.value0, x0 - fsde, y0 + fsde, ax.fontsize)
    for (i = 1; i <= ticks1; i++) {
        xs = x0 + i * ticklen;
        ys = y0;


        frm.drawpolar(xs, ys, ax.len3, -Math.PI / 2);
        frm.drawpolar(xs, ys, ax.len4, +Math.PI / 2);
        if ((i % valuestep) === 0) {


            var val = ax.value0 + i / valuestep * ax.valuelen;//ax.vlen1/ticks1;
            frm.drawtext(val, xs, ys + fsde, ax.fontsize)
        }
    }
    for (i = 1; i <= ticks2; i++) {

        xs = x0 - i * ticklen;
        ys = y0;
        frm.drawpolar(xs, ys, ax.len3, -Math.PI / 2);
        frm.drawpolar(xs, ys, ax.len4, +Math.PI / 2);

        if ((i % valuestep) === 0) {


            var val = ax.value0 - i / valuestep * ax.valuelen;
            frm.drawtext(val, xs, ys + fsde, ax.fontsize)


        }


    }
    frm.drawtext(ax.label, x0 + ax.len1 + 2 * fsde, y0, 1.5 * ax.fontsize)
    frm.styles(gr.ls, gr.fs);
    frm.drawpolar(x0, y0, ax.len1, 0);
    frm.drawpolar(x0, y0, ax.len2, Math.PI);

}

function axisyDraw(gr, frm) {


    var ax = gr.axisy;
    var x0 = gr.x0;
    var y0 = gr.y0;
    var fsde = ax.fsde;
/// draw 1 ticks
    var i, xs, ys;
    var gridpix = ax.gridlen * ax.ppv;
    var ticks1 = toint(ax.len1 / gridpix);
    var ticks2 = toint(ax.len2 / gridpix);
    var ticklen = ax.gridlen * ax.ppv;
    var valuestep = toint(ax.valuelen / ax.gridlen);
    frm.styles(gr.lsgrid, gr.fs);

    for (i = 1; i <= ticks1; i++) {
        xs = x0;
        ys = y0 - i * ticklen;
        frm.drawpolar(xs, ys, ax.len3, 0);
        frm.drawpolar(xs, ys, ax.len4, Math.PI);
        if ((i % valuestep) === 0) {


            var val = ax.value0 + i / valuestep * ax.valuelen;
            frm.drawtext(val, xs - fsde, ys, ax.fontsize)
        }

    }
    for (i = 1; i <= ticks2; i++) {
        xs = x0;
        ys = y0 + i * ticklen;
        frm.drawpolar(xs, ys, ax.len3, 0);
        frm.drawpolar(xs, ys, ax.len4, Math.PI);
        if ((i % valuestep) === 0) {

            var val = ax.value0 - i / valuestep * ax.valuelen;//i*ax.vlen1/ticks1;
            frm.drawtext(val, xs - fsde, ys, ax.fontsize)
        }
    }
    frm.drawtext(ax.label, x0 - fsde, y0 - ax.len1 - 2 * fsde, 1.5 * ax.fontsize)
    frm.styles(gr.ls, gr.fs);
    frm.drawpolar(x0, y0, ax.len1, -Math.PI / 2);
    frm.drawpolar(x0, y0, ax.len2, Math.PI / 2);
}





