
( WaveDotDirection = new function ()
{

    this.RIGHT = 1;
    this.DOWNRIGHT = 2;
    this.DOWN = 3;
    this.DOWNLEFT = 4;
    this.LEFT = 5;
    this.UPLEFT = 6;
    this.UP = 7;
    this.UPRIGHT = 8;

    this.getPointFromDirection = function ( d )
    {
        var p = new createjs.Point();
        if ( d == this.RIGHT || d == this.DOWNRIGHT || d == this.UPRIGHT ) p.x = 1;
        if ( d == this.LEFT || d == this.DOWNLEFT || d == this.UPLEFT ) p.x = -1;
        if ( d == this.UP || d == this.UPLEFT || d == this.UPRIGHT ) p.y = -1;
        if ( d == this.DOWN || d == this.DOWNLEFT || d == this.DOWNRIGHT ) p.y = 1;

        return p;
    }

} );

( WaveDot = function ( _start, _direction, _lifetime )
{
    this.direction = null;
    this.start = null;
    this.pos = null;
    this.lifetime = 0;
    this.life = 0;

    this.init = function ( start, direction, lifetime )
    {
        this.start = start;
        this.pos = new createjs.Point( start.x, start.y );
        this.direction = direction;
        this.lifetime = lifetime;

    }

    this.walk = function ()
    {
        var pt = WaveDotDirection.getPointFromDirection( this.direction );
        this.pos.x += pt.x;
        this.pos.y += pt.y;
        this.life++;
    }

    this.isAlive = function ()
    {
        return ( this.life < this.lifetime );
    }

    this.init( _start, _direction, _lifetime );
} );

( WaveBase = function ()
{
    this.dots = new Array();
    this.powerUp = null;
    this.table = null;
    this.timeToNext = 0;
    this.time = 0;
    this.active = true;
    this.interval = 0;
    this.start = null;
    this.curPos = null;

    this.superInit = function ( table, powerUp, start, params )
    {
        this.table = table;
        this.start = start;
        this.start.prototype = new createjs.Point();
        this.curPos = new createjs.Point( this.start.x, this.start.y );
        this.powerUp = powerUp;
        this.time = 0;
    }

    this.addDot = function ( wd )
    {
        this.dots.push( wd );
    }

    this.mergeDot = function ( wd )
    {
        //wd = new WaveDot();
        for ( var i = 0; i < this.dots.length; i++ )
        {
            var dot = this.dots[i];
            if ( dot.direction == wd.direction )
            {
                dot.lifetime += ( wd.lifetime - wd.life + 1 );
            }
        }
    }

    this.update = function ()
    {
        if ( !this.active ) return;

        if ( this.time >= this.timeToNext )
        {
            this.walk();
            this.nextTimeToNext();
        }
        else
        {
            this.time++;
        }

    }

    this.setJewel = function ( wd )
    {
        //trace( "Set: " + wd.pos );
        this.table.setJewel( wd.pos, this.powerUp.type, null, true );
        this.table.activateJewelSuperPower( wd.pos, wd );
    }

    this.nextTimeToNext = function ()
    {
        this.time = 0;
    }

    this.destroy = function ()
    {
        this.table = null;
        this.start = null;
        this.curPos = null;
        this.active = false;
    }

    this.walk = function ()
    {
        var stillAlive = false; //the cake is a lie
        //for each( var wd in this.dots )
        for ( var i = 0; i < this.dots.length; i++ )
        {
            var wd = this.dots[i];
            if ( wd.isAlive() )
            {
                wd.walk();
                this.setJewel( wd );
                stillAlive = true;
            }
        }

        if ( !stillAlive )
        {
            if ( !this.nextStep() )
            {
                this.active = false;
            }
        }

    }

    //to be overridden when needed;
    this.nextStep = function ()
    {
        return false;
    };

    this.str = function ()
    {
        return this.powerUp.level
    };
} );

