// Ajax.Carousel v1.0
// $Id: ajax.carousel.js 37 2009-04-07 17:19:47Z joshua $
// An Image Carousel Javascript Class for the Prototype and Script.aculo.us toolkits.
//
// Copyright (c) 2009 Joshua Newman
//
// This project is loosely based on the spectacular JQuery Agile Carousel script. However,
// I had a need for something very similar that worked as pure javascript with Prototype 
// and Scriptaculous, so Ajax.Carousel was born.
//
// Requirements: (all included in the /lib directory)
// Prototype (http://www.prototypejs.org)
// Script.aculo.us (http://script.aculo.us)
// SuperSleight (http://24ways.org/2007/supersleight-transparent-png-in-ie6)
//
// This software is licensed under the GPL v3. For more information, see the GPL website:
// http://www.gnu.org/licenses/gpl-3.0.txt
//
// For documentation of this project, please visit the google code project page:
// http://code.google.com/p/ajaxcarousel/

Ajax.Carousel = Class.create({
  initialize: function(element, options) {
    this.element = element = $(element);
    // Set up global variables
    this.id = this.element.id;
    this.version = "1.0";
    this.transitionTypes = ['none', 'crossfade', 'blinddown', 'blindup', 'dropout', 'puff', 'grow', 'shrink', 'fold', 'switchoff', 'slideup', 'slidedown', 'slideleft', 'slideright'];
    this.transitionEasings = ['linear', 'sinoidal', 'spring'];

    this.prepareOptions(options);
    this.addLoadEvent(function() { this.initAfterLoad() } .bind(this));
    //this.debug("Ajax.Carousel " + this.version);
  },
  initAfterLoad: function() {
    this.innerId = this.id + "-inner";
    this.slides = new Array();
    this.buttonPosition = (parseInt(this.options._innerWidth) - parseInt(this.options.buttonPosition));
    this.createContainer();
    this.createSlides();
    this.isPaused = true;
    this.isPlaying = false;
    //this.debug("Initialized.");
  },
  createContainer: function() { // Creates the slideshow container
    //this.debug("Creating container...");
    var style = document.createElement('style');
    style.type = "text/css";
    var cssText = "";
    if (this.options.showControls == "yes") { // Control container
      // Control buttons
      cssText += "#" + this.id + "-controls div {\n";
      cssText += "height: " + parseInt(this.options.control_buttons.height) + "px;\n";
      cssText += "top: " + Math.round((parseInt(this.options.controls.height) - parseInt(this.options.control_buttons.height)) / 2) + "px;\n";
      cssText += "}\n";
    } // Control container
    if (this.options.showHoverPrevNext == "yes") { // hover next and hover prev buttons
      cssText += "#" + this.id + "-hover_next, #" + this.id + "-hover_prev {\n";
      cssText += "background-color: " + this.options.backgroundColor + ";";
      if (this.options.showControls == "yes") { // Need to make room for the controls if they exist
        cssText += "top: " + parseInt(this.options.controls.height) + "px;\n";
        cssText += "background-position: 50% " + (Math.round(parseInt(this.options._innerHeight) / 2) - (Math.round(parseInt(this.options.hover_next.height) / 2) + parseInt(this.options.controls.height))) + "px;\n";
      } else { // Nope. let's do the full height
        cssText += "background-position: center center;\n";
      } // if (this.options.showControls == "yes")
      cssText += "width: " + parseInt(this.options.hover_next.width) + "px;\n";
      cssText += "background-repeat: no-repeat;\n";
      cssText += "}\n";
    } // hover next and hover prev buttons
    cssText += this.options.additionalCSS;
    if (Prototype.Browser.IE) {
      style.styleSheet.cssText = cssText;
    } else { // everybody else
      style.appendChild(document.createTextNode(cssText));
    }
    document.getElementsByTagName("head")[0].appendChild(style);
    var Container = document.createElement("div");
    Container = $(Container);
    Container.setStyle({
      width: parseInt(this.options._innerWidth) + "px",
      height: parseInt(this.options._innerHeight) + "px",
      left: parseInt(this.options.innerPadding) + "px",
      top: parseInt(this.options.innerPadding) + "px"
    });
    Container.id = this.innerId;
    Container.className = "carousel-inner";
    
    if(this.options.useRoundedInnerCorners == "yes") { // Rounded inner corners
      var topLeft = document.createElement("div");
      topLeft = $(topLeft);
      topLeft.id = this.id + "-rounded_top_left";
      topLeft.className = "carousel-rounded_top_left";
      Container.appendChild(topLeft);
      var topRight = document.createElement("div");
      topRight = $(topRight);
      topRight.id = this.id + "-rounded_top_right";
      topRight.className = "carousel-rounded_top_right";
      Container.appendChild(topRight);
      var bottomLeft = document.createElement("div");
      bottomLeft = $(bottomLeft);
      bottomLeft.id = this.id + "-rounded_bottom_left";
      bottomLeft.className = "carousel-rounded_bottom_left";
      Container.appendChild(bottomLeft);
      var bottomRight = document.createElement("div");
      bottomRight = $(bottomRight);
      bottomRight.id = this.id + "-rounded_bottom_right";
      bottomRight.className = "carousel-rounded_bottom_right";
      Container.appendChild(bottomRight);
    }

    // Build the controls
    if (this.options.showControls == "yes") { // Main Controls Container
      //this.debug("Building Controls...");
      var controls = document.createElement("div");
      controls = $(controls);
      controls.setStyle(this.options.controls);
      controls.setStyle({
        width: parseInt(this.options._innerWidth) + "px",
        top: "0px",
        left: "0px"
      });
      var cbo = this.options.control_buttons;
      controls.id = this.id + "-controls";
      controls.className = "carousel-controls";
      Container.appendChild(controls);
      if (this.options.showFirstLast == "yes") { // Last Button
        //this.debug("- Last button");
        this.buttonPosition -= parseInt(cbo.last.width);
        var last_button = document.createElement("div");
        last_button = $(last_button);
        with (last_button) {
          setStyle(this.options.control_buttons.last);
          setStyle({
            left: this.buttonPosition + "px",
            top: Math.round((parseInt(this.options.controls.height) - parseInt(cbo.height)) / 2) + "px",
            height: parseInt(this.options.control_buttons.height) + "px",
            backgroundPosition: "0px " + parseInt(this.options.control_buttons.offset) + "px"
          });
          //last_button = Element.applyCSS(last_button, this.options.control_buttons.last);
          last_button.id = this.id + "-last_button";
          addClassName("carousel-last_button");
          addClassName("carousel-control_button");
          writeAttribute({
            alt: "Last Slide",
            title: "Last Slide"
          });
        }
        controls.appendChild(last_button);
        this.addNewListener(last_button.id, 'mouseover', this.handleControls.bindAsEventListener(this));
        this.addNewListener(last_button.id, 'mouseout', this.handleControls.bindAsEventListener(this));
        this.addNewListener(last_button.id, 'click', this.handleControls.bindAsEventListener(this, "last"));
      } // Last Button
      if (this.options.showPrevNext == "yes") { // Next Button
        //this.debug("- Next button");
        this.buttonPosition -= parseInt(cbo.next.width);
        var next_button = document.createElement("div");
        next_button = $(next_button);
        with (next_button) {
          setStyle(this.options.control_buttons.next);
          setStyle({
            left: this.buttonPosition + "px",
            top: Math.round((parseInt(this.options.controls.height) - parseInt(cbo.height)) / 2) + "px",
            height: parseInt(this.options.control_buttons.height) + "px",
            backgroundPosition: "0px " + parseInt(this.options.control_buttons.offset) + "px"
          });
          next_button.id = this.id + "-next_button";
          addClassName("carousel-next_button");
          addClassName("carousel-control_button");
          writeAttribute({
            alt: "Next Slide",
            title: "Next Slide"
          });
        }
        controls.appendChild(next_button);
        this.addNewListener(next_button.id, 'mouseover', this.handleControls.bindAsEventListener(this));
        this.addNewListener(next_button.id, 'mouseout', this.handleControls.bindAsEventListener(this));
        this.addNewListener(next_button.id, 'click', this.handleControls.bindAsEventListener(this, "next"));
      } // Next Button
      if (this.options.showPausePlay == "yes") { // Pause/Play
        //this.debug("- Pause/Play button");
        this.buttonPosition -= parseInt(cbo.pause.width);
        var play_button = document.createElement("div");
        play_button = $(play_button);
        with (play_button) {
          setStyle(this.options.control_buttons.play);
          setStyle({
            left: this.buttonPosition + "px",
            top: Math.round((parseInt(this.options.controls.height) - parseInt(cbo.height)) / 2) + "px",
            height: parseInt(this.options.control_buttons.height) + "px",
            backgroundPosition: "0px " + parseInt(this.options.control_buttons.offset) + "px"
          });
          play_button.id = this.id + "-pause_button";
          writeAttribute({
            alt: "Play",
            title: "Play"
          });
          addClassName("carousel-play_button");
          addClassName("carousel-control_button");
        }
        controls.appendChild(play_button);
        this.addNewListener(play_button.id, 'mouseover', this.handleControls.bindAsEventListener(this));
        this.addNewListener(play_button.id, 'mouseout', this.handleControls.bindAsEventListener(this));
        this.addNewListener(play_button.id, 'click', this.handleControls.bindAsEventListener(this, "pauseplay"));
      } // Pause/Play
      if (this.options.showPrevNext == "yes") { // Previous Button
        //this.debug("- Previous button");
        this.buttonPosition -= parseInt(cbo.prev.width);
        var prev_button = document.createElement("div");
        prev_button = $(prev_button);
        with (prev_button) {
          setStyle(this.options.control_buttons.prev);
          setStyle({
            left: this.buttonPosition + "px",
            top: Math.round((parseInt(this.options.controls.height) - parseInt(cbo.height)) / 2) + "px",
            height: parseInt(this.options.control_buttons.height) + "px",
            backgroundPosition: "0px " + parseInt(this.options.control_buttons.offset) + "px"
          });
          prev_button.id = this.id + "-prev_button";
          addClassName("carousel-prev_button");
          addClassName("carousel-control_button");
          writeAttribute({
            alt: "Previous Slide",
            title: "Previous Slide"
          });
        }
        controls.appendChild(prev_button);
        this.addNewListener(prev_button.id, 'mouseover', this.handleControls.bindAsEventListener(this));
        this.addNewListener(prev_button.id, 'mouseout', this.handleControls.bindAsEventListener(this));
        this.addNewListener(prev_button.id, 'click', this.handleControls.bindAsEventListener(this, "prev"));
        var next_button = document.createElement("div");
      } // Previous Button
      if (this.options.showFirstLast == "yes") { // First Button
        //this.debug("- First button");
        this.buttonPosition -= parseInt(cbo.first.width);
        var first_button = document.createElement("div");
        first_button = $(first_button);
        with (first_button) {
          setStyle(this.options.control_buttons.first);
          setStyle({
            left: this.buttonPosition + "px",
            top: Math.round((parseInt(this.options.controls.height) - parseInt(cbo.height)) / 2) + "px",
            height: parseInt(this.options.control_buttons.height) + "px",
            backgroundPosition: "0px " + parseInt(this.options.control_buttons.offset) + "px"
          });
          first_button.id = this.id + "-first_button";
          addClassName("carousel-first_button");
          addClassName("carousel-control_button");
          writeAttribute({
            alt: "First Slide",
            title: "First Slide"
          });
        }
        controls.appendChild(first_button);
        this.addNewListener(first_button.id, 'mouseover', this.handleControls.bindAsEventListener(this));
        this.addNewListener(first_button.id, 'mouseout', this.handleControls.bindAsEventListener(this));
        this.addNewListener(first_button.id, 'click', this.handleControls.bindAsEventListener(this, "first"));
      } // First Button
      this.buttonPosition -= cbo.slide_bullet.left;
      if (this.options.showSlideCaptions == "yes") { // Slide Captions
        //this.debug("- Slide Captions");
        var slide_caption = document.createElement("div");
        slide_caption = $(slide_caption);
        slide_caption.setStyle(this.options.slide_caption);
        slide_caption.setStyle({
          top: "0px",
          left: parseInt(this.options.buttonPosition) + "px",
          height: parseInt(this.options.controls.height) + "px",
          lineHeight: parseInt(this.options.controls.height) + "px"
        });
        slide_caption.id = this.id + "-slide_caption";
        slide_caption.className = "carousel-slide_caption";
        controls.appendChild(slide_caption);
      } // Slide Captions
      Container.appendChild(controls);
    } // Controls

    if (this.options.showHoverPrevNext == "yes") { // Hover Previous & Next buttons
      // Previous Slide Hover Button
      //this.debug("- Previous hover button");
      var hover_prev = document.createElement("div");
      hover_prev = $(hover_prev);
      with (hover_prev) {
        setStyle(this.options.hover_prev);
        setStyle({
          height: (this.options.showControls == "yes") ? (parseInt(this.options._innerHeight) - parseInt(this.options.controls.height)) + "px" : parseInt(this.options._innerHeight) + "px",
          opacity: 0
        });
        hover_prev.id = this.id + "-hover_prev";
        writeAttribute({
          alt: "Previous Slide",
          title: "Previous Slide"
        });
        addClassName("carousel-hover_prev");
      }
      Container.appendChild(hover_prev);
      this.addNewListener(hover_prev.id, 'mouseover', this.handleControls.bindAsEventListener(this));
      this.addNewListener(hover_prev.id, 'mouseout', this.handleControls.bindAsEventListener(this));
      this.addNewListener(hover_prev.id, 'click', this.handleControls.bindAsEventListener(this, "hover_prev"));
      // Next Slide Hover Button
      //this.debug("- Next hover button");
      var hover_next = document.createElement("div");
      hover_next = $(hover_next);
      with (hover_next) {
        setStyle(this.options.hover_next);
        setStyle({
          height: (this.options.showControls == "yes") ? (parseInt(this.options._innerHeight) - parseInt(this.options.controls.height)) + "px" : parseInt(this.options._innerHeight) + "px",
          opacity: 0
        });
        hover_next.id = this.id + "-hover_next";
        writeAttribute({
          alt: "Next Slide",
          title: "Next Slide"
        });
        addClassName("carousel-hover_next");
      }
      Container.appendChild(hover_next);
      this.addNewListener(hover_next.id, 'mouseover', this.handleControls.bindAsEventListener(this));
      this.addNewListener(hover_next.id, 'mouseout', this.handleControls.bindAsEventListener(this));
      this.addNewListener(hover_next.id, 'click', this.handleControls.bindAsEventListener(this, "hover_next"));
    } // Hover Previous & Next buttons

    if (this.options.showSlideNumber == "yes") { // Slide Number
      //this.debug("- Slide Number");
      var slide_number = document.createElement("div");
      slide_number = $(slide_number);
      with (slide_number) {
        setStyle(this.options.slide_number);
        setStyle({
          top: (parseInt(this.options._innerHeight) - parseInt(this.options.slide_number.height) - 7) + "px",
          left: (parseInt(this.options._innerWidth) - parseInt(this.options.slide_number.width) - 7) + "px",
          lineHeight: parseInt(this.options.slide_number.height) + "px"
        });
        slide_number.id = this.id + "-slide_number";
        addClassName("carousel-slide_number");
      }
      Container.appendChild(slide_number);
    } // Slide Number

    if (!(this.options.waterMark == "")) { // Watermark
      //this.debug("- Watermark");
      var water_mark = document.createElement("div");
      water_mark = $(water_mark);
      with (water_mark) {
        // Place the water mark on the bottom right, 10px to the left of the slide number.
        setStyle(this.options.water_mark);
        setStyle({
          top: (parseInt(this.options._innerHeight) - (parseInt(this.options.water_mark.height) + 5)) + "px",
          left: (parseInt(this.options._innerWidth) - (parseInt(this.options.water_mark.width) + parseInt(this.options.slide_number.width) + 10)) + "px",
          lineHeight: parseInt(this.options.water_mark.height) + "px"
        });
        water_mark.id = this.id + "-water_mark";
        addClassName("carousel-water_mark");
        water_mark.innerHTML = this.options.waterMark;
      }
      Container.appendChild(water_mark);
    } // Watermark

    // Slide Container
    //this.debug("Slide Container...");
    var slide_holder = document.createElement("div");
    slide_holder = $(slide_holder);
    slide_holder.setStyle({
      width: parseInt(this.options._innerWidth) + "px",
      height: parseInt(this.options._innerHeight) + "px"
    });
    slide_holder.id = this.id + "-slides";
    slide_holder.addClassName("carousel-slides");
    Container.appendChild(slide_holder);

    this.element.appendChild(Container);
    //this.debug("CreateContainer Complete.");

  }, // createContainer:
  createSlides: function() { // Creates slides from the player's rss feed
    //this.debug("Ajax request for rss feed initializing...");
    var ajaxOptions = Object.clone(this.options.ajaxOptions);
    Object.extend(ajaxOptions, {
      onSuccess: function(transport) {
        //this.debug("200 OK Received. Building Slides...");
        var items = transport.responseXML.getElementsByTagName('item');
        var slideNum = 0;
        if (this.options.firstSlideIsIntro != "yes") this.slides[0] = { id: this.id + "-loading", caption: "", enclosureUrl: "", enclosureType: "", linkHref: "", linkTarget: "" };
        for (var b = 0; b < items.length; b++) { // Loop through the slides
          //this.debug("- Slide " + b);
          var slideId, slideCaption, slideEnclosureURL, slideEnclosureType, slideLinkHref, slideLinkTarget
          if (this.options.firstSlideIsIntro == "yes" && slideNum == 0) {
            slideId = this.id + "-slide_intro";
          } else { // Intro is always slide 0. Everything else starts with 1.
            slideNum++;
            slideId = this.id + "-slide_" + slideNum;
          } // if (this.options.firstSlideIsIntro == "yes" && slideNum == 0)

          for (var c = 0; c < items[b].childNodes.length; ++c) {
            var item = items[b].childNodes[c];
            if (item.nodeName == "title") slideCaption = ( item.text || item.textContent ) || '';
            if (item.nodeName == "description") slideDescription = ( item.text || item.textContent ) || '';
            if (item.nodeName == "link") {
              slideLinkHref = (item.text || item.textContent) || '#';
              for (var d = 0; d < item.attributes.length; ++d) {
                if (item.attributes[d].nodeName == "target") slideLinkTarget = item.attributes[d].nodeValue;
              }
            }
            if (item.nodeName == "enclosure") {
              for (var d = 0; d < item.attributes.length; ++d) {
                if (item.attributes[d].nodeName == "url") slideEnclosureURL = item.attributes[d].nodeValue;
                if (item.attributes[d].nodeName == "type") slideEnclosureType = item.attributes[d].nodeValue;
              }
            }
          }

          //this.debug("- - id:" + slideId + "\n- - caption:" + slideCaption + "\n- - description:" + slideDescription +
          //            "\n- - enclosureURL:" + slideEnclosureURL + "\n- - enclosureType:" + slideEnclosureType + "\n- - linkHref:" +
          //            slideLinkHref + "\n- - linkTarget:" + slideLinkTarget);

          var slide_holder = $(this.id + "-slides");
          slide_holder.setStyle({
            width: parseInt(this.options._innerWidth) + "px",
            height: parseInt(this.options._innerHeight) + "px"
          });

          // Create our slide div
          var slide = document.createElement('div');
          slide = $(slide);
          if (this.options.firstSlideIsIntro == "yes" && slideNum == 0) {
            //this.debug("-- Intro Slide");
            slide.addClassName("carousel-intro");
          } else {
            //this.debug("-- Normal Slide");
            slide.addClassName("carousel-slide");
          } // if (this.options.firstSlideIsIntro == "yes")
          slide.id = slideId;
          slide.hide();

          // build HTML according to the file type
          if (slideEnclosureURL.match(/^.+\.(jpe?g|png|gif)$/i) || slideEnclosureType.match(/^.+\/(jpe?g|png|gif)$/i)) { // Image files
            //this.debug("-- Image Slide");
            this.slides[slideNum] = {
              id: slideId,
              caption: slideCaption,
              description: slideDescription,
              enclosureURL: slideEnclosureURL,
              enclosureType: slideEnclosureType,
              linkHref: slideLinkHref,
              linkTarget: slideLinkTarget
            };
            var slide_link = document.createElement('a');
            slide_link.href = this.slides[slideNum].linkHref;
            slide_link.target = this.slides[slideNum].linkTarget;

            var slide_img = document.createElement('img');
            slide_img = $(slide_img);
            with (slide_img) {
              slide_img.src = slideEnclosureURL;
              writeAttribute({
                alt: this.slides[slideNum].description,
                title: this.slides[slideNum].description,
                height: parseInt(this.options._innerHeight),
                width: parseInt(this.options._innerWidth),
                border: 0
              });
              setStyle({
                height: parseInt(this.options._innerHeight),
                width: parseInt(this.options._innerWidth)
              });
            }

            slide_link.appendChild(slide_img);
            slide.appendChild(slide_link);
            slide_holder.appendChild(slide);

          } else if (slideEnclosureURL.match(/^.+\.(swf)$/i) || slideEnclosureType.match(/^.+\/(x-shockwave-flash)$/i)) { // Flash files
            //this.debug("-- Flash Slide");
            this.slides[slideNum] = {
              id: slideId,
              caption: slideCaption,
              description: slideDescription,
              enclosureURL: slideEnclosureURL,
              enclosureType: slideEnclosureType,
              linkHref: slideLinkHref,
              linkTarget: slideLinkTarget
            };
            var swf = document.createElement('object');
            swf = $(swf);
            swf.writeAttribute({
              type: "application/x-shockwave-flash",
              data: this.slides[slideNum].enclosureURL,
              height: parseInt(this.options._innerHeight),
              width: parseInt(this.options._innerWidth)
            });

            var swfparam1 = document.createElement('param');
            swfparam1 = $(swfparam1);
            swfparam1.writeAttribute({
              name: "movie",
              value: this.slides[slideNum].enclosureURL
            });

            var swfparam2 = document.createElement('param');
            swfparam2 = $(swfparam2);
            swfparam2.writeAttribute({
              name: "wmode",
              value: "opaque"
            });

            swf.appendChild(swfparam2);
            swf.appendChild(swfparam1);
            slide.appendChild(swf);
            slide_holder.appendChild(slide);

          } else if (slideEnclosureURL.match(/^.+\.(htm?l|php|cgi)$/i) || slideEnclosureType.match(/^.+\/(html|xml)$/i)) { // .html, .php & .cgi files or via the mime types text/html or text/xml
            //this.debug("-- HTML Slide (sending Ajax Request)");
            this.slides[slideNum] = {
              id: slideId,
              caption: slideCaption,
              description: slideDescription,
              enclosureURL: slideEnclosureURL,
              enclosureType: slideEnclosureType,
              linkHref: slideLinkHref,
              linkTarget: slideLinkTarget
            };
            var ajaxOptions = Object.clone(this.options.ajaxOptions);
            Object.extend(ajaxOptions, {
              onSuccess: function(transport) {
                //this.debug("200 OK Received for HTML slide. Response:");
                //this.debug("<pre>" + debugText + "</pre>");

                var response;
                if (typeof XRegExp == "function") { // Yay, using XRegExp!
                  var regex = new XRegExp("<\/?html.*?>|<head.*?\/head>|<\/?body.*?>|<script.*?\/script>");
                  response = transport.responseText.replace(regex);
                } else {
                  response = transport.responseText.replace(/<\/?html.*?>|<head.*?\/head>|<\/?head.*?>|<\/?body.*?>|<script.*?\/script>|<\/?script.*?>|<\/?title.*?\/title>|<\/?link.*?>|<\/?meta.*?>/gmi);
                }
                $(slide.id).innerHTML = response;

              } .bind(slide) // onSuccess: function(transport)
            });
            new Ajax.Request(this.slides[slideNum].enclosureURL, ajaxOptions);
            //this.debug("Ajax Request sent.");
            slide_holder.appendChild(slide);

          } else { // Anything else is an unsupported file type, ignore it.
            slide = "";
          }

          if (this.options.pauseOnSlideHover == "yes" && this.options.useTimer == "yes") { // Add listener for hover
            this.addNewListener(slide.id, 'mouseover', this.handleSlideHover.bindAsEventListener(this));
            this.addNewListener(slide.id, 'mouseout', this.handleSlideHover.bindAsEventListener(this));
          } // Hover listener

        } // for ( var b = 0; b < items.length; b++ )
        if (this.options.showSlideBullets == "yes" && this.options.showControls == "yes") {
          //this.debug("Adding slide bullets");
          this.buttonPosition = parseInt(this.options.buttonPosition);
          for (var slideBulletIndex = 1; slideBulletIndex < this.slides.length; slideBulletIndex++) {
            var slide_bullet = document.createElement('div');
            slide_bullet = $(slide_bullet);
            with (slide_bullet) {
              setStyle(this.options.control_buttons.slide_bullet);
              setStyle({
                height: parseInt(this.options.control_buttons.height) + "px",
                left: parseInt(this.buttonPosition) + "px",
                backgroundPosition: "0px " + parseInt(this.options.control_buttons.offset) + "px"
              });
              slide_bullet.id = this.id + "-slide_bullet_" + slideBulletIndex;
              writeAttribute({
                title: "Slide " + slideBulletIndex,
                alt: "Slide " + slideBulletIndex
              });
              addClassName("carousel-slide_bullet");
              addClassName("carousel-control_button");
            }
            $(this.id + "-controls").appendChild(slide_bullet);
            this.addNewListener(slide_bullet.id, 'mouseover', this.handleControls.bindAsEventListener(this, slideBulletIndex));
            this.buttonPosition += parseInt(this.options.control_buttons.slide_bullet.width) + parseInt(this.options.control_buttons.slide_bullet.padding);
            if (this.options.showSlideCaptions == "yes")
              $(this.id + "-slide_caption").setStyle({ left: this.buttonPosition + parseInt(this.options.buttonPosition) + "px" });
          }
        }

        // Everything is loaded, start the show
        if(this.slides.length > 1) {
          this.startSlideShow(); 
        } else {
          this.unRegisterListeners();
          $(this.id + '-loading').fade();
          var slideContainer = $(this.id + '-slides');
          slideContainer.innerHTML = "No slides are available in this feed.";
          slideContainer.zIndex = 60;
        }
        //this.debug("Slide Creation Complete.");

      } .bind(this) // onSuccess: function(transport)
    }); // Object.extend(ajaxOptions)
    new Ajax.Request(this.options.rssFeed, ajaxOptions);
    //this.debug("done.");
  }, // createSlides:
  handleSlideHover: function(e) { // Pause on mouseover
    //this.debug(Event.element(e).id + ":" + e.type + " event fired.");
    if (this.options.useTimer == "yes") {
      switch (e.type) {
        case "mouseover":
          Event.stop(e);
          if (this.isPaused) return;
          this._pause();
          break;
        case "mouseout":
          if (this.isPaused) return;
          this._play();
          break;
      }
    }
  }, // enterHover:
  handleControls: function(e) { // Handles all control elements
    //this.debug(Event.element(e).id + ":" + e.type + " event fired.");
    var element = Event.element(e);
    var args = $A(arguments);
    args.shift();
    switch (e.type) {
      case "mouseover":
        Event.stop(e);
        // If it's a hover button, we want to fade it in.
        if (element.hasClassName("carousel-hover_next") || element.hasClassName("carousel-hover_prev")) {
          // for some reason, IE makes it disappear at 100%, so we'll only go to 99%.
          new Effect.Opacity(element.id, { duration: 0.5, from: 0.0, to: 0.99 });
        } else { // Other buttons we just change the background position to the hover image.
          element.style.backgroundPosition = "0px 0px";
          // If it's a slide bullet, show that slide.
          if (element.hasClassName("carousel-slide_bullet")) this.showSlide(args[0], 'none');
        }
        break;
      case "mouseout":
        // hover buttons fade out
        if (element.hasClassName("carousel-hover_next") || element.hasClassName("carousel-hover_prev")) {
          // To prevent flashing with the IE strangeness, we start at 99% instead of 100%.
          new Effect.Opacity(element.id, { duration: 0.5, from: 0.99, to: 0.0 });
        } else { // other buttons back to normal background position
          element.style.backgroundPosition = "0px " + parseInt(this.options.control_buttons.offset) + "px";
        }
        break;
      case "click":
        switch (args[0]) {
          case "pauseplay":
            if (this.isPaused) {
              this.Play();
            } else {
              this.Pause();
            }
            break;
          case "prev":
            this.showSlide((this.currentSlide - 1 == 0) ? this.slides.length - 1 : this.currentSlide - 1);
            break;
          case "next":
            this.showSlide(this.currentSlide + 1);
            break;
          case "first":
            this.showSlide(1);
            break;
          case "last":
            this.showSlide(this.slides.length - 1);
            break;
          case "hover_prev":
            this.showSlide((this.currentSlide - 1 == 0) ? this.slides.length - 1 : this.currentSlide - 1);
            break;
          case "hover_next":
            this.showSlide(this.currentSlide + 1);
            break;
        }
        break;
    }
  },
  startSlideShow: function() { // Starts the show!
    //this.debug("Starting Slideshow...");
  	if (this.slides.length <= 2) {
      this.unRegisterListeners();
      this.currentSlide = 1;
      this.lastSlide = 0;
      $(this.slides[this.currentSlide].id).bringToFront().show();
      this.updateSlide();
    } else {
      this.registerListeners();
      if (this.options.firstSlideIsIntro == "yes") {
        this.showSlide(0);
      } else {
        this.showSlide(1);
      }
    }
    (this.options.useTimer == "yes" && this.slides.length > 2) ? this.Play() : this.Pause();
    if (!(this.options.waterMark == "")) new Effect.Opacity(this.id + "-water_mark", { from: 0.99, to: 0.2 });
    $(this.id + "-loading").fade();
    //this.debug("Slideshow started.");
  },
  Play: function() { // User play functionality
    //this.debug("Play called.");
    this._play();
    this.isPaused = false;
    this.isPlaying = true;
    if (this.options.showControls == "yes" && this.options.showPausePlay == "yes" ) {
	  var pause_button = $(this.id + "-pause_button");
	  with (pause_button) {
	    setStyle(this.options.control_buttons.pause);
	    writeAttribute({
	      alt: "Pause",
	      title: "Pause"
	    });
	    addClassName("carousel-play_button");
	    removeClassName("carousel-pause_button");
	    addClassName(this.id + "-paused");
	    removeClassName(this.id + "-playing");
	  }
    }
  }, // Play:
  Pause: function() { // User pause functionality
    //this.debug("Pause called.");
    this._pause();
    this.isPaused = true;
    this.isPlaying = false;
    if (this.options.showControls == "yes" && this.options.showPausePlay == "yes" ) {
	  var play_button = $(this.id + "-pause_button");
	  with (play_button) {
	    setStyle(this.options.control_buttons.play);
	    writeAttribute({
	      alt: "Play",
	      title: "Play"
	    });
	    addClassName("carousel-pause_button");
	    removeClassName("carousel-play_button");
	    addClassName(this.id + "-playing");
	    removeClassName(this.id + "-paused");
	  }
    }
  }, // Pause
  _play: function() { // System play functionality
    //this.debug("Playing...");
    if (Object.isUndefined(this.slideTimer) || !this.slideTimer.currentlyExecuting) {
      this.slideTimer = new PeriodicalExecuter(function() {
        this.showSlide(this.currentSlide + 1);
      } .bind(this), this.options.slideDuration);
    } // if (this.__paused && this.options.useTimer)
  }, // _play:
  _pause: function() { // System pause functionality
    //this.debug("Pausing...");
    var pause_button = $(this.id + "_pause_button");
    if (!Object.isUndefined(this.slideTimer)) {
      this.slideTimer.stop();
    } // if (this.IsPlaying && this.options.useTimer)
  }, // Pause:
  showSlide: function(slideNum, transition) { // Slide Changes
    //this.debug("Changing Slide...");
    // intro slide is always slide 0
    if (!slideNum) (this.options.firstSlideIsIntro == "yes") ? slideNum = 0 : slideNum = 1;
    if (!this.currentSlide) this.currentSlide = this.slides.length - 1;
    if (this.currentSlide != slideNum) {
      if (slideNum == 0) {
        this.lastSlide = 0;
        this.currentSlide = 0;
      } else if (slideNum >= this.slides.length) {
        this.lastSlide = this.currentSlide;
        this.currentSlide = 1;
      } else {
        this.lastSlide = this.currentSlide;
        this.currentSlide = slideNum;
      } // if (!this.currentSlide) {} else if (slideNum >= this.slides.length) {} else
      ((this.currentSlide + 1) >= this.slides.length) ? this.nextSlide = 1 : this.nextSlide = this.currentSlide + 1;
      //this.debug("Current Slide: " + this.currentSlide + " Last Slide: " + this.lastSlide + " Next Slide: " + this.nextSlide);

      this.Transition(transition);
    }
  }, // showSlide:
  Transition: function(transition) { // Transitioning between slides
    if (!transition) transition = this.options.transitionType;
    //this.debug("Transition Called (" + transition + ", " + this.options.transitionEasing + ")");

    var lastSlide = $(this.slides[this.lastSlide].id);
    var currentSlide = $(this.slides[this.currentSlide].id);
    var nextSlide = $(this.slides[this.nextSlide].id);
    var imageWidth = parseInt(this.options._innerWidth);
    var imageHeight = parseInt(this.options._innerHeight);
    var transitionEasing;

    // Default to bringing the current slide to the front and sending the last slide to the back
    currentSlide.bringToFront();
    lastSlide.sendToBack();

    // Select the easing method (note, scriptaculous incorrectly calls easing methods transitions. *shrug*)
    switch (this.options.transitionEasing) {
      case 'linear':
        //this.debug("Set easing: linear");
        transitionEasing = Effect.Transitions.linear;
        break;
      case 'spring':
        //this.debug("Set easing: spring");
        transitionEasing = Effect.Transitions.spring;
        break;
      case 'sinoidal':
        //this.debug("Set easing: sinoidal");
      default:
        //if (this.options.transitionEasing != "sinoidal") this.debug("(" + this.options.transitionEasing + " unrecognized.)");
        transitionEasing = Effect.Transitions.sinoidal;
        break;
    }

    // Do the transition
    switch (transition) {
      case 'crossfade': // Fades slides between each other
        //this.debug("Transitioning crossfade");
        currentSlide.appear({ duration: this.options.transitionDuration });
        lastSlide.fade({ duration: this.options.transitionDuration, beforeStart: this.onTransition.bind(this) });
        break;
      case 'blinddown': // Blinds new slide down over the old
        //this.debug("Transitioning blinddown");
        currentSlide.blindDown({ duration: this.options.transitionDuration, transition: transitionEasing, beforeStart: this.onTransition.bind(this) });
        break;
      case 'blindup': // Blinds old slide up revealing the new
        //this.debug("Transitioning blindup");
        lastSlide.bringToFront();
        currentSlide.sendToBack().show();
        lastSlide.blindUp({ duration: this.options.transitionDuration, /* spring transition is broken for blindup - transition: transitionEasing, */beforeStart: this.onTransition.bind(this) });
        break;
      case 'dropout': // Old slide drops out of existence
        //this.debug("Transitioning dropout");
        lastSlide.bringToFront();
        currentSlide.sendToBack().show();
        lastSlide.dropOut({ duration: this.options.transitionDuration, beforeStart: this.onTransition.bind(this) });
        break;
      case 'puff': // Old slide puffs out of existence
        //this.debug("Transitioning puff");
        lastSlide.bringToFront();
        currentSlide.sendToBack().show();
        lastSlide.puff({ duration: this.options.transitionDuration, beforeStart: this.onTransition.bind(this) });
        break;
      case 'grow': // New slide grows into the frame over the old slide
        //this.debug("Transitioning grow");
        currentSlide.grow({ duration: this.options.transitionDuration, direction: 'center', beforeStart: this.onTransition.bind(this) });
        break;
      case 'shrink': // Old slide shrinks out of the frame revealing the new slide
        //this.debug("Transitioning shrink");
        lastSlide.bringToFront();
        currentSlide.sendToBack().show();
        lastSlide.shrink({ duration: this.options.transitionDuration, beforeStart: this.onTransition.bind(this) });
        break;
      case 'fold': // Old slide is folded and taken off screen
        //this.debug("Transitioning fold");
        lastSlide.bringToFront();
        currentSlide.sendToBack().show();
        lastSlide.fold({ duration: /* fold's transition duration is broken, so we cut it in half. */this.options.transitionDuration / 3, beforeStart: this.onTransition.bind(this) });
        break;
      case 'switchoff': // Like a TV set
        //this.debug("Transitioning switchoff");
        lastSlide.bringToFront();
        currentSlide.sendToBack().show();
        lastSlide.switchOff({ duration: /* fold's transition duration is broken, so we cut it in half. */this.options.transitionDuration / 2, beforeStart: this.onTransition.bind(this) });
        break;
      case 'slideup': // Carousel up
        //this.debug("Transitioning slideup");
        currentSlide.setStyle({ top: imageHeight + 'px' });
        nextSlide.setStyle({ top: (imageHeight * 2) + 'px' });
        currentSlide.show();
        nextSlide.show();
        currentSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:0', { duration: this.options.transitionDuration, transition: transitionEasing });
        lastSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:-' + imageHeight + 'px;left:0', { duration: this.options.transitionDuration, transition: transitionEasing });
        nextSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:' + imageHeight + 'px;left:0', { duration: this.options.transitionDuration, transition: transitionEasing, beforeStart: this.onTransition.bind(this) });
        break;
      case 'slidedown': // Carousel down
        //this.debug("Transitioning slidedown");
        currentSlide.setStyle({ top: '-' + imageHeight + 'px' });
        nextSlide.setStyle({ top: '-' + (imageHeight * 2) + 'px' });
        currentSlide.show();
        nextSlide.show();
        currentSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:0', { duration: this.options.transitionDuration, transition: transitionEasing });
        lastSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:' + imageHeight + 'px;left:0', { duration: this.options.transitionDuration, transition: transitionEasing });
        nextSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:-' + imageHeight + 'px;left:0', { duration: this.options.transitionDuration, transition: transitionEasing, beforeStart: this.onTransition.bind(this) });
        break;
      case 'slideright': // Carousel right
        //this.debug("Transitioning slideright");
        currentSlide.setStyle({ left: '-' + imageWidth + 'px' });
        nextSlide.setStyle({ left: '-' + (imageWidth * 2) + 'px' });
        currentSlide.show();
        nextSlide.show();
        currentSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:0', { duration: this.options.transitionDuration, transition: transitionEasing });
        lastSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:' + imageWidth + 'px;', { duration: this.options.transitionDuration, transition: transitionEasing });
        nextSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:-' + imageWidth + 'px;', { duration: this.options.transitionDuration, transition: transitionEasing, beforeStart: this.onTransition.bind(this) });
        break;
      case 'slideleft': // Carousel left
        //this.debug("Transitioning slideleft");
        currentSlide.setStyle({ left: imageWidth + 'px' });
        nextSlide.setStyle({ left: (imageWidth * 2) + 'px' });
        currentSlide.show();
        nextSlide.show();
        currentSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:0', { duration: this.options.transitionDuration, transition: transitionEasing });
        lastSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:-' + imageWidth + 'px;', { duration: this.options.transitionDuration, transition: transitionEasing });
        nextSlide.morph('height:' + imageHeight + ';width:' + imageWidth + ';top:0;left:' + imageWidth + 'px;', { duration: this.options.transitionDuration, transition: transitionEasing, beforeStart: this.onTransition.bind(this) });
        break;
      case 'none': // No transition
        //this.debug("Transitioning none");
      default: // No transition
        //if (transition != 'none') this.debug("(" + transition + " unrecognized.)");
        currentSlide.show();
        this.onTransition(false);
    } // switch
  }, // Transition:
  onTransition: function(isBound) { // Calls functions specific to transitioning
    if (this._duringTransition) clearTimeout(this._duringTransition);
    if (this._afterTransition) clearTimeout(this._afterTransition);
    if (this.transitionTypes.indexOf(this.options.transitionType) >= 1 && isBound) {
      this._duringTransition = setTimeout(this.updateSlide.bind(this), (this.options.transitionDuration * 1000) / 2);
      this._afterTransition = setTimeout(this.resetSlides.bind(this), this.options.transitionDuration * 1100);
    } else {
      this.updateSlide();
      this.resetSlides();
    }
  }, // onTransition:
  updateSlide: function() { // Updates the slide caption, number, and bullets.
    //this.debug("Updating slide data...");
    if (this.options.showSlideNumber == "yes") $(this.id + '-slide_number').innerHTML = this.currentSlide + " / " + (this.slides.length - 1);
    if (this.options.showControls == "yes" && this.options.showSlideBullets == "yes") {
      $(this.id + '-slide_bullet_' + this.currentSlide).setStyle({ backgroundPosition: "0px 0px" });
      if (this.lastSlide != 0) $(this.id + '-slide_bullet_' + this.lastSlide).setStyle({ backgroundPosition: "0px " + parseInt(this.options.control_buttons.offset) + "px" });
    }
    if (this.options.showControls == "yes" && this.options.showSlideCaptions == "yes") $(this.id + '-slide_caption').innerHTML = this.slides[this.currentSlide].caption;
  }, // updateSlide
  resetSlides: function() { // Resets slides to their original width, height, top and left.
    //this.debug("Resetting slides...");
    currentSlide = $(this.slides[this.currentSlide].id);
    for (var slideNum = 0; slideNum < this.slides.length; slideNum++) {
      if (slideNum != this.currentSlide) {
        with ($(this.slides[slideNum].id)) {
          hide();
          removeClassName("carousel-slide-foreground");
          removeClassName("carousel-slide-background");
          addClassName("carousel-slide-hidden");
          setStyle({
            left: currentSlide.offsetLeft,
            top: currentSlide.offsetTop,
            width: currentSlide.offsetWidth,
            height: currentSlide.offsetHeight
          });
        } // with
      } // if
    } // for
  },
  prepareOptions: function(options) { // Sets up options to defaults, as well as callback functions
    this.options = Object.clone(this.DefaultOptions);
    Object.extend(this.options, options || {});
    // Check for required options
    if (!this.options.rssFeed)
      throw ("rssFeed is a required Ajax.Carousel option.");
    // Add additional options
    if (this.element.getDimensions().width > 0 && this.element.getDimensions().height > 0) {
      Object.extend(this.options, this.element.getDimensions()); // adds this.options.width & this.options.height
    } else {
      Object.extend(this.options, {
    	height: parseInt(this.element.style.height),
    	width: parseInt(this.element.style.width)
      });
    }
    Object.extend(this.options, {
      _innerHeight: (parseInt(this.options.height) - parseInt(this.options.innerPadding) * 2),
      _innerWidth: (parseInt(this.options.width) - parseInt(this.options.innerPadding) * 2),
      backgroundColor: this.element.getStyle('background-color')
    });
    // Preload the pause button to prevent flashing
    var pause_button = new Image();
    pause_button.src = this.options.control_buttons.pause.backgroundImage;
  }, // prepareOptions:
  addNewListener: function(e, n, h) {
    //this.debug("Adding event listener " + e + ":" + n);
    this.Listeners.push({
      element: e,
      eventName: n,
      handler: h
    });
  }, // addNewListener
  registerListeners: function() { // Registers listeners
    this.Listeners.each(function(listener) {
      Event.observe(listener.element, listener.eventName, listener.handler);
    });
  }, // registerListeners
  unRegisterListeners: function() { // Unregisters listeners
    this.Listeners.each(function(listener) {
      $(listener.element).stopObserving();
    });
  },
  addLoadEvent: function(newFunction) { // Adds a body.onload event
    var currentFunction = window.onload;
    if (typeof window.onload != 'function') {
      window.onload = newFunction;
    } else {
      window.onload = function() {
        if (currentFunction) {
          currentFunction();
        }
        newFunction();
      }
    }
  }, // addLoadEvent
  debug: function(text) { // Debugging code
    if (this.options.debug) {
      $(this.options.debug).innerHTML += text + "<br>";
    }
  } // debug
});

