/**
    Vehicle homepage DHTML flyouts
    Copyright 2006 Organic
*/

Flyouts = {
   
    DEBUG: true,
   
    // VEHICLE_NAV_SELECTOR: '#nav_holder .veh_holder li a.vehicle',
    
    // FLYOUTS_DATA: FlyoutsData,
    
    SHADE_ID:  'shade',
    
    INTERVAL_TIME: 10,

    SHADE_OPACITY:           60,
    SHADE_ANIM_IN_DURATION:  300,
    SHADE_ANIM_OUT_DURATION: 150,
    SHADE_TWEEN_IN_FUNC:     Math.linearTween,
    SHADE_TWEEN_OUT_FUNC:    Math.linearTween,

    _flyout_ids: {},
    
    /**
        Initialize the flyouts system.
    */
    init: function() {
        // Debounce this init call.
        if (arguments.callee.done) return;
        arguments.callee.done = true;
            
    },

    /**
        Register a flyout by vehicle ID and element ID.
    */
    register: function(fid, eid) {
        this._flyout_ids[fid] = eid;
    },

    /**
        There's some inconsistency in the use of vehicle ids.
        This function is a hack to smooth out the differences.
    */
    fixupID: function(fid) {
        switch(fid) {
            case 'srt4': 
                fid='srt-4'; break;
            case 'ram_srt10': 
                fid='srt-10'; break;
            case 'stratus':
                fid = 'stratus_sedan'; break;
            case 'ram_truck':
                fid = 'ram_1500'; break;
        }
        return fid;
    },
    
    /**
        Populate the flyout with new data for a given flyout ID 
        record, showing it if necessary.
    */
    switchFlyout: function(fid) {
        
        fid = this.fixupID(fid);

        // HACK: Switch vehicle ID for nav
        // curVehicle = fid;
        // curModel   = '';

        // If this isn't a recognized flyout, vamoose.
        if (!this._flyout_ids[fid]) 
            return this.hideFlyout();
        
        // Hide all but the desired flyout.
        for (k in this._flyout_ids) {
            $(this._flyout_ids[k]).style.display = 
                (k == fid) ? 'block' : 'none';
            if ($(this._flyout_ids[k]+'-disclaimer'))
                $(this._flyout_ids[k]+'-disclaimer').style.display = 
                    (k == fid) ? 'block' : 'none';
        }
        
        // Reveal the shade layer, if necessary.
        this.enableShade();
    },
    
    /**
        Hide the flyout layer.
    */
    hideFlyout: function() {
        this.disableShade();
        
        // Hide all flyouts.
        for (k in this._flyout_ids) {
            $(this._flyout_ids[k]).style.display = 'none';
            if ($(this._flyout_ids[k]+'-disclaimer'))
                $(this._flyout_ids[k]+'-disclaimer').style.display = 'none';
        }
    },

    /**
        Safely reveal the shade, with animation.
    */
    enableShade: function() {
        // Debounce shade enable.
        if (this.shade_enabled) return;
        
        var shade = $(this.SHADE_ID);
        
        // Ensure that the shade's self-destruct is enabled.
        var _this = this;
        shade.onmouseover = function() { _this.hideFlyout(); }
        
        // Initiate shade animation.
        this.setOpacity(shade, 0);
        shade.style.display = "block";
        this.startShadeFadeIn();

        // Flag that the shade is enabled.
        this.shade_enabled = true;
    },
    
    /**
        Safely hide the shade, with animation.
    */
    disableShade: function() {
        // Debounce shade disable.
        if (!this.shade_enabled) return;

        var _this = this;
        this.startShadeFadeOut(function() { _this._hideShade(); });
        this.shade_enabled = false;
    },
    _hideShade: function() {
        var shade = $(this.SHADE_ID);
        shade.style.display = "none";
    },

    /**
        Prepare and start a fade-in animation for the shade.
    */
    startShadeFadeIn: function(cb) {
        this._shade_anim = {
            start_time: new Date().getTime(),
            last_time:  new Date().getTime(),
            duration:   this.SHADE_ANIM_IN_DURATION,
            start_opac: 0,
            curr_opac:  0,
            end_opac:   this.SHADE_OPACITY,
            opac_diff:  this.SHADE_OPACITY,
            tween_func: this.SHADE_TWEEN_IN_FUNC,
            callback:   cb
        };
        this.start();
    },

    /**
        Prepare and start a fade-out animation for the shade.
    */
    startShadeFadeOut: function(cb) {
        this._shade_anim = {
            start_time: new Date().getTime(),
            last_time:  new Date().getTime(),
            duration:   this.SHADE_ANIM_OUT_DURATION,
            start_opac: this.SHADE_OPACITY,
            curr_opac:  this.SHADE_OPACITY,
            end_opac:   0,
            opac_diff:  0 - this.SHADE_OPACITY,
            tween_func: this.SHADE_TWEEN_OUT_FUNC,
            callback:   cb
        };
        this.start();
    },
    
    /**
        Perform a step in an in-progress shade animation.
    */
    animateShade: function() {
       
        // Return if there's nothing to do.
        var anim = this._shade_anim;
        if (!anim) return;
        
        // Record now as the last time of animation.
        anim.last_time = new Date().getTime();
        
        // How long has this animation been going?
        var time_so_far = anim.last_time - anim.start_time;
        
        // Calculate the new opacity using the desired tween function
        anim.curr_opac = anim.tween_func(
            time_so_far, anim.start_opac, anim.opac_diff, anim.duration
        );
        
        // See how close to being done we are, and tweak the shade's opacity.
        var shade     = $(this.SHADE_ID);
        var goal_diff = Math.abs(anim.curr_opac - anim.end_opac);
        
        if ( (time_so_far < anim.duration) && (goal_diff > 1) ) {
            // Keep animating while there's still time and goal not reached.
            this.setOpacity(shade, anim.curr_opac);
        } else {
            // Time's up, or the goal's been reached - so set the final 
            // opacity, call the callback, destroy the task data.
            this.setOpacity(shade, anim.end_opac);
            if (anim.callback) anim.callback();
            this._shade_anim = null;
        }
    
    },

    /**
        Given an element and an percentage (0-100), modify the 
        element's opacity.
    */
    setOpacity: function(ele, perc) {
        if (ele.filters) {
            ele.filters.alpha.opacity = perc;
        } else if (ele.style) {
            var frac_opac = perc / 100;
            ele.style.MozOpacity   = frac_opac;
            ele.style.KHTMLOpacity = frac_opac;
            ele.style.opacity      = frac_opac;
        }
    },
    
    // TODO: Make this "threading" stuff abstract

    /**
        Perform a step in the "thread".  Stop the "thread" when it runs
        out of work to do.
    */
    run: function() {
        // Rememeber time it is.
        this._thisrun = new Date().getTime();

        if (this._shade_anim) {
            // If there's a shade to animate, do it.
						
            this.animateShade();
        } else {
            // If there's no other work to do, stop the "thread".
            this.stop();
        }

        // Remember what time it was.
        this._lastrun = this._thisrun;
    },

    /**
        Start running our interval-driven "thread".
    */
    start: function() {
        var _this = this;
        if (!this._interval)
            this._interval = setInterval(
                function() { _this.run(); }, 
                this.INTERVAL_TIME
            );
    },
    
    /**
        Stop running our interval-driven "thread".
    */
    stop: function() {
        if (this._interval) {
            clearInterval(this._interval);
            this._interval = null;
        }
    }

}

function flyoutsInit() {
    Flyouts.init();
}

// Wire up the on window load event.
/*
if (document.addEventListener) {
    document.addEventListener("DOMContentLoaded", flyoutsInit, null);
}
*/
addLoadEvent(flyoutsInit);


