/* 
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

var PVector = function() {
    function PVector(x, y, z) {
        this.x = x || 0;
        this.y = y || 0;
        this.z = z || 0
    }
    PVector.dist = function(v1, v2) {
        return v1.dist(v2)
    };
    PVector.dot = function(v1, v2) {
        return v1.dot(v2)
    };
    PVector.cross = function(v1, v2) {
        return v1.cross(v2)
    };
    PVector.angleBetween = function(v1, v2) {
        return Math.acos(v1.dot(v2) / (v1.mag() * v2.mag()))
    };
    PVector.unitary = function(v1, v2) {
        var d = v1.dist(v2);
        return new PVector((v1.x-v2.x)/d, (v1.y-v2.y)/d, 0);
    }
    PVector.prototype = {
        set: function(v, y, z) {
            if (arguments.length === 1) this.set(v.x || v[0] || 0, v.y || v[1] || 0, v.z || v[2] || 0);
            else {
                this.x = v;
                this.y = y;
                this.z = z
            }
        },
        get: function() {
            return new PVector(this.x, this.y, this.z)
        },
        mag: function() {
            var x = this.x,
            y = this.y,
            z = this.z;
            return Math.sqrt(x * x + y * y + z * z)
        },
        add: function(v, y, z) {
            if (arguments.length === 1) {
                this.x += v.x;
                this.y += v.y;
                this.z += v.z
            } else {
                this.x += v;
                this.y += y;
                this.z += z
            }
        },
        sub: function(v, y, z) {
            if (arguments.length === 1) {
                this.x -= v.x;
                this.y -= v.y;
                this.z -= v.z
            } else {
                this.x -= v;
                this.y -= y;
                this.z -= z
            }
        },
        mult: function(v) {
            if (typeof v === "number") {
                this.x *= v;
                this.y *= v;
                this.z *= v
            } else {
                this.x *= v.x;
                this.y *= v.y;
                this.z *= v.z
            }
        },
        div: function(v) {
            if (typeof v === "number") {
                this.x /= v;
                this.y /= v;
                this.z /= v
            } else {
                this.x /= v.x;
                this.y /= v.y;
                this.z /= v.z
            }
        },
        dist: function(v) {
            var dx = this.x - v.x,
            dy = this.y - v.y,
            dz = this.z - v.z;
            return Math.sqrt(dx * dx + dy * dy + dz * dz)
        },
        dot: function(v, y, z) {
            if (arguments.length === 1) return this.x * v.x + this.y * v.y + this.z * v.z;
            return this.x * v + this.y * y + this.z * z
        },
        cross: function(v) {
            var x = this.x,
            y = this.y,
            z = this.z;
            return new PVector(y * v.z - v.y * z, z * v.x - v.z * x, x * v.y - v.x * y)
        },
        normalize: function() {
            var m = this.mag();
            if (m > 0) this.div(m)
        },
        limit: function(high) {
            if (this.mag() > high) {
                this.normalize();
                this.mult(high)
            }
        },
        heading2D: function() {
            return -Math.atan2(-this.y, this.x)
        },
        toString: function() {
            return "[" + this.x.toFixed(2) + ", " + this.y.toFixed(2) + ", " + this.z.toFixed(2) + "]"
        },
        array: function() {
            return [this.x, this.y, this.z]
        }
    };

    function createPVectorMethod(method) {
        return function(v1, v2) {
            var v = v1.get();
            v[method](v2);
            return v
        }
    }
    for (var method in PVector.prototype) if (PVector.prototype.hasOwnProperty(method) && !PVector.hasOwnProperty(method)) PVector[method] = createPVectorMethod(method);
    return PVector
}();

function PLine (x1, y1, x2, y2) {
    this.x1 = x1 || 0;
    this.y1 = y1 || 0;
    this.x2 = x2 || 0;
    this.y2 = y2 || 0;
    
    this.getX1 = function () {
        return this.x1;
    }

    this.getX2 = function () {
        return this.x2;
    }

    this.getY1 = function () {
        return this.y1;
    }

    this.getY2 = function () {
        return this.y2;
    }

    this.slope = function () {
        return (this.y2 - this.y1) / (this.x2 - this.x1);
    }
}

var G = 1.0;

function raton (a, v, l, _m, i) {
    var s = this;
    s.max_vel = -1;
    s.bounce = 1.0;

    s.gravity = new PVector(0, 0.05);
    s.isClashed = false;
    var ox=0, oy=0, sprite=0, inc=0.03;
    s.force = new PVector();
    s.wind = new PVector();
    s.radio = (i || 0) * (2*Math.PI/4);
    var image = imgs.get("raton");
    var overwheel = 0;
    s.acc = a.get();
    s.vel = v.get();
    s.loc = l.get();
    s.radius = 0;
    var estado = 0;
    s.mass = _m;
    s.w = 60;
    s.h = 60;
    s.r = 30;
    var rota = 0;
    var sca = 1;
    this.borrar = false;
    
  
    this.setEstado  = function(es) {
        estado = es;
    }
  
    this.getEstado = function () {
        return estado;
    }
  
    this.setOrigen = function (_ox, _oy) {
        ox = _ox;
        oy = _oy;
    }
  
    var posX = function (i) {
        return Math.floor(i%3)*image.width/3;
    }
  
    var posY = function (i) {
        return Math.floor(i/3)*image.height/2;
    }
  
    this.isOrigen = function (_ox, _oy) {
        return (ox == _ox && oy == _oy);
    }
  
    this.pintar = function(ctx) {
        var ww = 2*s.r, hh = 2*s.r;
        var x = s.loc.x, y = s.loc.y;
        sprite = (sprite+inc)%2;
        if(estado == 0) {              //Girando en una rueda
            var radio = 0;
            overwheel = 0;
        
            for(var i=0; i<ruedas.length; i++) {
                if(ruedas[i].x == ox && ruedas[i].y == oy) {
                    radio = ruedas[i].r;
                    s.loc.set(ruedas[i].x+50*Math.cos((radio+s.radio)-Math.PI/2),
                        ruedas[i].y+50*Math.sin((radio+s.radio)-Math.PI/2), 0);
                }
            }
        
            s.radius = radio + s.radio;
            ctx.save();
            ctx.translate(ox, oy);
            ctx.rotate(radio + s.radio);
            ctx.drawImage(image, posX(sprite), posY(sprite), ww, hh, -(ww/2+0), -(hh/2+50), ww, hh);
            ctx.restore();
        } else if (estado == 1) {     //Moviendose
            for(i=0; i<obstaculos.length; i++) {
                var obs = obstaculos[i].puntos;
                for(var j=0; j<obs.length; j++) {
                    if (s.collisionCircle(new PLine(obs[j][0], obs[j][1], obs[(j+1)%obs.length][0], obs[(j+1)%obs.length][1]))) {
                        s.radius += s.vel.x*0.02;
                        if(!s.isClashed)
                            //snds.get("rebote").play();
                        s.isClashed = true;
                    } else {
                        s.isClashed = false;
                    }
                }
            }
          
            for(i=0; i<ruedas.length; i++) {
                if (s.isCollidedCircleToCircle(ruedas[i].x, ruedas[i].y, 15)) {
                    s.setOrigen(ruedas[i].x, ruedas[i].y);
                    s.setEstado(0);
                }
            }
          
            for(i=0; i<cheeses.length; i++) {
                if (s.isCollidedCircleToCircle(cheeses[i].x, cheeses[i].y, 20)) {
                    cheeses[i].borrar = true;
                }
            }
          
            if (s.isCollidedCircleToCircle(salida.x, salida.y, salida.r-5)){
                estado = 3;
            }
          
            if(overwheel++ > 120) {
                //snds.get("muerto").play();
                estado = 2;
            }
          
            s.applyForces();
            s.update();
            ctx.save();
            ctx.translate(x, y);
            ctx.rotate(s.radius);
            ctx.drawImage(image, posX(2+sprite), posY(2+sprite), ww, hh, -ww/2, -hh/2, ww, hh);
            ctx.restore();
            
        } else if (estado == 2) {     //Muerta
            ctx.save();
            ctx.translate(x, y);
            ctx.rotate(s.radius);
            ctx.drawImage(image, posX(4), posY(4), ww, hh, -ww/2, -hh/2, ww, hh);
            ctx.restore();
        }else if (estado == 3) {
            ctx.save();
            ctx.translate(salida.x, salida.y);
            ctx.rotate(rota);
            ctx.scale(sca, sca)
            ctx.drawImage(image, posX(0), posY(0), ww, hh, -ww/2, -hh/2-30, ww, hh); 
            rota += 0.5;
            if(sca>0){
                sca -= 0.05; 
            }else{
                this.borrar = true;
                //snds.get("entra").play();
            }
            ctx.restore();
        }
    }

    this.update = function () {
        s.vel.add(s.acc);
        var desp = s.vel.get();
        desp.limit(10);
        s.loc.add(desp);
    }

    this.applyForces = function () {
        s.acc.mult(0);
        var W = s.gravity.get();
        W.mult(s.mass);                                                         //Calculando el peso del objeto
        s.acc.add(W);                                                           //Agregando el peso a las fuerzas puestas
        s.acc.add(s.force);                                                     //Agregando la fuerza (Generadas al colisionar con objetos)
        s.acc.add(s.wind);                                                      //Fuerza generada por el viento
        force = s.force.get();
        s.force.mult(0);
    }
    
    this.collisionCircle = function (l) {
        var u = mu(l, s.loc);

        if(u>=0 && u<=1) {
            var pt = new PVector(l.getX1()+u*(l.getX2()-l.getX1()), l.getY1()+u*(l.getY2()-l.getY1())), 
            d = pt.dist(s.loc), r = s.r;
                
            var U = PVector.unitary(pt, s.loc), pos = pt.get(), vel = s.vel.get(),
            dir = U.get(), frc = s.vel.mag(), ps = pt.get(), desp = s.vel.get();
            vel.normalize();
            desp.limit(40);
            vel.mult(1);
            ps.add(vel);
            
            if(d <= r+desp.mag() && ps.dist(s.loc) > d) {
                dir.mult(r);
                pos.sub(dir);               //Posicion de la bolita sobre la recta
                U.mult(-frc);               //Fuerza respecto la direccion anterior
                s.force.add(U);             //Sumar la fuerza calculada a la fuerza total
                s.loc = pos.get();          //Cambiar la posicion a la posicion correcta del objeto
                unit = U.get();
                
                return true;
            }
        }
        
        return false;
    }
    
    this.stopWheelandListen = function () {
        for(var i=0; i<ruedas.length; i++) {
            ruedas[i].lock = (ruedas[i].x == ox && ruedas[i].y == oy)
        }
    }
    
    this.isCollidedCircleToCircle = function (x, y, r) {
        var loc = new PVector(x, y);
        return (s.loc.dist(loc) <= r+s.r);
    }
    
    this.isCollidedCircleToLine = function (l) {
        var u = mu(l, s.loc);
        if(u>=0 && u<=1) {
        //Despues se termina...
        }
    }
}

function wheel(_x, _y, _rueda) {
    var image = (!_rueda)? "rueda" : _rueda;
    this.lock = false;
    this.x = _x;
    this.y = _y;
    this.a = 0;
    this.r = 0;
    
    this.pintar = function (ctx) {
        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.rotate(this.r);
        ctx.drawImage(imgs.get(image), -40, -40);
        this.r += (!this.lock)? 0.02 : 0;
        ctx.restore();
    }
}

function mu (l, p) {
    var Ax = l.getX1(), Ay = l.getY1(), 
    Bx = l.getX2(), By = l.getY2(),
    Cx = p.get().x, Cy = p.get().y;
    return ((Cx-Ax)*(Bx-Ax) + (Cy-Ay)*(By-Ay)) / (Math.pow(Bx-Ax, 2) + Math.pow(By-Ay, 2));
}

function sign (n) {
    return n/Math.abs(n) || 1;
}

function imagenes () {
    var img = [];
    
    this.add = function (imagen, directorio) {
        img[imagen] = new Image();
        img[imagen].src = directorio;
    }
    
    this.get = function (imagen) {
        return img[imagen];
    }
    
    this.isLoaded = function () {
        var carga = true;
        for (var k in img) {
            if (img.hasOwnProperty(k)) {
                carga = (!carga)? false : img[k].complete;
            }   
        }
        
        return carga;
    }
    
}
 
function quesos(_x, _y, _w, _h, i, _image){
    var image = _image;
    this.x = _x;
    this.y = _y;
    this.width = _w;
    this.height = _h;
    var inicio = i;
    var escalar = 0.03;
    this.borrar = false;
    
    this.pintar = function (ctx) {
        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.scale(inicio, inicio);
        ctx.drawImage(imgs.get(image), -this.width/2, -this.height/2);
        ctx.restore();
        inicio += escalar;
        if(inicio > 1 || inicio < 0.5) {
            escalar = -escalar;
        }
    }
}

//puntos: [[x1, y1], [x2, y2], ..., [xn, yn]];
function barras(_x, _y, _inclinacion, _sx, _sy, _puntos, _ignorepaint, _barra) {
    var inclinacion = _inclinacion;
    var ignorepaint = _ignorepaint || false;
    this.puntos = _puntos;
    var sx = _sx;
    var sy = _sy;
    var x = _x;
    var y = _y;
    var barra = (!_barra)? "muro" : _barra;
    
    this.pintar = function (ctx) {
        if(!ignorepaint) {
            ctx.save();
            ctx.translate(x, y);
            ctx.rotate(inclinacion);
            ctx.scale(sx, sy);
            ctx.drawImage(imgs.get(barra), -imgs.get(barra).width/2, -imgs.get(barra).height/2);
            ctx.restore();
//            ctx.strokeStyle= "#f00";
//            for(var i=0; i<4; i++) {
//                ctx.beginPath();
//                    ctx.moveTo(this.puntos[i][0], this.puntos[i][1]);
//                    ctx.lineTo(this.puntos[(i+1)%this.puntos.length][0], this.puntos[(i+1)%this.puntos.length][1])
//                    ctx.stroke();
//            }
        }
    }
}

function salir (x, y, _exit) {
    this.x = x;
    this.y = y;
    this.r = 20;
    var exit = (!_exit)? "exit2" : _exit;
    
    this.pintar = function (ctx) {
        ctx.drawImage(imgs.get(exit), this.x-imgs.get(exit).width/2, this.y-imgs.get(exit).height/2);
    }
}

function sonidos (){
    var snd = [];
  
    this.add = function (sonido, directorio) {
        snd[sonido] = document.createElement("audio");
        snd[sonido].setAttribute('src', directorio);
        snd[sonido].autobuffer = true;
        snd[sonido].loop = true;
        snd[sonido].load();
    }
  
    this.get = function (sonido) {
        return snd[sonido];
    }
}