/* $Id: sprite.js 175 2010-08-10 11:40:39Z victor $ */


/*
 *
 *  Sprite options:
 *
 *    name - for debugging
 *    parent - immediate parent container
 *
 *    flags (only apply to sprites that go through world.AddSprite()):
 *    
 *    visible - call the Draw() method on every step
 *              
 *    collidable - put this sprite into the collision detector
 *                 if you set this you'll need to define 'dimensions'
 *                 using a tooDeeDimensions thingy
 *               
 *    stationary - 'false' means assume this sprite needs to be
 *                  checked for collisions on every step. Only
 *                  looked at if 'collidable' is true
 *
 *
 *  Several types of sprites:
 *     the visible boundry wall
 *          these need to be in the collision testing queue
 *          not visible
 *          stationary
 *     walls in the game
 *          collision testing
 *          visible
 *          stationary
 *    characters
 *          characters are multiple sprites made to look like
 *          one thing; there is one 'selected' sprite that is
 *          visible, collidable and not stationary. The others
 *          are not visible and therefore not collidable. These
 *          flags need to be dynamically turned on and off.
 *
 *
*/
function tooDeeSprite( options )
{
    if( !options)
        return;
  
    this.parent = null;
    this.children   = new tooDeeList();
    
    // this will set all the options to
    // members
    tooDeeOptMix(this,this._defaults,options);
}

tooDeeMixin( tooDeeSprite, tooDeeObject, 
{
    dbg: 'tooDeeSprite',
    
    world:          null,

    _defaults: {
        visible: false,
        collidable: false,
        stationary: true,
        zOrder: 1
	},
    
    SetParent: function(parent)
    {
        this.parent = parent;
        
        var me = this;
        function getWorld(p)
        {
            if( p.world )
            {
                me.world = p.world;
                return;
            }
            else if( !p.parent )
            {
                throw "no parent or world found!"
            }
            
            getWorld(p.parent);
        }
        
        getWorld(this);
    },
    
    GetContext: function()
    {
        // not very OOpy but I don't have it in me
        // to call down 3 functions on every render
        // of every sprite on every step()
        return this.world.canvasWrapper.context;
    },
    
    AddChild: function( child )
    {
        this.children.Append( child );
        
        if( !child.parent || !child.world ) 
            child.SetParent(this);
            
        return child;
    },
    
    Children: function( func )
    {
        return this.children.Each( func );
    },
        
    Draw: function()
    {
        this.children.Propogate( 'Draw' );
    },
    
    DrawWire: function()
    {
        this.children.Propogate( 'DrawWire' );        
    },
    
    DrawBounds: function()
    {
        if( !this.dimensions )
            return;
        
        var D = this.dimensions;
        var context = this.GetContext();
        context.save();
        context.strokeStyle = 'blue';
        context.lineWidth   = this.world.MeterPerPixel();
        context.strokeRect( D.UL.x, D.UL.y, D.width, D.height );
        context.restore();

    },
    
    DebugDump: function()
    {
        this.children.Propogate('DebugDump');
        var globDim = this.dimensions ? this.dimensions : 'n/a';
        var
        str = '<b>' + this + '</b> ' + ' dim: ' + globDim;
        _log(str);
        this.DrawBounds();
    },
    
    CollideNotify: function()
    {
        
    },
    
    Destroy: function()
    {
        this.children.Propogate( 'Destroy' );
        this.children =
        this.world = 
        this.parent = null;
    }

});

function tooDeeSpriteWithEvents( options )
{
    tooDeeSprite.apply( this, [ options ] );
    tooDeeEventDelegator.apply( this );
}

tooDeeMixin(tooDeeSpriteWithEvents, tooDeeSprite, tooDeeEventDelegator.prototype );

tooDeeSpriteWithEvents.prototype.Destroy = function()
{
    tooDeeEventDelegator.prototype.Destroy.apply(this);
    tooDeeSprite.prototype.Destroy.apply(this);
}

/**************************************************
 *
 *  Invisible boundry around visible viewport
 *
 */
function tooDeeViewportBoundry( options )
{
    var defaults = {
        collidable: true,
        visible: false,
        stationary: true
    };
    
    tooDeeSprite.apply( this, [ tooDeeOptMix( {}, defaults, options ) ] );
    
};

tooDeeMixin(tooDeeViewportBoundry, tooDeeSprite,
{
    dbg: 'tooDeeViewportBoundry'

});

/**************************************************
 *
 *  Visible wall characters bump into
 *
 */

