(function($){
        
        $.fn.trains = function(options) {
                options = $.extend({
                        //trains
                        maxDelayAdd : 12000,
                        minDelayAdd : 2000,
                        minTrainDuration : 12000,
                        maxTrainDuration :17000,
                        pageChangeDuration : 500,
                        chanceToStop : 0.5, //percentage
                        //pages
                        doorDuration :500
                }, options);
                
                //trains
                var self = this;
                var trains = [];
                var currentIndex = null;
                var inTransition = false;
                var timeouts = [];
                var pageCache = {};
                var trackAddition = 0;
                
                //cars
                var carConfig = {};
                var carTimeout = null;
                
                //links
                var defaultPage = null;
                var defaultIndex = null;
                var defaultNextIndex = null;
                
                setup();
                
                function setup() {
                        
                        //jQuery.fx.interval = 100;
                        checkPageSize();
                        
                        $(self).each(function(index){
                                //fade when mouses over/out
                                $(this).find('.track')
                                        .mouseover(function(){
                                                $(this).css('opacity', 0.7);
                                        })
                                        .mouseout(function(){
                                                $(this).css('opacity', 1);
                                        })
                                
                                activateTrain(index, $(this).find('.train'));
                                bindLink(index, $(this).find('a.track-image'));
                        });
                        
                        setupCars();
                        
                        
                        
                        if (defaultPage) {
                                displayPage(defaultPage, defaultIndex, defaultNextIndex);
                        }
                }
                
                function checkPageSize() {
                        var windowSize = $(window).width() - 40;
                        
                        if (windowSize > options.size) {
                                $(options.mainContainer).css('width', windowSize + 'px');
                                $('.track').css('width', windowSize + 'px');
                                var wrapperWidth = (windowSize - options.size) / 2;
                                
                                $(options.leftWrapper).css('width', wrapperWidth + 'px');
                                $(options.rightWrapper).css('width', wrapperWidth + 'px');
                                
                                trackAddition = wrapperWidth;
                                
                                /*$('.track').each(function(){
                                        
                                        $(this).find(options.leftWrapper).css({
                                                'background-image' : 'url(' + $(this).metadata().left_track + ')',
                                                'background-repeat' : 'repeat-x'
                                        });
                                        
                                        $(this).find(options.rightWrapper).css({
                                                'background-image' : 'url(' + $(this).metadata().right_track + ')',
                                                'background-repeat' : 'repeat-x'
                                        });
                                });*/
                        }
                        else {
                                $('.track').css('width', options.size + 'px');
                                $(options.road).css('width', options.size + 'px');
                                $(options.leftWrapper).hide();
                                $(options.rightWrapper).hide();
                        }
                }
                
                /*************************** LINKS ************************/
                function bindLink(index, link) {
                        
                        var page = $(self[index]).find('.pages');
                       
                        var nextIndex = (index == self.length - 1) ? 0 : index + 1;
                        
                        //check if we a page is already loaded
                        if (page.hasClass('default')) {
                                defaultPage = page;
                                defaultIndex = index;
                                defaultNextIndex = nextIndex;
                        }
                        
                        $(link).click(function(e){
                                e.preventDefault();
                              
                                if (inTransition) return;
                                
                                var currentPage = (currentIndex != null) ? $(self[currentIndex]).find('.pages') : null;
                                var link = this;
                                
                                inTransition = true;
                                
                                
                                
                                //close open page
                                if (currentIndex !== null && currentIndex == index) {
                       
                                        closeDoors(currentPage, function(){
                                                
                                                closePage(currentPage, function(){
                                                       
                                                       //closing open page
                                                       currentIndex = null;
                                                       inTransition = false; 
                                                        
                                                        
                                                        
                                                });
                                               
                                        });
                                        
                                        return false;
                                       
                                }
                                /*else if (currentIndex !== null) {
                                       
                                        closeDoors(currentPage, function(){
                                               loadPage(link, page, index, nextIndex); 
                                        });
                                        
                                }*/
                                else {
                                        
                                        loadPage(link, page, index, nextIndex);
                                }
                                
                                return false;
                        });
                }
                
                function openTracks(callback) {
                        //if (!callback) callback = function(){alert('here')};
                        
                        $(self).each(function(index){
                                
                                if (!$(this).is(':visible')) {
                                        $(this).slideDown(options.pageChangeDuration/2, (index == self.length - 1) ? callback : null);
                                        //$(this).show();
                                }
                                else if (index == self.length - 1) {
                                        setTimeout(function(){
                                                if (typeof(callback) == 'function') {
                                                        callback.call();
                                                }
                                        }, options.pageChangeDuration/4);
                                }
                        });
                        //$(self).slideDown(options.pageChangeDuration/2, callback);
                }
                
                function closeTracks(index, nextIndex) {
                        for (var i = 0; i < self.length; i++) {
                                if (i != nextIndex && i != index) {
                                        $(self[i]).slideUp(options.pageChangeDuration/2);
                                }
                                else if (i == nextIndex) {
                                        $(self[i]).slideDown(options.pageChangeDuration/2);
                                }
                        }
                }
                
                function closePage(page, callback) {
                        console.log('Closing open page');
                        showCar();
                        openTracks();
                        
                        $(page).slideUp(options.pageChangeDuration, callback);
                }
                
                function loadPage(link, page, index, nextIndex) {
                        
                        var url = $(link).attr('href');
                        if (!pageCache[url]) {
                                $.getJSON(url, function(data){
                                        
                                        pageCache[url] = data;
                                        
                                        $(page).find('.page').html(data.content);
                                       
                                        if (currentIndex != null) {
                                                
                                                closePage($(self[currentIndex]).find('.pages'), function(){
                                                        displayPage(page,index,nextIndex, function(){
                                                                if (data.js) {
                                                                        eval(data.js);
                                                                }
                                                        });
                                                });
                                        }
                                        else {
                                                displayPage(page,index,nextIndex, function(){
                                                        if (data.js) {
                                                                //alert(data.js);
                                                                eval(data.js);
                                                        }
                                                });
                                        }
                                        
                                });
                        }
                        else {
                                $(page).html(url.content);
                                
                                if (currentIndex != null) {
                                                closePage($(self[currentIndex]).find('.pages'), function(){
                                                        displayPage(page,index,nextIndex, function(){
                                                                if (pageCache[url].js) {
                                                                        eval(pageCache[url].js); 
                                                                }
                                                        });
                                                });
                                }
                                else {
                                        displayPage(page,index,nextIndex, function(){
                                                if (pageCache[url].js) {
                                                        eval(pageCache[url].js); 
                                                }
                                        });
                                }
                        }
                       
                        

                        
                }
                
                function displayPage(page, index, nextIndex, callback) {
                   
                        hideCar();
                        /*if (currentIndex) {
                                $(self[currentIndex]).find('.pages').slideUp(options.pageChangeDuration);
                        }*/

                        if (!nextIndex) { //no page after this, so hide all
                                closeTracks(index, -1);
                                //$(self).slideUp(options.pageChangeDuration/2);
                        }
                        else {
                                closeTracks(index, nextIndex);
                        }

                        $(self[index]).slideDown(options.pageChangeDuration);
                        $(page).slideDown(options.pageChangeDuration, function(){
                                openDoors(page, function(){
                                        inTransition = false;
                                        currentIndex = index;
                                        if (typeof(callback) == 'function') {
                                                callback.call();
                                        }
                                });

                        });
                                
                        bindNav(page);        
                }
                
                function bindNav(page) {
                        
                        $(page).find('.sub-nav li a, .third-level li a').click(function(e){
                                
                                e.preventDefault();
                                
                                var link = this;
                                var url = $(link).attr('href');
                                if (!pageCache[url]) {
                                        $.getJSON(url, function(data){
                                               pageCache[url] = data;
                                               changePage(page, data.content, function(){
                                                        if (data.js) {
                                                               eval(data.js);
                                                       }
                                               });
                                               
                                               
                                        });
                                }
                                else {
                                        changePage(page, pageCache[url].content, function(){
                                                if (pageCache[url].js) {
                                                       eval(pageCache[url].js);  
                                                }
                                        });
                                        
                                        
                                }
                        });
                        
                        $(page).find('.sub-nav a.home').click(function(e){
                                e.preventDefault();
                                
                                var currentPage = (currentIndex != null) ? $(self[currentIndex]).find('.pages') : null;
                                
                                if (currentPage) {
                                        closePage(currentPage);
                                        openTracks();
                                        showCar();
                                }
                        });
                }
                
                function changePage(page, html, callback) {
                                var alt = $(page).find('.page-alt');
                                var main = $(page).find('.page');
                                alt.html(html).show();
                                
                                //make sure doors are open when changing pages
                                setDoorsOpen(alt);
                                
                                $(main).fadeOut('slow', function(){
                                      main.html(html);
                                      
                                      setTimeout(function(){
                                              setDoorsOpen(main);
                                      
                                              main.show();

                                              setTimeout(function(){
                                                        alt.hide();
                                                        alt.html('');
                                                        bindNav(page);

                                                        if (typeof(callback) == 'function') {
                                                                callback.call();
                                                        }
                                              }, 200);
                                      
                                      }, 200);
                                      //make sure doors are open when bringing main
                                      //page back into focus
                                      
                                });
                                
                                
                        
                }
                
                function setDoorsOpen(frame) {
                        var doorLeft = $(frame).find('.door-left');
                        doorLeft.css('left', -doorLeft.width());
                        
                        var doorRight = $(frame).find('.door-right');
                        doorRight.css('right', -doorRight.width());
                }
                
                function openDoors(page, callback) {
                        
                        var doorLeft = $(page).find('.door-left');
                        
                        doorLeft.animate({
                                left : -doorLeft.width()
                        }, options.doorDuration);
                        
                        var doorRight = $(page).find('.door-right');
                        doorRight.animate({
                                right : -doorRight.width()
                        }, options.doorDuration, function(){
                               
                                if (typeof(callback) == 'function') {
                                        callback.call();
                                }
                        });
                }
                
                function closeDoors(page, callback) {
                   
                        var doorLeft = $(page).find('.door-left');
                        
                        doorLeft.animate({
                                left : 0
                        }, options.doorDuration);
                        
                        var doorRight = $(page).find('.door-right');
                        doorRight.animate({
                                right : 0
                        }, options.doorDuration, function(){
                                if (typeof(callback) == 'function') {
                                        callback.call();
                                }
                        });
                }
                
                
                
                /******************************* TRAINS ***********************************/
                function activateTrain(index, train) {
                        
                        //alert($(train).css('width'));
                        
                        trains[index] = {
                                'train' : train,
                                width : $(train).width(),
                                stopPosition : $(train).metadata().stop_position,
                                stopDirection : $(train).metadata().stop_direction,
                                trainLeft : $(train).find('.train-left'),
                                trainRight : $(train).find('.train-right')
                        };
                        
                        //calculate positions
                        var movePosition = $(window).width() + trains[index].width;
                        trains[index].leftPosition = -1 * movePosition;
                        trains[index].rightPosition = movePosition + $(window).width();
                        trains[index].calculatedStopPosition = getStopPosition(index);
                        //set starting position
                        $(train).css({
                                //'width' : trains[index].width,
                                'left' : trains[index].calculatedStopPosition
                        });

                        if (trains[index].stopDirection == 0) {
                               trains[index].trainRight.hide();
                        }
                        else trains[index].trainLeft.hide();
                        
                        setTimeout(function(){
                                moveTrain(index);
                        }, getRandomDelay());
                }
                /**
                 * 0 = left, 1 = right
                 */
                function getStopPosition(index) {
                        
                        return (trains[index].stopDirection == 0) ? Math.round(trains[index].stopPosition + trackAddition)  : Math.round(trains[index].stopPosition - trains[index].width + trackAddition);
                }
                
                function moveTrain(index) {
                        
                        var currentPosition = parseInt(trains[index].train.css('left'));
                      
                        var newPosition = 0;
                        
                        if (currentPosition == trains[index].calculatedStopPosition) { //if stopped, move correct direction
                                
                                newPosition = (trains[index].stopDirection == 1) ? trains[index].rightPosition : trains[index].leftPosition;
                        }
                        else {
                                
                                newPosition = (currentPosition > 0) ? trains[index].leftPosition : trains[index].rightPosition;
                                
                                //shall we stop, 
                                if (
                                        (newPosition < 0 && trains[index].stopDirection == 0) //moving left, stop direction is left
                                        || (newPosition > 0 && trains[index].stopDirection == 1) //moving right, stop direction is right
                                        ){

                                        var chance = Math.random();

                                        if (chance < options.chanceToStop) {
                                                newPosition = trains[index].calculatedStopPosition;
                                        }
                                }
                        }

                        //swap trains
                        if (currentPosition == trains[index].rightPosition) {
                               trains[index].trainRight.hide();
                               trains[index].trainLeft.show();
                        }
                        else if (currentPosition == trains[index].leftPosition){
                                trains[index].trainLeft.hide();
                                trains[index].trainRight.show();
                        }
                         
                        trains[index].train.animate({
                                left : newPosition
                        }, getRandomTime(options.minTrainDuration, options.maxTrainDuration), function(){
                                
                                var delay = getRandomDelay();
                                timeouts[index] = setTimeout(function(){
                                        moveTrain(index);
                                }, delay);
                                
                        });
                       
                }
                
                function stopTrains() {
                        for (var i = 0; i < trains.length; i++) {
                                clearTimeout(timeouts[i]);
                                $(trains[i].train).clearQueue().stop(true, true);
                                $(trains[i].train).hide();
                        }
                }
                
                function startTrains() {
                        for (var i = 0; i < trains.length; i++) {
                                moveTrain(i);
                                $(trains[i].train).show();
                        }
                }
                
                /**************************** TIMING *****************************/
                function getRandomTime(min, max) {
                        return Math.random() * (max - min) + min;
                }
                
                function getRandomDelay() {
                        return getRandomTime(options.minDelayAdd, options.maxDelayAdd);
                }
                
                function getRandom(min,max) {
                        return Math.round(Math.random() * (max - min) + min);
                }
                
                /***************************** CARS ******************************/
                function setupCars() {
                        //get cars
                        carConfig.car = $(options.road).find('.car');
                        carConfig.leftCar = carConfig.car.find('.car-left');
                        carConfig.leftCars = carConfig.car.find('.car-left img');
                        
                        carConfig.rightCar = carConfig.car.find('.car-right');
                        carConfig.rightCars = carConfig.car.find('.car-right img');
                        
                        //stop position
                        carConfig.stopPosition = carConfig.car.metadata().stop_position + trackAddition;
                        
                        //end positions
                        carConfig.leftPosition = -$(window).width();
                        carConfig.rightPosition = $(window).width() * 2;
                        
                        
                        //hide right cars
                        carConfig.rightCar.hide();
                        
                        //hide left cars, then show first car
                        carConfig.leftCars.hide();
                        
                        $(carConfig.leftCars[0]).show();
                        
                        //move to start
                        carConfig.car.css('left', carConfig.stopPosition);
                        
                        carTimeout = setTimeout(function(){
                                moveCar();
                        }, getRandomDelay());
                        
                }
                
                function moveCar() {
                        
                        var currentPosition = parseInt(carConfig.car.css('left'));
                      
                        var newPosition = 0;
                        
                        if (currentPosition == carConfig.stopPosition) { //if stopped, move correct direction
                                
                                newPosition = carConfig.leftCar.is(':visible') ? carConfig.leftPosition : carConfig.rightPosition;
                        }
                        else {
                                
                                newPosition = (currentPosition > 0) ? carConfig.leftPosition : carConfig.rightPosition;
                                
                                //shall we stop, 
                                var chance = Math.random();

                                if (chance < options.chanceToStop) {
                                        newPosition = carConfig.stopPosition;
                                }
                                
                        }

                        //swap trains
                        if (currentPosition == carConfig.rightPosition) {
                               carConfig.rightCar.hide();
                               
                               carConfig.leftCar.show();
                               
                               //select car
                               selectCar(carConfig.leftCars);
                               
                        }
                        else if (currentPosition == carConfig.leftPosition){
                                carConfig.leftCar.hide();
                                carConfig.rightCar.show();
                                
                                //select car
                                selectCar(carConfig.rightCars);
                        }
                         
                        carConfig.car.animate({
                                left : newPosition
                        }, getRandomTime(options.minTrainDuration, options.maxTrainDuration), function(){
                                
                                var delay = getRandomDelay();
                                carTimeout = setTimeout(function(){
                                        moveCar();
                                }, delay);
                                
                        });
                }
                
                function selectCar(cars) {
                        var carIndex = getRandom(0, cars.length - 1);
                               
                        cars.each(function(index){
                                if (index == carIndex) {
                                        $(this).show();
                                }
                                else {
                                        $(this).hide();
                                }
                        });
                }
                
                function hideCar() {
                        $(options.road).slideUp(options.pageChangeDuration);
                }
                
                function showCar() {
                        $(options.road).slideDown(options.pageChangeDuration);
                }
        };
})(jQuery);