( UniDirectional = function ()
{
    this.direction;

    this.init = function ( table, powerUp, start, params )
    {
        this.superInit( table, powerUp, start, params );
        this.direction = params.direction;

        switch ( this.direction )
        {
            case 1:
                this.addDot( new WaveDot( start, WaveDotDirection.RIGHT, this.str() ) );
                break;
            case 2:
                this.addDot( new WaveDot( start, WaveDotDirection.DOWN, this.str() ) );
                break;
            case 3:
                this.addDot( new WaveDot( start, WaveDotDirection.LEFT, this.str() ) );
                break;
            case 4:
                this.addDot( new WaveDot( start, WaveDotDirection.UP, this.str() ) );
                break;
        }
    }

    //Override
    this.str = function ()
    {
        return this.powerUp.level + 1;
    }

} ).prototype = new WaveBase();

( BiDirecional = function ()
{
    this.isVertical = false;

    this.init = function ( table, powerUp, start, params )
    {
        this.superInit( table, powerUp, start, params );
        this.isVertical = params.isVertical;

        if ( this.isVertical )
        {
            this.addDot( new WaveDot( start, WaveDotDirection.UP, this.str() ) );
            this.addDot( new WaveDot( start, WaveDotDirection.DOWN, this.str() ) );
        }
        else
        {
            this.addDot( new WaveDot( start, WaveDotDirection.LEFT, this.str() ) );
            this.addDot( new WaveDot( start, WaveDotDirection.RIGHT, this.str() ) );
        }
    }

} ).prototype = new WaveBase();

( LWave = function ()
{
    this.direction;
    this.pt1;
    this.pt2;

    this.init = function ( table, powerUp, start, params )
    {
        this.superInit( table, powerUp, start, params );
        this.direction = params.direction;

        if ( this.direction == 1 || this.direction == 2 ) this.addDot( new WaveDot( start, WaveDotDirection.RIGHT, this.str() ) );
        if ( this.direction == 3 || this.direction == 4 ) this.addDot( new WaveDot( start, WaveDotDirection.LEFT, this.str() ) );
        if ( this.direction == 1 || this.direction == 4 ) this.addDot( new WaveDot( start, WaveDotDirection.UP, this.str() ) );
        if ( this.direction == 2 || this.direction == 3 ) this.addDot( new WaveDot( start, WaveDotDirection.DOWN, this.str() ) );

        this.pt1 = this.start.clone();
        this.pt2 = this.start.clone();
    }

} ).prototype = new WaveBase();

( Crossed = function ()
{
    this.init = function ( table, powerUp, start, params )
    {
        this.superInit( table, powerUp, start, params );
        this.addDot( new WaveDot( start, WaveDotDirection.RIGHT, this.str() ) );
        this.addDot( new WaveDot( start, WaveDotDirection.DOWN, this.str() ) );
        this.addDot( new WaveDot( start, WaveDotDirection.LEFT, this.str() ) );
        this.addDot( new WaveDot( start, WaveDotDirection.UP, this.str() ) );
    }

} ).prototype = new WaveBase();

( Spiral = function ()
{
    this.step = 0;
    this.curDot;
    this.direction;
    this.d;

    this.init = function ( table, powerUp, start, params )
    {
        this.superInit( table, powerUp, start, params );

        this.direction = params.direction;

        if ( this.direction == 1 )
        {
            this.d = WaveDotDirection.RIGHT
        };
        if ( this.direction == 2 || this.direction == 4 )
        {
            this.d = WaveDotDirection.DOWN;
        }
        if ( this.direction == 3 )
        {
            this.d = WaveDotDirection.LEFT
        };

        this.curDot = new WaveDot( start, this.d, 1 );
        this.addDot( this.curDot );
    }

    this.nextStep = function ()
    {
        this.step++;
        if ( this.step == 1 )
        {
            if ( this.direction == 1 || this.direction == 3 ) this.d = WaveDotDirection.DOWN;
            if ( this.direction == 2 ) this.d = WaveDotDirection.LEFT;
            if ( this.direction == 4 ) this.d = WaveDotDirection.RIGHT;

            this.curDot = new WaveDot( this.curDot.pos.clone(), this.d, 1 )
            this.addDot( this.curDot );
        }
        else if ( this.step == 2 )
        {
            if ( this.direction == 1 ) this.d = WaveDotDirection.LEFT;
            if ( this.direction == 2 || this.direction == 4 ) this.d = WaveDotDirection.UP;
            if ( this.direction == 3 ) this.d = WaveDotDirection.RIGHT;

            this.curDot = new WaveDot( this.curDot.pos.clone(), this.d, ( this.str() < 2 ? 1 : 2 ) );
            this.addDot( this.curDot );
        }
        else if ( this.step == 3 && this.str() >= 2 )
        {
            if ( this.direction == 1 || this.direction == 3 ) this.d = WaveDotDirection.UP;
            if ( this.direction == 2 ) this.d = WaveDotDirection.RIGHT;
            if ( this.direction == 4 ) this.d = WaveDotDirection.LEFT;

            this.curDot = new WaveDot( this.curDot.pos.clone(), this.d, ( this.str() == 2 ? 1 : 2 ) );
            this.addDot( this.curDot );
        }
        else if ( this.step == 4 && this.str() >= 3 )
        {
            if ( this.direction == 1 ) this.d = WaveDotDirection.RIGHT;
            if ( this.direction == 2 || this.direction == 4 ) this.d = WaveDotDirection.DOWN;
            if ( this.direction == 3 ) this.d = WaveDotDirection.LEFT;

            this.curDot = new WaveDot( this.curDot.pos.clone(), this.d, ( this.str() == 3 ? 2 : 3 ) );
            this.addDot( this.curDot );
        }
        else
        {
            return false;
        }

        this.walk();

        return true;

    }

} ).prototype = new WaveBase();