function tooDeeWallSection( options )
{
    tooDeeSprite.apply( this, [options] );
}

tooDeeMixin(tooDeeWallSection, tooDeeSprite,
{
    dbg: 'tooDeeWall',
    
    Draw: function()
    {
        var context = this.GetContext();
        context.save();
        context.fillStyle = this.color;
        var D = this.dimensions;
        context.fillRect( D.UL.x, D.UL.y, D.width, D.height );
        context.restore();
    }

});

function tooDeeWall( options )
{
    options.visible = true;

    tooDeeSprite.apply( this, [options] );

    this.name = 'wall-' + this.center.x + '/' + this.center.y;
    
    var me = this;
    
    function makeOpts()
    {
        return {
               stationary: true,
               collidable: true,
               dimensions: new tooDeeDimensions(),
               world: me.world,
               parent: me,
               color: '#AABBAA'            
        };
    }
    var opt1 = makeOpts();
    var opt2 = makeOpts();
    var wid = 0.15;
    
    if( this.isVert )
    {
        opt1.dimensions.Set(    this.center.x - wid,
                                this.center.y - (this.len/2),
                                this.center.x,
                                this.center.y + (this.len/2)
                            );
        opt2.dimensions.Set(    this.center.x,
                                this.center.y - (this.len/2),
                                this.center.x + wid,
                                this.center.y + (this.len/2)
                            );
        
        opt1.name = 'wall.left';
        opt2.name = 'wall.right';
    }
    else
    {
        opt1.dimensions.Set(    this.center.x - (this.len/2),
                                this.center.y - wid,
                                this.center.x + (this.len/2),
                                this.center.y
                            );

        opt2.dimensions.Set(    this.center.x - (this.len/2),
                                this.center.y,
                                this.center.x + (this.len/2),
                                this.center.y + wid
                            );
        
        opt1.name = 'wall.top';
        opt2.name = 'wall.bottom';
    }
    
    var wall1 = new tooDeeWallSection(opt1);
    var wall2 = new tooDeeWallSection(opt2);
    
    this.AddChild( wall1 );
    this.AddChild( wall2 );
    
    this.world.AddSprite(wall1);
    this.world.AddSprite(wall2);
};

tooDeeMixin(tooDeeWall, tooDeeSprite,
{
    dbg: 'tooDeeWall'

});

/**************************************************
 *
 *  Invisible mark for characters to bump into
 *
 *  This is a 'mark' as in an actor hits her mark on the stage or a
 *  film set. I couldn't think of a better name for the class that
 *  didn't require inside knowledge of show business - or, sorry -
 *  the theatrical arts.
 *
 *  You know, I used to live in Hollywood. In fact I went to Fairfax
 *  High. That's where Phil Spector went to school. You might know
 *  who that is based on his yet-another-celebrity-kills-a-beligerant-
 *  hooker trial a few years ago*, if not, ask your grandparents who
 *  he is. It's also where the Red Hot Chilli Peppers went. That's
 *  the CD (!) your mom plays on the way to soccer practice. They
 *  actually went AFTER I did so that's how fucking old I am.
 *
 *  It's also across the street, or, er, used to be 35 years ago,
 *  from where Spector built his recording studio and where some
 *  pretty amazing records were recorded. At time I was going there,
 *  Jeff Beck recorded Wired and (I think) Blow by Blow there. He's the
 *  guy in the Tina Turner wig that everybody over 40 keeps telling
 *  you is the greatest living guitar player because Jimi is dead.
 *  Who's Tina Turner? Never fucking mind.
 *  
 *  *Sincere appologies to the friends and family of the young
 *  woman this prick killed for no reason. I have no idea what
 *  she did for a living or what her rationale was for having
 *  sex with with an armed, toothless, crazy rich psychotic has-
 *  has-has-has-been could have been.
 */

function tooDeeMark( options )
{
    var defaults = {
        collidable: true,
        stationary: true
    };
    
    tooDeeSprite.apply( this, [ tooDeeOptMix({},defaults,options) ] );
    
    this.dimensions = new tooDeeDimensions();
    this.dimensions.Set( this.center.x - 0.3,
                         this.center.y - this.len/2,
                         this.center.x + 0.3,
                         this.center.y + this.len/2);
}

tooDeeMixin(tooDeeMark, tooDeeSprite,
{
    dbg: 'tooDeeMark'
});


/**************************************************
 *
 *  Cover full screen
 *
 */