Object.extend(Ajax.Carousel.prototype, { // Extends the Carousel for Listeners, Default Options, and Default Callbacks
  Listeners: [],
  DefaultOptions: {
    // carousel-specific options
    // Durations in seconds (not ms)
    slideDuration: "7.0",
    useTimer: "yes",
    transitionDuration: "1.0",
    transitionEasing: "spring",
    transitionType: "crossfade",
    showControls: "yes",
    showFirstLast: "yes",
    showPausePlay: "yes",
    showPrevNext: "yes",
    showSlideBullets: "yes",
    showSlideCaptions: "yes",
    showSlideNumber: "yes",
    showHoverPrevNext: "yes",
    pauseOnSlideHover: "yes",
    waterMark: "",
    firstSlideIsIntro: "no",
    introDuration: "7.0",
    introTransition: "no",
    slidesVisible: "1",
    useRoundedInnerCorners: "no",
    buttonPosition: "7px",
    // styling: all measurements should be in px only
    innerPadding: "0px",
    controls: {
      backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/bg_controls.png')",
      height: "30px",
      width: "511px",
      backgroundRepeat: "repeat-x"
    },
    control_buttons: {
      offset: "-36px",
      height: "25px",
      slide_bullet: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/slide_bullet.gif')", width: "11px", padding: "5px" },
      first: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/first.png')", width: "34px" },
      last: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/last.png')", width: "34px" },
      prev: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/prev.png')", width: "31px" },
      next: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/next.png')", width: "31px" },
      play: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/play.png')", width: "24px" },
      pause: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/pause.png')", width: "24px" }
    },
    hover_prev: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/hover_prev.png')", width: "77px", height: "118px" },
    hover_next: { backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/hover_next.png')", width: "77px", height: "118px" },
    slide_number: {
      backgroundImage: "url('/site/kingdomtools.com/images/ajax.carousel/bg_swatch.png')",
      color: "#333",
      fontFamily: "Arial, Helvetica, Sans-serif",
      fontSize: "15px",
      fontWeight: "bold",
      height: "23px",
      width: "45px",
      backgroundRepeat: "no-repeat"
    },
    slide_caption: {
      color: "#333",
      fontFamily: "Tahoma",
      fontSize: "15px",
      height: "20px",
      lineHeight: "20px"
    },
    water_mark: {
      height: "30px",
      width: "246px"
    },
    additionalCSS: "",

    // Other options
    ajaxOptions: {
      method: 'get',
      onException: function(response, error) {
        alert('Exception:\nName: ' + error.name + '\nNumber: ' + error.number + '\n\nDescription:\n' + error.description + '\n\nMessage:\n' + error.message);
      }.bind(this),
      onFailure: function(transport, ipe) {
        alert('Error communicating with the server: ' + transport.responseText.stripTags());
      }.bind(this)
    }
  } // DefaultOptions:
});        // Object.Extend(Ajax.Carousel.prototype)

Element.addMethods({
  bringToFront: function(p_eElement) {
    //this.debug("Bringing " + p_eElement.id + " to front...");
    p_eElement.removeClassName("carousel-slide-background");
    p_eElement.removeClassName("carousel-slide-hidden");
    p_eElement.addClassName("carousel-slide-foreground");
    return p_eElement;
  },
  sendToBack: function(p_eElement) {
    //this.debug("Sending " + p_eElement.id + " to back...");
    p_eElement.removeClassName("carousel-slide-foreground");
    p_eElement.removeClassName("carousel-slide-hidden");
    p_eElement.addClassName("carousel-slide-background");
    return p_eElement;
  }
});

