TransitionManager = Class.create({
  observable: {},

  initialize: function(observable) {
    this.observable = observable;

    // setup the observers for any anchors or forms that were provided
    this.observeAnchorsFor(observable['anchors']);
    this.observeFormsFor(observable['forms']);

    // observe the transition events that can be fired from anchors/forms and possibly flash
    Event.observe(document, 'interface:transition', this.transition.bind(this));
    Event.observe(document, 'flash:buttonClick', this.transition.bind(this));
  },

  observeAnchorsFor: function(elements) {
    if (typeof(elements) == 'string') elements = [elements];

    this._host = TransitionManager.getUrlParts(window.location.href).host;
    elements.each(function(element) {
      var containerElement = $(element);
      if (!containerElement) return;
      containerElement.select('a').each(function(anchor) {
        var host = TransitionManager.getUrlParts(anchor.href).host;
        if (anchor.href && host && host != this._host) return;
        if (anchor.hasClassName('ignore')) return;

        anchor.observe('click', function(event) {
          event.stop();
          var transitionType = (anchor.rel && anchor.rel.substring(0, 'transition'.length) == 'transition') ? anchor.rel : false;
          if (document._transitioning) {
            anchor.blur();
          } else {
            Event.fire(document, 'interface:transition', {containerElement: containerElement, url: anchor.href, transitionType: transitionType});
          }
        }.bind(this));
      }.bind(this));
    }.bind(this));
  },

  observeFormsFor: function(elements) {
    if (typeof(elements) == 'string') elements = [elements];

    elements.each(function(element) {
      var containerElement = $(element);
      if (!containerElement) return;
      containerElement.select('form').each(function(form) {
        if (form.hasClassName('ignore')) return;
        form.observe('submit', function(event) {
          event.stop();
          if (!document._transitioning) {
            Event.fire(document, 'interface:transition', {containerElement: containerElement, url: form.action, method: form.method, params: form.serialize(true)});
          }
        }.bind(this));
      }.bind(this));
    });
  },

  transition: function(event) {
    trace('transition', event.memo);
    if (event.memo['url']) window.location.href = event.memo.url;
    event.stop();
  }
});

Object.extend(TransitionManager, {
  getUrlParts: function(uri) {
    var parts = uri.match(/^((http[s]?|ftp):\/\/)?(((.+)@)?([^:\/\?#\s]+)(:(\d+))?)?(\/?[^\?#]+)?(\?([^#]+))?(#(.*))?$/i);
    parts = {scheme: parts[2], credentials: parts[5], host: parts[6], port: parts[8], path: parts[9], query: parts[11], hash: parts[13]};
    var out = {};
    out.uri = uri;
    out.scheme = (parts.scheme === undefined) ? '' : parts.scheme;
    out.host = (parts.host === undefined) ? '' : parts.host;
    out.port = (parts.port === undefined) ? 80 : parts.port;
    out.credentials = (parts.credentials === undefined) ? false : parts.credentials.split(':');
    out.path = (parts.path === undefined) ? '' : (parts.path == '') ? '/' : parts.path;
    out.query = (parts.query === undefined) ? '' : parts.query;
    out.hash = (parts.hash === undefined) ? '' : parts.hash;
    out.args = {};
    out.query.replace(/([^&=]*)=([^&=]*)/g, function (m, attr, value) {
      if (out.args[attr] === undefined) {
        out.args[attr] = value;
      } else {
        if (typeof(out.args[attr]) != 'object') out.args[attr] = [out.args[attr]];
        out.args[attr].push(value);
      }
    });
    return out;
  },

  makeUrlForHash: function(newUrl, currentUrl) {
    var pos = currentUrl.indexOf('#');
    if (pos >= 0) currentUrl = currentUrl.substr(0, pos);

    var newParts = TransitionManager.getUrlParts(newUrl);
    return currentUrl + '#' + (newParts.path ? newParts.path : '') + (newParts.query ? '?' + newParts.query : '');
  }
});

// add handling for the back/forward button
window.currentLocation = window.location.href;
window.intervalTest = setInterval(function() {
  if (window.currentLocation != window.location.href) {
    var urlParts = TransitionManager.getUrlParts(window.location.href);
    Event.fire(document, 'interface:transition', {containerElement: '', url: urlParts.hash ? urlParts.hash : urlParts.path});
  }
}, 5);

// add handling for the refresh button
var urlParts = TransitionManager.getUrlParts(window.location.href);
if (urlParts.hash) {
  Event.observe(document, 'dom:loaded', function() {
    if (document.body) document.body.setStyle('visibility:hidden');
  });
  window.location.href = urlParts.hash
}
