GlowAnimation = function () {


    var supportsOpacity = jQuery.support.opacity;
    var glow = null;
    var glowWidth = 0;
    var glowHeight = 0;
    var glowLoaded = false;

    var flickr = null;
    var flickrLoaded = false;

    var ref = null;
    var refLoaded = false;

    var origin = null;
    var flickrOrigin = null;
    var leftOffset = 0;
    var topOffset = 15;

    // some default values	
    var animationDuration = 4320;
    var glowDuration = 250;
    var flickrDuration = 500;
    var pauseDuration = 4000; // set to 0 to indicate "no repeat"

    var pathMap = [
		{ left: -70, top: 360 }
		, { left: -187, top: 349 }
		, { left: -308, top: 288 }
		, { left: -383, top: 188 }
		, { left: -460, top: 128 }
		, { left: -558, top: 70 }
		, { left: -676, top: 32 }
		, { left: -788, top: 39 }
		, { left: -975, top: 60 }
    //	, { left: -975, top: 145 }
		, { left: -1000, top: 176 }
    //	, { left: -975, top: 229 }
    //, { left: -912, top: 270 }
	];
    var pathMapIdx = 0;

    var flickrPos = { left: -940, top: 260 };  // flickr's starting position

    var sleepStep = false;
    var currentlyPaused = false;
    var timer = null;

    var cfg = {
        /*
        * microAnimationDistance: defines how far the glow image will move in whatever direction
        * 	specified by the pathMap.
        */
        microAnimationDistance: -15

        /*
        * finalAnimationDistance: defines how far the flickr image will move to the right at the
        *  end of the animation
        */
		, finalAnimationDistance: 150

        /*
        * flickrOpacityStart: starting point for opacity animation on flickr
        */
		, flickrOpacityStart: .5

        /*
        * fadeBeforeLoopDuration: duration of "fade out" effect on flickr, immediately preceding a
        *  new animation cycle
        */
		, fadeBeforeLoopDuration: 200

        /*
        * scaleGlowPastNative: when true glow image grows from 50% to 200%
        * 	otherwise it grows from 8% to 100%
        */
		, scaleGlowPastNative: true

        /*
        * glowZIndex: CSS z-layer attribute for glow image.  Flickr image will be glowZIndex-1
        */
		, glowZIndex: 5
    };

    var endAnimation = false;

    /******************************************************************************/
    /*
    /* Initialize the animation
    /*   See accompanying HTML document for what values should be passed to init.
    /*
    /******************************************************************************/
    function init(glowSrc, flickrSrc, refElementId, _leftOffset, _topOffset,
		_animationDuration, _flickrDuration, _pauseDuration) {
        //console.log("init() entered.");

        // check optional parameters
        if (typeof _leftOffset != "undefined") leftOffset = _leftOffset;
        if (typeof _topOffset != "undefined") topOffset = _topOffset;
        if (typeof _animationDuration != "undefined") animationDuration = _animationDuration;
        if (typeof _flickrDuration != "undefined") flickrDuration = _flickrDuration;
        if (typeof _pauseDuration != "undefined") pauseDuration = _pauseDuration;

        // add glow image to DOM
        //var glowHTML = '<img id="animatedGlow" src="' + glowSrc + '" ' +
        //	'style="display:none; position:absolute;" />';
        //$("#" + refElementId).before(glowHTML);

        // add flickr image to DOM 
        //var flickrHTML = '<img id="animatedFlickr" src="' + flickrSrc + '" ' +
        //	'style="display:none; position:absolute; z-index:" + (cfg.glowZIndex-1) + ";" />';
        //$("#animatedGlow").after(flickrHTML);

        // bind load event
        //$("#animatedGlow").load(animatedGlow_loadHandler);
        //$(".flicker1").load(animatedFlickr_loadHandler);

        // cache jQuery object references
        glow = $("#animatedGlow");
        $(".flicker1").hide();
        //flickr.replaceWith("<div id='flickerImage'></div>");
        flickr = $("#flickerImage");
        //        flickr.append("<div class='f1'></div>");
        //        flickr.append("<div class='f2'></div>");
        //        flickr.append("<div class='f3'></div>");
        //        flickr.append("<div class='f4'></div>");
        ref = $("#" + refElementId);

        initAnimation();
    }

    /******************************************************************************/
    function animatedGlow_loadHandler() {
        //console.log("animatedGlow_loadHandler() entered.");
        alert("animatedGlow loaded");
        glowLoaded = true;
    }

    /******************************************************************************/
    function findOrigin() {
        //console.log("findOrigin() entered.");

        /*
        * The following formula calculates the position of the glow image to be centered
        * on the top-right corner of the reference element.
        */
        var leftOrigin = ref.offset().left + ref.width() - Math.floor(glow.width() / 2);
        var topOrigin = ref.offset().top - Math.floor(glow.height() / 2);

        /*
        * We may also need to adjust down and to the left to locate the top of the main
        * graphic, which the custom path is supposed to cross.
        * 
        * These are the offset values collected during the calibration step.
        */
        leftOrigin += leftOffset;
        topOrigin += topOffset;

        /* store calculated origin */
        origin = {
            left: leftOrigin
			, top: topOrigin
        };

        glowWidth = glowWidth == 0 ? glow.width() : glowWidth;
        glowHeight = glowHeight == 0 ? glow.height() : glowHeight;
    }

    /******************************************************************************/
    function animatedFlickr_loadHandler() {
        //console.log("animatedFlickr_loadHandler() entered.");
        alert("animatedFlickr loaded");
        flickrLoaded = true;
    }

    /******************************************************************************/
    function findFlickrOrigin() {
        //console.log("findFlickrOrigin() entered.");

        /*
        * The following formula calculates the position of the flickr image to be centered
        * on the top-right corner of the reference element.
        */
        var leftOrigin = ref.offset().left + ref.width() - Math.floor(flickr.width() / 2);
        var topOrigin = ref.offset().top - Math.floor(flickr.height() / 2);

        /*
        * We may also need to adjust down and to the left to locate the top of the main
        * graphic, which the custom path is supposed to cross.
        * 
        * These are the offset values collected during the calibration step.
        */
        leftOrigin += leftOffset;
        topOrigin += topOffset;

        /* store calculated origin */
        flickrOrigin = {
            left: leftOrigin
			, top: topOrigin
        };
    }

    /******************************************************************************/
    //function ref_loadHandler() {
    //console.log("ref_loadHandler() entered.");
    //alert("ref loaded");
    //    refLoaded = true;
    //}

    /******************************************************************************/
    function initAnimation() {
        //console.log("initAnimation() entered.");

        // only execute if all necessary elements are fully loaded
        //if (glowLoaded && flickrLoaded) {
        //alert("begin animation");
        findOrigin();
        //findFlickrOrigin();
        runAnimation();
        //}
    }

    /******************************************************************************/
    function runAnimation() {
        //console.log("runAnimation() entered.");
        if (supportsOpacity) {
            glow.css({
                left: origin.left + pathMap[0].left,
                top: origin.top + pathMap[0].top,
                display: "block",
                opacity: 0.3
            });
        } else {
            glow.css({
                left: origin.left + pathMap[0].left,
                top: origin.top + pathMap[0].top,
                display: "block"
            });
        }
        doStep();
    }

    /******************************************************************************/
    function doStep() {
        //console.log("doStep() entered. (iteration=" + pathMapIdx + ")");
        if (!endAnimation) {
            if (pathMapIdx + 1 < pathMap.length) {

                /* 
                * Pull position and direction that define the path of the animation
                * for this step.
                */
                var step = pathMap[pathMapIdx];
                var stepNext;
                if (pathMapIdx + 1 < pathMap.length) {
                    stepNext = pathMap[pathMapIdx + 1];
                }

                /* load animation attributes for this step */
                var leftMoveAmount = cfg.microAnimationDistance;
                if (typeof step.leftMove != "undefined") {
                    leftMoveAmount = step.leftMove;
                } else {
                    if (typeof stepNext != "undefined") {
                        leftMoveAmount = (stepNext.left - step.left) / 2;
                    }
                }

                var topMoveAmount = 0;
                if (typeof step.topMove != "undefined") {
                    topMoveAmount = step.topMove;
                } else {
                    if (typeof stepNext != "undefined") {
                        topMoveAmount = (stepNext.top - step.top) / 2;
                    }
                }

                var start;
                var end = {
                    left: leftMoveAmount,
                    top: topMoveAmount
                }


                animateGlow(start, end, Math.floor(animationDuration / pathMap.length * 0.5));
                sleepStep = !sleepStep;
                if (sleepStep)
                    pathMapIdx++;


                //                if (sleepStep) {
                //                    /* do one micro-animation */
                //                    //animateGlow(start, end, Math.floor(glowDuration / pathMap.length * 0.75), "none");
                //                    pathMapIdx++;
                //                    sleepStep = false;
                //                }
                //                else {

                //                    /* load animation attributes for this step */
                //                    /*var scaleModifier = 0;
                //                    if (cfg.scaleGlowPastNative)
                //                    scaleModifier = 6;
                //                    var start = {
                //                    left: origin.left + step.left
                //                    , top: origin.top + step.top
                //                    , width: Math.floor(((pathMapIdx + 1 + scaleModifier) / pathMap.length) * glowWidth)
                //                    , height: Math.floor(((pathMapIdx + 1 + scaleModifier) / pathMap.length) * glowHeight)
                //                    }
                //                    var end = {
                //                    left: origin.left + step.left + leftMoveAmount
                //                    , top: origin.top + step.top + topMoveAmount
                //                    }*/

                //                    /* do one micro-animation */

                //                    //animateGlow(start, end, Math.floor(glowDuration / pathMap.length * 0.25), "block");
                //                    animateGlow(start, end, Math.floor(animationDuration / pathMap.length * 0.5), 1.0);
                //                    //glow.hide();
                //                    //pathMapIdx++;
                //                    sleepStep = true;
                //                }
            }
            else {
                /* glow micro-animations complete. */
                pathMapIdx = 0;
                animationFinalStep();
            }
        }
    }

    function showGlow() {
        if (!endAnimation) {
            glow.animate({ opacity: 1.0 }
			    , glowDuration
			    , 'linear'
			    , hideGlow
		    );
        }
    }
    function hideGlow() {
        if (!endAnimation) {
            glow.animate({ opacity: 0.3 }
			    , glowDuration
			    , 'linear'
			    , showGlow
		    );
        }
    }


    /******************************************************************************/
    function animateGlow(start, end, duration) {
        //console.log("animateGlow() entered.");

        /* set "start" position and attributes */
        /*glow.css(
        {
        left: start.left + "px"
        , top: start.top + "px"
        , width: start.width
        , height: start.height
        , display: glowDisplayMode
        }
        );*/

        /* animate to "end" position */
        if (supportsOpacity) {
            var glowOpacity;
            if (sleepStep)
                glowOpacity = .3;
            else
                glowOpacity = 1.0;
            glow.animate(
			    {
			        left: "+=" + end.left + "px"
				    , top: "+=" + end.top + "px"
                    , opacity: glowOpacity
			    }
			    , duration
			    , 'linear'
			    , doStep
		    );
        } else {
            var glowDisplayMode;
            if (sleepStep)
                glowDisplayMode = "none";
            else
                glowDisplayMode = "block";
            glow.css({ display: glowDisplayMode });
            glow.animate(
			    {
			        left: "+=" + end.left + "px"
				    , top: "+=" + end.top + "px"
			    }
			    , duration
			    , 'linear'
			    , doStep
		    );
        }
    }

    /******************************************************************************/
    function animationFinalStep() {
        //console.log("animationFinalStep() entered.");

        glow.hide();
        flickr.css(
			{
			    marginLeft: (parseInt(flickr.css("margin-left")) - cfg.finalAnimationDistance) + "px"
			    //, top: (flickrOrigin.top + flickrPos.top) + "px"
				, display: "block"
			}
		);

        if (supportsOpacity) {
            flickr.css({ opacity: cfg.flickrOpacityStart });
        }
        flicker1();


        //        if (supportsOpacity) {


        //        }
        //        else {
        //            flickr.animate(
        //				{
        //				    marginLeft: "+=" + cfg.finalAnimationDistance
        //				}
        //				, flickrDuration
        //			);
        //        }

        animationComplete();
    }

    var flickerAnimationTime = flickrDuration / 3;
    var flickerAnimationDistance = cfg.finalAnimationDistance / 3;
    function flicker1() {
        if (supportsOpacity) {
            flickr.children(".f1").fadeOut(flickrDuration / 2);
            flickr.children(".f2").fadeIn(flickrDuration / 2);
            flickr.css({ marginTop: "-40px" });
            flickr.animate(
			    {
			        marginLeft: "+=" + flickerAnimationDistance
                    , marginTop: "+=10"
				    , opacity: .25
			    }
			    , flickerAnimationTime
                , flicker2
		    );
        } else {
            flickr.css({ marginTop: "-40px" });
            flickr.animate(
			    {
			        marginLeft: "+=" + flickerAnimationDistance
                    , marginTop: "+=10"
			    }
			    , flickerAnimationTime
                , flicker2
		    );
        }
    }
    function flicker2() {
        if (supportsOpacity) {
            flickr.children(".f2").fadeOut(flickrDuration / 2);
            flickr.children(".f4").fadeIn(flickrDuration / 2);
            flickr.animate(
			    {
			        marginLeft: "+=" + flickerAnimationDistance
                    , marginTop: "+=10"
				    , opacity: .5
			    }
			    , flickerAnimationTime
            //, flicker3
                , flicker4
		    );
        } else {
            flickr.children(".f1").css("display", "none");
            flickr.children(".f2").css("display", "block");
            flickr.animate(
			    {
			        marginLeft: "+=" + flickerAnimationDistance
                    , marginTop: "+=10"
			    }
			    , flickerAnimationTime
            //, flicker3
                , flicker4
		    );
        }
    }
    //    function flicker3() {
    //        flickr.children(".f2").fadeOut(flickrDuration / 2);
    //        flickr.children(".f3").fadeIn(flickrDuration / 2);
    //        flickr.animate(
    //			{
    //			    marginLeft: "+=" + flickerAnimationDistance
    //                , marginTop: "+=10"
    //				, opacity: .75
    //			}
    //			, flickerAnimationTime
    //            , flicker4
    //		);
    //    }
    function flicker4() {
        if (supportsOpacity) {
            flickr.animate(
			    {
			        marginLeft: "+=" + flickerAnimationDistance
                    , marginTop: "+=10"
				    , opacity: 1
                    , width: "223px"
			    }
			    , flickerAnimationTime
		    );
        } else {
            flickr.children(".f2").css("display", "none");
            flickr.children(".f4").css("display", "block");
            flickr.animate(
			    {
			        marginLeft: "+=" + flickerAnimationDistance
                    , marginTop: "+=10"
                    , width: "223px"
			    }
			    , flickerAnimationTime
		    );
        }
    }

    /******************************************************************************/
    function animationComplete() {
        //console.log("animationComplete() entered.");
        StartSlides();
        if (pauseDuration > 0)
            animationRecycle();
    }

    /******************************************************************************/
    function animationRecycle() {
        //console.log("animationRecycle() entered.");

        if (timer != null)
            clearTimeout(timer);

        if (!currentlyPaused) {
            currentlyPaused = true;
            timer = setTimeout(GlowAnimation.animationRecycle, pauseDuration);
        }
        else {
            currentlyPaused = false;
            if (supportsOpacity)
                flickr.fadeOut(cfg.fadeBeforeLoopDuration);
            else
                flickr.hide();
            initAnimation();
        }
    }

    /******************************************************************************/
    function killAnimation() {
        endAnimation = true;
        glow.hide();
        flickr.show();
        flickr.css("width", "223px");
        flickr.children().css("display", "none");
        flickr.children(".f4").css("display", "block");

    }

    /******************************************************************************/

    return {
        init: init
		, animationRecycle: animationRecycle
        , killAnimation: killAnimation
    }
} ();
