/*----------------------------------------------------------
 Page Configuration
 -----------------------------------------------------------*/
var animatorAircraft = function(){
    var path = "M720.078,59.406c0,0-71.546,137.22-139.505,174.095 c-84.854,46.042-211.416,53.234-287.641,47.479c-76.226-5.755-185.528-25.897-198.472,37.409 C88.5,448.041,631.5,425.041,626.596,590.321c-1.438,143.879-24.449,153.951-40.271,187.043",
        firstWalkerObj = $('.animator_aircraft > .walker')[0],
        walkers = [];

    // handles whatever moves along the path
    function AnimateWalker(walker){
        this.pathAnimator = new PathAnimator( path );
        this.walker = walker;
        this.reverse = false;
        this.speed = 10;
        this.easing = '';
        this.startOffset = null;
        this.color = 'deeppink'; // visually separate different walkers easily
    }

    AnimateWalker.prototype = {
        start : function(){
            //this.walker.style.cssText = "";
            this.startOffset = (this.reverse || this.speed < 0) ? 100 : 0; // if in reversed mode, then animation should start from the end, I.E 100%
            this.pathAnimator.context = this; // just a hack to pass the context of every Walker inside it's pathAnimator
            this.pathAnimator.start( this.speed, this.step, this.reverse, this.startOffset, this.finish, this.easing);
        },

        // Execute every "frame"
        step : function(point, angle){
            this.walker.style.cssText = "top:" + point.y + "px;" +
            "left:" + point.x + "px;" +
            "transform:rotate(" + angle + "deg);" +
            "-webkit-transform:rotate(" +  angle + "deg);" +
            "color:" + this.color;
        },

        // Restart animation once it was finished
        finish : function(){
            //this.start();
        },

        // Resume animation from the last completed percentage (also updates the animation with new settings' values)
        resume : function(){
            this.pathAnimator.start( this.speed, this.step, this.reverse, this.pathAnimator.percent, this.finish, this.easing);
        }
    }

    function generateWalker(walkerObj){
        var newAnimatedWalker = new AnimateWalker( walkerObj );
        walkers.push(newAnimatedWalker);
        return newAnimatedWalker;
    }

    // start "animating" the first Walker on the page
    generateWalker(firstWalkerObj).start();
    // bind the first Controller to the first Walker
    var firstController = $('menu > div:first');
    resetController( firstController );
    firstController.data( 'walker', walkers[0] );

    /*-----------------------------------------------------------
     User Controls
     ------------------------------------------------------------*/
    $('#showPath').on('change', togglePath);
    $('#addWalker').on('click', addWalker);
    $('menu')
        .on('click', '.delete', removeInstance)
        .on('click', '.stopPlay', stopPlay)
        .on('click', '.reverse', switchDirection)
        .on('change', '.speed', changeSpeed)
        .on('change', 'select', changeEasing);

    $('.speed').trigger('change');

    // show / hide the path of the animated object
    function togglePath(){
        $('#svgPath01').toggleClass('show');
    }

    // add a new instance Walker and his controller box
    function addWalker(){
        var newWalker = firstWalkerObj.cloneNode(true),
            controllerTemplate = $('menu > div:last'),
            controllerClone = controllerTemplate.clone(),
            newAnimatedWalker = generateWalker(newWalker),
            color = '#'+(Math.random()*0xFFFFFF<<0).toString(16);

        resetController( controllerClone );
        controllerTemplate.after( controllerClone.css('borderColor', color) );

        $(firstWalkerObj).after(newWalker);

        controllerClone.data('walker', newAnimatedWalker);  // keep track which controller controls which walker
        newAnimatedWalker.color = color;
        newAnimatedWalker.start();
    }
    // reset the controller box for new "walker" instances
    function resetController(obj){
        var speed = 20;
        obj.find('.speed').val(speed).next().text(speed + 's');
        obj.find(':checkbox').removeAttr('checked');
    }

    // pause or place the animated object along the path
    function stopPlay(){
        var thisAnimatedWalker = $(this.parentNode.parentNode).data('walker');

        thisAnimatedWalker.pathAnimator.running ? thisAnimatedWalker.pathAnimator.stop() : thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    // switch direction of the animated object
    function switchDirection(){
        var thisAnimatedWalker = $(this.parentNode.parentNode).data('walker');
        thisAnimatedWalker.reverse = (thisAnimatedWalker.reverse == true) ? false : true;
        if( thisAnimatedWalker.pathAnimator.running )
            thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    function changeSpeed(){
        var thisAnimatedWalker = $(this.parentNode).data('walker');
        thisAnimatedWalker.speed = this.value;
        this.nextElementSibling.innerHTML = this.value + 's';
        thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    function removeInstance(){
        var parent = $(this.parentNode),
            thisAnimatedWalker = parent.data('walker');

        // make sure at least one Walker stays
        if( walkers.length > 1 ){
            parent.remove();
            thisAnimatedWalker.pathAnimator.stop();
            $(thisAnimatedWalker.walker).remove();
            walkers.splice(walkers.indexOf(thisAnimatedWalker), 1);
        }
    }

    function changeEasing(){
        var thisAnimatedWalker = $(this.parentNode).data('walker'),
            easingFunc = '';

        if( this.value ){
            var formula = this.value;
            easingFunc = function(t){ return eval(formula) };
        }

        thisAnimatedWalker.easing = easingFunc;
        thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    // reset checkboxes
    $(':checkbox').removeAttr('checked');
    $('select').prop('selectedIndex', 0);
};





/*----------------------------------------------------------
 Page Configuration
 -----------------------------------------------------------*/
var animatorCar = function(){
    var path = "M893.943,64.278c0,0-30.202,90.644-125.123,93.521C673.898,160.678,369,94.492,307.157,84.422 C245.314,74.35,92.865,36.941,55.472,126.146c-37.393,89.205-8.629,404.3,212.854,421.565 c104.989,17.266,274.697-37.408,274.697-37.408",
        firstWalkerObj = $('.animator_car > .walker')[0],
        walkers = [];

    // handles whatever moves along the path
    function AnimateWalker(walker){
        this.pathAnimator = new PathAnimator( path );
        this.walker = walker;
        this.reverse = false;
        this.speed = 10;
        this.easing = '';
        this.startOffset = null;
        this.color = 'deeppink'; // visually separate different walkers easily
    }

    AnimateWalker.prototype = {
        start : function(){
            //this.walker.style.cssText = "";
            this.startOffset = (this.reverse || this.speed < 0) ? 100 : 0; // if in reversed mode, then animation should start from the end, I.E 100%
            this.pathAnimator.context = this; // just a hack to pass the context of every Walker inside it's pathAnimator
            this.pathAnimator.start( this.speed, this.step, this.reverse, this.startOffset, this.finish, this.easing);
        },

        // Execute every "frame"
        step : function(point, angle){
            this.walker.style.cssText = "top:" + point.y + "px;" +
            "left:" + point.x + "px;" +
            "transform:rotate(" + angle + "deg);" +
            "-webkit-transform:rotate(" +  angle + "deg);" +
            "color:" + this.color;
        },

        // Restart animation once it was finished
        finish : function(){
            //this.start();
        },

        // Resume animation from the last completed percentage (also updates the animation with new settings' values)
        resume : function(){
            this.pathAnimator.start( this.speed, this.step, this.reverse, this.pathAnimator.percent, this.finish, this.easing);
        }
    }

    function generateWalker(walkerObj){
        var newAnimatedWalker = new AnimateWalker( walkerObj );
        walkers.push(newAnimatedWalker);
        return newAnimatedWalker;
    }

    // start "animating" the first Walker on the page
    generateWalker(firstWalkerObj).start();
    // bind the first Controller to the first Walker
    var firstController = $('menu > div:first');
    resetController( firstController );
    firstController.data( 'walker', walkers[0] );

    /*-----------------------------------------------------------
     User Controls
     ------------------------------------------------------------*/
    $('#showPath').on('change', togglePath);
    $('#addWalker').on('click', addWalker);
    $('menu')
        .on('click', '.delete', removeInstance)
        .on('click', '.stopPlay', stopPlay)
        .on('click', '.reverse', switchDirection)
        .on('change', '.speed', changeSpeed)
        .on('change', 'select', changeEasing);

    $('.speed').trigger('change');

    // show / hide the path of the animated object
    function togglePath(){
        $('#svgPath02').toggleClass('show');
    }

    // add a new instance Walker and his controller box
    function addWalker(){
        var newWalker = firstWalkerObj.cloneNode(true),
            controllerTemplate = $('menu > div:last'),
            controllerClone = controllerTemplate.clone(),
            newAnimatedWalker = generateWalker(newWalker),
            color = '#'+(Math.random()*0xFFFFFF<<0).toString(16);

        resetController( controllerClone );
        controllerTemplate.after( controllerClone.css('borderColor', color) );

        $(firstWalkerObj).after(newWalker);

        controllerClone.data('walker', newAnimatedWalker);  // keep track which controller controls which walker
        newAnimatedWalker.color = color;
        newAnimatedWalker.start();
    }
    // reset the controller box for new "walker" instances
    function resetController(obj){
        var speed = 20;
        obj.find('.speed').val(speed).next().text(speed + 's');
        obj.find(':checkbox').removeAttr('checked');
    }

    // pause or place the animated object along the path
    function stopPlay(){
        var thisAnimatedWalker = $(this.parentNode.parentNode).data('walker');

        thisAnimatedWalker.pathAnimator.running ? thisAnimatedWalker.pathAnimator.stop() : thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    // switch direction of the animated object
    function switchDirection(){
        var thisAnimatedWalker = $(this.parentNode.parentNode).data('walker');
        thisAnimatedWalker.reverse = (thisAnimatedWalker.reverse == true) ? false : true;
        if( thisAnimatedWalker.pathAnimator.running )
            thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    function changeSpeed(){
        var thisAnimatedWalker = $(this.parentNode).data('walker');
        thisAnimatedWalker.speed = this.value;
        this.nextElementSibling.innerHTML = this.value + 's';
        thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    function removeInstance(){
        var parent = $(this.parentNode),
            thisAnimatedWalker = parent.data('walker');

        // make sure at least one Walker stays
        if( walkers.length > 1 ){
            parent.remove();
            thisAnimatedWalker.pathAnimator.stop();
            $(thisAnimatedWalker.walker).remove();
            walkers.splice(walkers.indexOf(thisAnimatedWalker), 1);
        }
    }

    function changeEasing(){
        var thisAnimatedWalker = $(this.parentNode).data('walker'),
            easingFunc = '';

        if( this.value ){
            var formula = this.value;
            easingFunc = function(t){ return eval(formula) };
        }

        thisAnimatedWalker.easing = easingFunc;
        thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    // reset checkboxes
    $(':checkbox').removeAttr('checked');
    $('select').prop('selectedIndex', 0);
};





/*----------------------------------------------------------
 Page Configuration
 -----------------------------------------------------------*/
var animatorFish = function(){
    var path = "M34.5-35.8c0,0,23.3,88.6,314,153S701,329,692,490.7C691.8,571.3,591,616,513.3,630.5",
        firstWalkerObj = $('.animator_fish > .walker')[0],
        walkers = [];

    // handles whatever moves along the path
    function AnimateWalker(walker){
        this.pathAnimator = new PathAnimator( path );
        this.walker = walker;
        this.reverse = false;
        this.speed = 8;
        this.easing = '';
        this.startOffset = null;
        this.color = 'deeppink'; // visually separate different walkers easily
    }

    AnimateWalker.prototype = {
        start : function(){
            //this.walker.style.cssText = "";
            this.startOffset = (this.reverse || this.speed < 0) ? 100 : 0; // if in reversed mode, then animation should start from the end, I.E 100%
            this.pathAnimator.context = this; // just a hack to pass the context of every Walker inside it's pathAnimator
            this.pathAnimator.start( this.speed, this.step, this.reverse, this.startOffset, this.finish, this.easing);
        },

        // Execute every "frame"
        step : function(point, angle){
            this.walker.style.cssText = "top:" + point.y + "px;" +
            "left:" + point.x + "px;" +
            "transform:rotate(" + angle + "deg);" +
            "-webkit-transform:rotate(" +  angle + "deg);" +
            "color:" + this.color;
        },

        // Restart animation once it was finished
        finish : function(){
            //this.start();
        },

        // Resume animation from the last completed percentage (also updates the animation with new settings' values)
        resume : function(){
            this.pathAnimator.start( this.speed, this.step, this.reverse, this.pathAnimator.percent, this.finish, this.easing);
        }
    }

    function generateWalker(walkerObj){
        var newAnimatedWalker = new AnimateWalker( walkerObj );
        walkers.push(newAnimatedWalker);
        return newAnimatedWalker;
    }

    // start "animating" the first Walker on the page
    generateWalker(firstWalkerObj).start();
    // bind the first Controller to the first Walker
    var firstController = $('menu > div:first');
    resetController( firstController );
    firstController.data( 'walker', walkers[0] );

    /*-----------------------------------------------------------
     User Controls
     ------------------------------------------------------------*/
    $('#showPath').on('change', togglePath);
    $('#addWalker').on('click', addWalker);
    $('menu')
        .on('click', '.delete', removeInstance)
        .on('click', '.stopPlay', stopPlay)
        .on('click', '.reverse', switchDirection)
        .on('change', '.speed', changeSpeed)
        .on('change', 'select', changeEasing);

    $('.speed').trigger('change');

    // show / hide the path of the animated object
    function togglePath(){
        $('#svgPath03').toggleClass('show');
    }

    // add a new instance Walker and his controller box
    function addWalker(){
        var newWalker = firstWalkerObj.cloneNode(true),
            controllerTemplate = $('menu > div:last'),
            controllerClone = controllerTemplate.clone(),
            newAnimatedWalker = generateWalker(newWalker),
            color = '#'+(Math.random()*0xFFFFFF<<0).toString(16);

        resetController( controllerClone );
        controllerTemplate.after( controllerClone.css('borderColor', color) );

        $(firstWalkerObj).after(newWalker);

        controllerClone.data('walker', newAnimatedWalker);  // keep track which controller controls which walker
        newAnimatedWalker.color = color;
        newAnimatedWalker.start();
    }
    // reset the controller box for new "walker" instances
    function resetController(obj){
        var speed = 20;
        obj.find('.speed').val(speed).next().text(speed + 's');
        obj.find(':checkbox').removeAttr('checked');
    }

    // pause or place the animated object along the path
    function stopPlay(){
        var thisAnimatedWalker = $(this.parentNode.parentNode).data('walker');

        thisAnimatedWalker.pathAnimator.running ? thisAnimatedWalker.pathAnimator.stop() : thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    // switch direction of the animated object
    function switchDirection(){
        var thisAnimatedWalker = $(this.parentNode.parentNode).data('walker');
        thisAnimatedWalker.reverse = (thisAnimatedWalker.reverse == true) ? false : true;
        if( thisAnimatedWalker.pathAnimator.running )
            thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    function changeSpeed(){
        var thisAnimatedWalker = $(this.parentNode).data('walker');
        thisAnimatedWalker.speed = this.value;
        this.nextElementSibling.innerHTML = this.value + 's';
        thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    function removeInstance(){
        var parent = $(this.parentNode),
            thisAnimatedWalker = parent.data('walker');

        // make sure at least one Walker stays
        if( walkers.length > 1 ){
            parent.remove();
            thisAnimatedWalker.pathAnimator.stop();
            $(thisAnimatedWalker.walker).remove();
            walkers.splice(walkers.indexOf(thisAnimatedWalker), 1);
        }
    }

    function changeEasing(){
        var thisAnimatedWalker = $(this.parentNode).data('walker'),
            easingFunc = '';

        if( this.value ){
            var formula = this.value;
            easingFunc = function(t){ return eval(formula) };
        }

        thisAnimatedWalker.easing = easingFunc;
        thisAnimatedWalker.resume.apply(thisAnimatedWalker);
    }

    // reset checkboxes
    $(':checkbox').removeAttr('checked');
    $('select').prop('selectedIndex', 0);
};