( MagneticWave = function ()
{
    this.curOrigin = null;
    this.nearest = null;
    this.curDot = null;
    this.step = 0;
    this.effectPhaseTwo = true;

    this.init = function ( table, powerUp, start, params )
    {
        this.superInit( table, powerUp, start, params );
        this.nearest = this.getNear( start );
        if ( this.nearest != null )
        {
            this.startNewPowerEffect();
        }
    }

    this.startNewPowerEffect = function ()
    {
        var dir = ( this.curOrigin.x > this.nearest.x ? WaveDotDirection.LEFT : WaveDotDirection.RIGHT );
        var lt = Math.abs( this.nearest.x - this.curOrigin.x );
        this.table.getJewelAt( this.nearest.x, this.nearest.y ).flash();
        this.curDot = new WaveDot( this.curOrigin, dir, lt );
        this.addDot( this.curDot );
        this.effectPhaseTwo = true;
    }

    this.nextStep = function ()
    {
        if ( this.step < this.powerUp.level )
        {
            if ( this.effectPhaseTwo )
            {
                if ( this.curDot == null || this.curDot.pos == null ) return false;

                var pt = this.curDot.pos.clone();
                var dir = ( pt.y > this.nearest.y ? WaveDotDirection.UP : WaveDotDirection.DOWN );
                var lt = Math.abs( this.nearest.y - pt.y );
                this.curDot = new WaveDot( pt, dir, lt );
                this.addDot( this.curDot );
                this.step++;
                this.effectPhaseTwo = false;
            }
            else
            {
                this.nearest = this.getNear( this.curDot.pos.clone() );
                if ( this.nearest != null )
                {
                    this.startNewPowerEffect();
                }
                else
                {
                    this.step++;
                    return false;
                }
            }

            return true;

        }
        return false;
    }

    this.getNear = function ( st )
    {
        this.curOrigin = st;
        this.table.findAllCombinations();
        var comb = this.table.findCombinationFrom( this.curOrigin.x, this.curOrigin.y );
        if ( comb == null ) return null;

        var ret = null;
        var distance = Number.MAX_VALUE;
        var p = null;
        var j = null;

        for ( var x = 0; x < this.table.tableWidth; x++ )
        {
            for ( var y = 0; y < this.table.tableHeight; y++ )
            {
                p = new createjs.Point( x, y );
                j = this.table.getJewelAt( x, y );
                if ( this.powerUp.type == j.type && !comb.containsPoint( p ) )
                {
                    var dt = Tools.getDistance( this.curOrigin, p );
                    if ( dt < distance )
                    {
                        distance = dt;
                        ret = new createjs.Point( x, y );
                    }
                    else if ( dt == distance && Math.random() < .5 )
                    {
                        ret = new createjs.Point( x, y );
                    }
                }
            }
        }
        return ret;
    }

} ).prototype = new WaveBase();

( BufferJewel = function ()
{
    this.type;
    this.powerUp;
    this.isTimer = false;

    this.init = function ( _type, _powerUp, _isTimer )
    {
        this.type = _type;
        this.powerUp = _powerUp;
        this.isTimer = _isTimer;
    }
} );