I=(S=Flocking = function(){
}).prototype;

I.FixedUpdate = function()
{
    var r = Uno.Random.$0(Uno.Application.Time()|0);

    for (var i = 0; i < this.positions.length; i++)
    {
        var bestFollow = -1;
        var bestScore = -100000.0;
        var bestDir = Uno.Float3.operator_Sub_1(r.NextFloat3(), 0.5);

        for (var n = 0; n < this.positions.length; n++)
        {
            if (n == i)
            {
                continue;
            }

            var dir = Uno.Float3.operator_Sub(this.positions[n], this.positions[i]);

            if (Uno.Vector.Length(dir) < 7.0)
            {
                continue;
            }

            var score = Uno.Vector.Dot(Uno.Vector.Normalize(dir), Uno.Vector.Normalize(this.velocities[i])) / Math.sqrt(Uno.Vector.Length(dir));

            if (score > bestScore)
            {
                bestScore = score;
                bestFollow = n;
                bestDir = Uno.Vector.Normalize(dir);
            }
        }

        this.velocities[i] = Uno.Float3.operator_Add(this.velocities[i], bestDir);
        this.velocities[i] = Uno.Float3.operator_Add(this.velocities[i], Uno.Float3.operator_Mul_1(Uno.Float3.operator_Sub_1(r.NextFloat3(), 0.5), 0.65));

        if (bestFollow != -1)
        {
            this.velocities[i] = Uno.Float3.operator_Add(this.velocities[i], Uno.Float3.operator_Mul_1(this.velocities[bestFollow], 0.03));
        }

        this.velocities[i] = Uno.Float3.operator_Mul_1(this.velocities[i], 0.91);
        this.positions[i] = Uno.Float3.operator_Add(this.positions[i], Uno.Float3.operator_Mul_1(this.velocities[i], 0.12));
    }
};

I.Draw = function()
{
    for (var i = 0; i < this.positions.length; i++)
    {
        var angle = Math.acos(Uno.Vector.Normalize(this.velocities[i]).Z);
        var axis = Uno.Vector.Normalize(Uno.Vector.Cross(Uno.Float3.$1(0.0, 0.0, 1.0), Uno.Vector.Normalize(this.velocities[i])));
        this.t.Transform.Local(Uno.Matrix.Mul(Uno.Matrix.RotationAxis(axis, angle), Uno.Matrix.Translation(Uno.Float3.operator_Mul(this.positions[i], Uno.Float3.$0(3.0)))));
        this.t.DrawDraw();
    }
};

S.$0 = function($this) {
    if (!$this) $this = new Flocking;
    $this.t = Tetrahedra.$0();
    $this.positions = _newFilledArray(200, function() { return new Uno.Float3; });
    $this.velocities = _newFilledArray(200, function() { return new Uno.Float3; });
    var r = Uno.Random.$0(1);

    for (var i = 0; i < $this.positions.length; i++)
    {
        $this.positions[i] = Uno.Float3.operator_Mul(r.NextFloat3(), Uno.Float3.$0(100.0));
        $this.velocities[i] = Uno.Float3.$1(0.0, 0.0, 0.0);
    }

    return $this;
};
