/*
---
script: good-carousel.js
description: GoodCarousel - A tiny and simple horizontal sliding Carousel with basic navigation, all powered by MooTools.
license: MIT-style license.
author:
 - Ryan Rampersad (http://ifupdown.com)
requires:
 core/1.2.4:
 - Class.Extras
 - Element
 - Element.Event
 - Element.Style
 - Fx.Tween
 - Utilities.Selectors
provides: [GoodCarousel]

...
*/
var GoodCarousel = new Class({

	Implements: [Options, Events],
	
	/*
		Events
			onStartUp
			onBeforeSlide
			onAfterSlide
			onEnd
			onStartOver
			onMouseEnter
			onMouseLeave
	*/

/*     container: null,
    inner: null,
    animate: null,
    nav: null,
        data: null,
    timer: null, */
	
	cycles: 0,
    ticks: 0,

    options: {
        width: 624,
        height: 282,
        delay: 8000,
        duration: 700,
        transition: Fx.Transitions.Sine.easeInOut,
        structure: {
            header: "h3",
            data: ".carousel-data",
            link: "p a",
            img: "img"
        },
        data: null,
        loops: 0
    },
	
    initialize: function (container, options) {
        this.setOptions(options);
        this.container = document.id(container);
        this.parseData();
        this.setup();
    },

    parseData: function () {

        var data = [];
        if (this.options.data == null) {

            this.container.getElements(this.options.structure.data).each(function (el, i) {
                var slide = {},
                    link = el.getElement(this.options.structure.link),
                    img = el.getElement(this.options.structure.img);
                slide.title = el.getElement(this.options.structure.header).get("text");
                slide.desc = link.get("text");
                slide.url = link.get("href");
                slide.img = img.get("src");
                slide.alt = img.get("title");
                slide.rel = link.get("rel");
                slide.index = i;
                data.push(slide);
            },
            this);
        }

        this.data = data;
        this.container.empty();

    },

    setup: function () {

        /*
			I didn't want to make this a String method so I'll make my own private method.
			elementize: return an element based on a string.
		*/
        function elementize(string) {
            return new Element("div", {
                html: string
            }).getFirst();
        }

        // Set the container's width, add class
        this.container.setStyle("width", this.options.width).addClass("carousel");

        // Make an inner container, set width and height.
        this.inner = new Element("div", {
            "class": "carousel-inner",
            "styles": {
                "width": this.options.width,
                "height": this.options.height
            }
        });
        // Container grabs inner. 
        this.container.grab(this.inner);
        // Make the animate div.
        this.animate = new Element("div", {
            "class": "carousel-animate",
            "styles": {
                "width": this.options.width
            }
        }).set("tween", {
            duration: this.options.duration,
            transition: this.options.transition
        });
        // Inner Container grabs this one.
        this.inner.grab(this.animate);

        // Get the link elements in the container.
        var slides = this.data;

        /*
			So we know how much space to allot.
		*/
        this.animate.setStyle("width", this.options.width * slides.length);

        // Make the under-slide navigation bar.
        this.nav = new Element("ul", {
            "class": "carousel-nav"
        });
        this.container.grab(this.nav);

        // Make the separate blocks here.
        slides.each(function (data, i) {

            var biglink_data = {
                url: data.url,
                img: data.img,
                height: this.options.height,
                width: this.options.width,
                title: data.title,
                desc: data.desc
            },
            biglink = ('<div class="carousel-item"><div class="carousel-item-info"><h1><a title="{title}" href="{url}">{title}</a></h1><div>{desc}</div></div><a href="{url}"><div class="img_holder"><img title="{title}" src="{img}" border="0" /></div></a></div>').substitute(biglink_data);
            biglink = elementize(biglink);

            biglink.setStyle("width", this.options.width).set("rel", data.rel);

            this.animate.grab(biglink);

            //======
            // Again, using substitue.
            var nav_data = {
                link: data.url,
                title: data.title
            },
            nav = ('<li><a id="carousel-link" href="#next-slide" data="{data}" title="{title}">{title}</a></li>').substitute(nav_data);
            nav = elementize(nav);

            nav.store("data", data).getFirst().set("rel", data.rel);

            // By default, first block is selected.
            if (i === 0) {
                nav.addClass("selected");
            }
            // Notice the stupid links.length-1? Arrays index from 0 even in foreach!
            // Last class takes off the borders and other things.
            if (i === (slides.length - 1)) {
                nav.addClass("last");
            }

            // Add the mouseenter/leave events.
            nav.addEvents({
                "click": this.events.over.bind(this)
            });

            // Let the nav grab the element.
            this.nav.grab(nav);

        },
        this); // This links.each loop is bound to _THIS_.
        this.tick(); // Start it up.
 		this.fireEvent("startUp");
    },

    tick: function (mouseHover) {

		this.fireEvent("beforeSlide");

		if ( mouseHover == null && this.options.loops > 0 && this.cycles >= this.options.loops) {
            $clear(this.timer);
			this.fireEvent("end");
            return false;
        }	
		
        var links = this.nav.getElements("li a");
        links.removeClass("selected").each(function (el, i) {
            if (this.ticks === i) {
                el.addClass("selected");
            }
        },
        this);

        this.slide();
		
		this.fireEvent("afterSlide");

        this.ticks++;
		
        if (this.ticks > (links.length - 1)) {
            this.ticks = 0;
            this.cycles++;
			this.fireEvent("startOver");
        }
        $clear(this.timer);
        this.timer = this.tick.delay(this.options.delay, this);
    },

    events: {
        over: function (event) {
            var data = event.target.getParent().retrieve("data", {
                index: 0
            });
            this.ticks = data.index;
            this.tick(true);
            $clear(this.timer);
			this.fireEvent("mouseEnter");
        },
        out: function (event) {
            this.timer = this.tick.delay(this.options.delay, this);
			this.fireEvent("mouseLeave");
        }
    },

    slide: function () {
        this.animate.tween("left", 0 - (this.ticks * this.options.width));
    }

});
