﻿/*!
* Karmic Flow 0.1
* http://www.karmagination.com
* Released under the MIT, BSD, and GPL Licenses - Choose one that fit your needs
* Copyright (c) 2009 Kean L. Tan 
* Start date: 2009-07-20
* Build date: 2009-09-02
*/

(function karmicFlow($) {
    $.fn.karmicFlow = function(opts) {
        // default options
        opts = $.extend({
            container: 'jflow_container',
            slider: 'jflow_slider',
            slides: 'jflow_slides',
            sliding: 'jflow_sliding',
            slide_selected: 'jflow_slide_selected',
            slide_overflow: 'jflow_slide_overflow',
            controller: 'jflow_controller',
            controller_selected: 'jflow_controller_selected',
            next: 'jflow_next_controller',
            prev: 'jflow_prev_controller',
            info: 'jflow_info_controller',
            close: 'jflow_close_controller',
            description: 'jflow_info',
            duration: 400
        }, opts || {});

        this.data('opts', opts);
        this.data('cur_index', this.data('cur_index') || 0);

        var playSlide = function(el) {

            var $el = $(el),
			target_container = $el.attr('target'),
			$container = $('#' + target_container),
			$current_selected = $container.find('.' + opts.slide_selected),
			$slider = $current_selected.parent(),
			$allSlides = $current_selected.parent().children(),
			index = $allSlides.index($current_selected),
			total = $allSlides.length,
			old_idx = $container.data('cur_index'),
			duration = $container.data('opts').duration,
			multiplier = 1;

            // -1 means not found.. just quit
            if (index == -1) return false;

            if ($el.hasClass(opts.next))
                index = (index + 1 == total) ? 0 : index + 1;
            else if ($el.hasClass(opts.prev))
                index = (index == 0) ? total - 1 : index - 1;

            $container.data('cur_index', index);

            $allSlides.removeClass(opts.slide_selected);
            $allSlides.eq(index).addClass(opts.slide_selected);

            var $controller_target = $('[href*=#' + $allSlides.eq(index).attr('id') + ']'),
			$controller_siblings = $('[target=' + $controller_target.attr('target') + ']');

            $controller_siblings.removeClass(opts.controller_selected);
            $controller_target.addClass(opts.controller_selected);

            $slider.addClass(opts.sliding);

            if ((index == 0 && old_idx == total - 1) || (index == total - 1 && old_idx == 0)) {
                multiplier = total;
            }

            $slider.stop().animate({
                marginLeft: -1 * $current_selected.width() * index
            }, duration * multiplier, function() {
                $slider.removeClass(opts.sliding);
            });

            return $controller_target[0];
        }

        // Hide the info window
        $('.' + opts.description).hide();

        for (var i = 0; i < this.length; i++) {
            $(this[i]).find('.' + opts.slides).each(function() {
                var $div = $('<div></div>');
                $div
			 .append(this.childNodes)
			 .appendTo(this)
			 .addClass(opts.slide_overflow)
			 .css('height', $(this).parent().parent().height());
            });
        }

        // first time init, we want delegate all those controllers with different class name so they know their purpose
        // we do not want to delegate twice
        var $doc = $();
        if (!$doc.data('jflow_init')) {
            $doc.data('jflow_init', 1);

            // Set Navigation Key Bindings
            $doc.bind("keydown.colorbox.karmicFlow", function(e) {
                if (e.keyCode === 37) {
                    var el = $().find('[class=' + opts.prev + ']');
                    playSlide(el);
                    // prevent default and stop propagation
                    e.preventDefault();
                } else if (e.keyCode === 39) {
                    var el = $().find('[class=' + opts.next + ']');
                    playSlide(el);
                    // prevent default and stop propagation
                    e.preventDefault();
                }
            });

            $doc.bind('click', function(e) {
                var el = e.target,
				$el = $(el),
				target_container = $el.attr('target');

                // slide controller
                if ($el.hasClass(opts.controller)) {
                    var $container = $('#' + target_container),
					$found_slide = $container.find('[id=' + el.hash.substring(1, el.hash.length) + ']'),
					index = $found_slide.parent().children().index($found_slide[0]),
					$slider = $found_slide.parent(),
					old_index = $container.data('cur_index'),
					duration = $container.data('opts').duration;

                    $('[target=' + target_container + ']').removeClass(opts.controller_selected);
                    $el.addClass(opts.controller_selected);
                    $slider.children().removeClass(opts.slide_selected);
                    $found_slide.addClass(opts.slide_selected);
                    $slider.addClass(opts.sliding);
                    $container.data('cur_index', index);

                    var marginLeft = -1 * $found_slide.width() * index;
                    $slider.stop().animate({
                        marginLeft: -1 * $found_slide.width() * index
                    }, duration * Math.abs(index - old_index), function() {
                        $slider.removeClass(opts.sliding);
                    });

                    // prevent default and stop propagation
                    e.preventDefault();
                }
                // next button, flawed, should use current selected or will be off
                else if ($el.hasClass(opts.next) || $el.hasClass(opts.prev)) {
                    playSlide(el);

                    // prevent default and stop propagation
                    e.preventDefault();
                }
                // info button || close info button
                else if ($el.hasClass(opts.info) || $el.hasClass(opts.close)) {
                    var $container = $('#' + target_container),
                    $info = $("." + opts.description);

                    if ($info.css("display") == "none") {
                        $info.animate({ opacity: .95, height: 'toggle' }, 250);
                    } else {
                        $info.animate({ opacity: 1, height: 'toggle' }, 250);
                    }

                    // prevent default and stop propagation
                    e.preventDefault();
                }
                
                // other normal anchors should not be affected and behave normally so no return false, prevent default or stop propagation here
            });
        }

        for (var i = 0; i < this.length; i++) {
            var $container = $(this[i]),
			$slider = $container.children(),
			$slides = $slider.height($container.height()).children();

            $slider.width($slides.length * $container.width());
            $slides.width($container.width());
        }

        // make this plugin chainable
        return this;

    }
})(this.jQuery);