ContentCarousel = function(domElementNamespace, perWindow, transitionEffect) {
  if (domElementNamespace) {
    this.initialize(domElementNamespace, perWindow, transitionEffect);
  }
};

ContentCarousel.prototype = {
  initialize: function(domElementNamespace, perWindow, transitionEffect) {
    this._behaviourOptions = {
      allowPartiallyEmptyLastWindow: false,
      cyclicalWindowMovement: false,
      transitionEffectOnClick: true
    };

    this._transitionEffect = transitionEffect;
    this._domElementNamespace = domElementNamespace;      /* dom ids and classnames for elements needed by
                                                             this object should be preceded with this value */

    this._perWindow = perWindow;                          /* number of items visible at a time */
    this._computeWindowBoundries();                       /* find the css left values for each window */
    this._initEventListeners();                           /* setup click events on control elements */
    this._prepDomElements();                              /* set some styles to keep things sane */
  },

  next: function() {
    if(this._hasNext()) {
      this._setWindow(this._nextWindow(), this._isClickEvent(arguments[0]));
      this._updateControlStatus();
    }
  },

  previous: function() {
    if(this._hasPrevious()) {
      this._setWindow(this._previousWindow(), this._isClickEvent(arguments[0]));
      this._updateControlStatus();
    }
  },

  _setWindow: function(index, fromClick) {
    var leftValue = this._windowBoundries[index];
    if (leftValue != undefined) {
      if ((fromClick && !this._behaviourOptions.transitionEffectOnClick) || this._transitionEffect == undefined) {
        this._itemContainer().style.left = leftValue.toString() + 'px';
      }
      else if (this._transitionEffect != undefined) {
        this._transitionEffect(this, leftValue);
      }
    }
  },

  /* initializers */
  _computeWindowBoundries: function() {
    this._windowBoundries = new Array();

    var pages = Math.ceil(this._numItems() / this._perWindow);
    for(var i = 0; i < pages; i++) {
      this._windowBoundries.push(i * this._windowWidth() * -1);
    }

    /* take into account whether or not the last window should be partially empty or always full */
    if(!this._behaviourOptions.allowPartiallyEmptyLastWindow) {
      var windowBoundaries = this._windowBoundries;

      var emptySpots = this._perWindow - (this._numItems() % this._perWindow);
      var last = windowBoundaries[windowBoundaries.length - 1];

      if (emptySpots < this._perWindow) {
        windowBoundaries[windowBoundaries.length - 1] = (emptySpots * this._itemWidth() + last);
      }
    }
  },

  _initEventListeners: function() {
    disable = function(disabled) {
      var element = $(this);
      if (disabled) {
        // Prototype
        if (this.addClassName) {
          element.addClassName('disabled');
        // jQuery
        } else {
          element.addClass('disabled');
        }
      } else {
        // Prototype
        if (this.addClassName) {
          element.removeClassName('disabled');
        // jQuery
        } else {
          element.removeClass('disabled');
        }
      }
    };

    var self = this;
    self._nextControlElement().onclick = function(event) {
      self.next(event);
    };

    self._previousControlElement().onclick = function(event) {
      self.previous(event);
    };

    self._nextControlElement().disable = disable;
    self._previousControlElement().disable = disable;
    self._updateControlStatus();
  },

  _prepDomElements: function() {
    var itemContainer = this._itemContainer();
    itemContainer.style.left = 0;
    itemContainer.style.width = (this._itemWidth() * this._numItems()).toString() + 'px';

    if(!this._needControls()) {
      //alert( $( this._nextControlElement() ) );
      //$(this._nextControlElement()).hide();
      //$(this._previousControlElement()).hide();
      var infoElement = document.getElementById(this._elementName('info'));
      $(infoElement).hide();
    }
  },

  /* property accessors */
  _hasNext: function() {
    return this._behaviourOptions.cyclicalWindowMovement ||
           (this._currentWindow() < this._windowBoundries.length - 1);
  },

  _nextWindow: function() {
    if (!this._hasNext()) {
      return -1;
    }

    if (this._behaviourOptions.cyclicalWindowMovement &&
        this._currentWindow() == (this._windowBoundries.length - 1)) {
      return 0;
    }

    return this._currentWindow() + 1; // update to take cyclical into account
  },

  _hasPrevious: function() {
    return this._behaviourOptions.cyclicalWindowMovement || (this._currentWindow() > 0);
  },

  _previousWindow: function() {
    if (!this._hasPrevious()) {
      return 0;
    }

    if (this._behaviourOptions.cyclicalWindowMovement && this._currentWindow() === 0) {
      return this._windowBoundries.length - 1;
    }

    return this._currentWindow() - 1; // update to take cyclical into account
  },

  _currentWindow: function() {
    var left = parseInt(this._itemContainer().style.left, 10);
    var curIndex = this._windowBoundries.indexOf(left);

    return (curIndex == -1) ? 0 : curIndex;
  },

  _windowWidth: function(){
    return this._itemWidth() * this._perWindow;
  },

  _lastWindowFull: function() {
    return (this._items.length % this._perWindow) === 0;
  },

  _itemWidth: function() {
    return this._lazyLoad('__itemWidth', function() {
      if (!(this._numItems() === 0)) { 
        var first = $(this._items()[0]);

        // For Prototype
        if (first.getWidth) {
          return first.getWidth();
        // For jQuery
        } else {
          return first.width();
        }
      }

      return -1;
    });
  },

  _nextControlElement: function() {
    return this._lazyLoad('__nextControlElement', function() {
      return document.getElementById(this._elementName('next'));
    });
  },

  _previousControlElement: function() {
    return this._lazyLoad('__previousControlElement', function() {
      return document.getElementById(this._elementName('previous'));
    });
  },

  _itemContainer: function() {
    return this._lazyLoad('__itemContainer', function() {
      return document.getElementById(this._elementName('container'));
    });
  },

  _items: function(windowIndex) {
    return this._lazyLoad('__items', function() {
      return this._itemContainer().children;
    });

  },

  _numItems: function() {
    return this._items().length;
  },

  /* helpers */
  _elementName: function(el) {
    return new Array(this._domElementNamespace, el).join('-');
  },

  _lazyLoad: function(property, valueFunction) {
    if (this[property] == undefined) {
      this[property] = valueFunction.apply(this);
    }

    return this[property];
  },

  _isClickEvent: function(e) {
    /* IE doesn't seem to like to to respond correctly to isLeftClick */
    return e != undefined && (e.button === 0);
  },

  _needControls: function() {
    return this._numItems() > this._perWindow;
  },

  _updateControlStatus: function() {
    this._nextControlElement().disable(!this._hasNext());
    this._previousControlElement().disable(!this._hasPrevious());
  }
};


