var GoodCarousel = new Class({

    container: null,
    inner: null,
    animate: null,
    nav: null,

    data: null,
    timer: null,
    ticks: 0,

    options: {
        width: 624,
        height: 282,
        delay: 5100,
        duration: 700
    },

    Implements: [Options],

    initialize: function (container, options) {
        this.setOptions(options);
        this.container = document.id(container);
        this.parseData();
        this.setup();
    },

    parseData: function () {

        var data = [],
		slides = this.container.getElements(".carousel-data");
		
        slides.each(function (el, i) {
            var slide = {},
            link = el.getElement("p a"),
            img = el.getElement("img");
            slide.title = el.getElement("h3").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); // Because I don't trust data[] = slide; in js.
        },
        this);

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

    },

    setup: function () {

        // 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
            }
        });
        // 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) {

            // Saving time by use substitue.
            var biglink_tpl = '<a class="carousel-item" href="{url}"><img src="{img}" height="{height}" width="{width}" border="0" /><span class="carousel-item-info"><strong><span>{title}</span></strong><br /><span>{desc}</span></span></a>',
            biglink_data = {
                url: data.url,
                img: data.img,
                height: this.options.height,
                width: this.options.width,
                title: data.title,
                desc: data.desc
            };
            // Run the substitute.
            var biglink = biglink_tpl.substitute(biglink_data);
            // Literalize the HTML by getting it out of a fake div.
            var biglink_e = new Element("div", {
                html: biglink
            }).getFirst();
            // Set the width on it too.
            biglink_e.setStyle("width", this.options.width);
            // Set the rel.
            biglink_e.set("rel", data.rel);
            // After element was made, have animate div grab it.
            this.animate.grab(biglink_e);

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

            // Get the element.
            var nav_e = (new Element("div", {
                html: nav
            })).getFirst();

            nav_e.store("data", data);

            // Set the width by dividing the # of links by the option-width.
            nav_e.setStyle("width", Math.floor(this.options.width / slides.length));

            // Set the rel on the inner link, not the list item.
            nav_e.getFirst().set("rel", data.rel);

            // By default, first block is selected.
            if (i == 0) {
                nav_e.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_e.addClass("last");
            }

            // Add the mouseenter/leave events.
            nav_e.addEvents({
                "mouseenter": this.events.over.bind(this),
                "mouseleave": this.events.out.bind(this)
            });

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

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

    /*
		The recuring function that triggers the slides to move.
			Removes selected class
			Adds selected class to whatever needs it
			Runs the tween
			Increments tick or resets it
			Clears and restarts timer.
	*/
    tick: function () {

        // Get the links in nav.
        var links = this.nav.getElements("li a");

        // selected is on one of them, so take it off.
        links.removeClass("selected");

        // It should be on one of them now anyway, add it.
        links.each(function (el, i) {
            if (this.ticks == i) {
                el.addClass("selected");
            }
        },
        this);

        // Run the _ANTIMATION_. This is based on the tick # and the option-width.
        this.slide(this.ticks * this.options.width);

        // Increment.
        this.ticks++;

        // Remember, (links.length-1) looks stupid but length doesn't _really_ start at 0.
        // If tick meets the length-1 of the links, restart.
        if (this.ticks > (links.length - 1)) {
            this.ticks = 0;

        }
        $clear(this.timer); // Clear.
        this.timer = this.tick.delay(this.options.delay, this); // Reset.
    },

    events: {
        over: function (event) {
            // Mouseenter: when they move over the block.
            var data = event.target.getParent().retrieve("data", {
                index: 0
            });
            // Set tick to the current block.
            this.ticks = data.index;
            this.tick();
            $clear(this.timer); // This clear pauses movement until mouseleave.
        },
        out: function (event) {
            // Resume movement.
            this.timer = this.tick.delay(this.options.delay, this);
        }
    },

    slide: function (to) {
        // This is the _ANIMATION_ function. Slides.
        this.animate.set("tween", {
            duration: this.options.duration
        });
        this.animate.tween("left", 0 - to);
    }

});