function tooDeeFullScreen( options )
{
    var defaults = {
        visible: true,
        color: 'black'
    };
    
    tooDeeSprite.apply( this, [ tooDeeOptMix({},defaults,options) ] );
}

tooDeeMixin(tooDeeFullScreen, tooDeeSprite,
{
    dbg: 'tooDeeFullScreen',
    
    Draw: function()
    {
        var c = this.world.canvasWrapper;
        var ctx = this.GetContext()
        ctx.save();
        ctx.fillStyle = this.color;
        ctx.fillRect( 0, 0, c.width, c.height );
        ctx.restore();
        
    }
});

/**************************************************
 *
 *  Load and draw a web resource image
 *
 */

function tooDeeImage( options )
{
    var defaults = {
        visible: true,
        center: { x: 1, y: 1 },
        position: null,    // optional, if set 'center' is ignored
        url: '',
        image: null  // optional, if set 'url' is ignored
    };
    
    tooDeeSprite.apply( this, [ tooDeeOptMix({},defaults,options) ] );
    
    this.imageReady = false;
    
    if( this.url )
        this.SetURL(this.url);
}

tooDeeMixin(tooDeeImage, tooDeeSprite,
{
    dbg: 'tooDeeImage',
    
    SetURL: function(url)
    {
        this.url = url;
        this.image = new Image();
        var me = this;
        this.image.onload = function() {
            me.imgDim = me.world.CanvasToWorld( me.image.width, me.image.height );
            if( !me.position )
            {
                me.position = {
                    x: me.center.x - (me.imgDim.x/2) ,
                    y: me.center.y - (me.imgDim.y/2)            
                }
            }
            me.imageReady = true;
        }
        this.image.src = url;
    },
    
    Draw: function()
    {
        if( !this.imageReady )
            return;
        
        var ctx = this.GetContext();
        try {
            ctx.drawImage( this.image, 0, 0,
                                      this.image.width, this.image.height,
                                      this.position.x, this.position.y,
                                      this.imgDim.x, this.imgDim.y);
        }
        catch(e)
        {
            alert('If your window is "zoomed", try resetting and hit Refresh in your browser');
            throw "Zoom error";
        }
    }
});

/**************************************************
 *
 *  Initial screen
 *
 */

function tooDeeWelcome( options )
{
    var defaults = {
        visible: true
    };
    
    tooDeeSpriteWithEvents.apply( this, [ tooDeeOptMix({},defaults,options) ] );
    
    // this order implies a zOrder (I think)
    
    this.fullScreen = this.AddChild( new tooDeeFullScreen( {
        world: this.world, // required for ctor
        color: 'black'
    }));
    
    var dim = this.world.CanvasDim();
    
    this.titleImg = this.AddChild( new tooDeeImage( {
        url: '/images/PassageTitle.png',
        center: { x: dim.x/2, y: dim.y/2 }
    }));

    
    // hook things together:
    
    this.firedDone = false;
    
    this.imgFader = new tooDeeFader( {
        min: 0.0,
        max: 1.0,
        fps: 8,
        steps: 30,
        inc: true,
        world: this.world
    });
    
    this.imgFader.SetAlphaTarget(this.titleImg);
    
    // when that's done, add the remix animation
    this.imgFader.Bind( 'max', this._addRemix, this, 1 );
    
    
    this.fadeOut = new tooDeeFader( {
        min: 0.0,
        max: 1.0,
        fps: 12,
        steps: 10,
        dec: true,
        world: this.world
    });
    
    this.fadeOut.Freeze(true);
}

tooDeeMixin(tooDeeWelcome, tooDeeSpriteWithEvents,
{
    dbg: 'tooDeeWelcome',
    
    _addRemix: function()
    {
        this.firedDone = true;
        
        var remix = this.AddChild( new tooDeeLineFrameAnimation( {
            world: this.world, // required for ctor
            looping: false,
            autoStart: true,
            scale: 40,
            center: { x: 7.7, y: 6.5 },
            figureName: 'remix'
        }));

        remix.animator.Bind( 'cycle', this.Trigger, this, 1, 'titleDone' );
        
    },
    
    FadeOut: function(onDone,obj)
    {
        this.fadeOut.SetAlphaTarget(this);
        this.fadeOut.Bind( 'min', onDone, obj, 1 );
        this.fadeOut.Freeze(false);
        //this.children.Remove(this.titleImg);
    },
    
    Destroy: function()
    {
        this.imgFader.Destroy();
        this.imgFader = null;
        tooDeeSpriteWithEvents.prototype.Destroy.apply(this);
        
    }
});


