function toHandle(string) {
  var result = string.toLowerCase();
  
  result = result.gsub(/[\'\"\(\)\[\]]/, '');
  result = result.gsub(/\W/, ' ');
  result = result.gsub(/\ +/, '-');
  result = result.gsub(/\ +/, '-');
  result = result.gsub(/(-+)$/, '');
  result = result.gsub(/^(-+)/, '');
  
  return result;
}

var ApiClientForm = Class.create();
ApiClientForm.prototype = {
  
  initialize: function(){
    this.select = $('api_client_kind');
    this.callbackRow = $('callback-url-row');
    this.callbackField = $('callback-url-field');
    
    Event.observe(this.select, 'change', this.onSelectChange.bindAsEventListener(this));

    if (this.select.value != '' && this.select.value != 'other') {
      this.callbackRow.show();
    }
  },
  
  onSelectChange: function(e) {
    element = e.element();

    if (element.value == 'auto_redirect') {
      if (this.callbackField.value == '') {
        this.callbackField.value = 'http://';
      }

      this.callbackRow.show();
      this.callbackField.focus();
    }
    else if (element.value == 'show_button') {
      if (this.callbackField.value == '') {
        this.callbackField.value = 'myprotocolhandler://';
      }

      this.callbackRow.show();
      this.callbackField.focus();
    }
    else if (element.value == 'other') {
      this.callbackRow.hide();
    }
  },
};

var ApiLinkForm = Class.create();
ApiLinkForm.prototype = {
  
  initialize: function(id){    
    this.select = $('page-select-' + id);
    this.link_details = this.select.up('table').select('.link-details');
    
    Event.observe(this.select, 'change', this.onSelectChange.bindAsEventListener(this));

    var timestamp = new Date().getTime();
    this.select.id = this.select.id.replace(/NEW_RECORD/g, timestamp);
    this.select.name = this.select.name.replace(/NEW_RECORD/g, timestamp);
    
    if (this.select.value != 'nil: nil') {
      this.show_details();
    }
  },
  
  show_details: function() {
    this.link_details.each(function(el){
      el.show();
    });
  },
  
  onSelectChange: function(e) {
    this.show_details();

    this.link_details.first().down('input').focus();
  },
};

var ApiLinkIcon = {
  current: null,
  placeholder: null,
  
  setIcon: function(path) {
    var url = '/images/' + path;
    ApiLinkIcon.current.down('.icon').setAttribute('src', url);
    ApiLinkIcon.current.down('.icon').show();
    ApiLinkIcon.current.down('.icon').adjacent('a').first().update('Choose a different icon');
    ApiLinkIcon.current.down('input').setAttribute('value', url);
  }
}


/*-------------------- Messenger Functions ------------------------------*/
// Messenger is used to manage error messages and notices
//
var Messenger = {
  autohide_error: null,
  autohide_notice: null,
  // When given an error message, wrap it in a list 
  // and show it on the screen.  This message will auto-hide 
  // after a specified amount of miliseconds
  error: function(message) {
    $('flasherrors').innerHTML = "<li>" + message + "</li>";
    new Effect.Appear('flasherrors', {duration: 0.3});
    
    if (this.autohide_error != null) {clearTimeout(this.autohide_error);}
    this.autohide_error = setTimeout(Messenger.fadeError.bind(this), 5000);
  },

  // Notice-level messages.  See Messenger.error for full details.
  notice: function(message) {
    $('flashnotice').innerHTML = "<li>" + message + "</li>";
    new Effect.Appear('flashnotice', {duration: 0.3});

    if (this.autohide_notice != null) {clearTimeout(this.autohide_notice);}
    this.autohide_notice = setTimeout(Messenger.fadeNotice.bind(this), 5000);
  },
  
  // Responsible for fading notices level messages in the dom    
  fadeNotice: function() {
    new Effect.Fade('flashnotice', {duration: 0.3});
    this.autohide_notice = null;
  },
  
  // Responsible for fading error messages in the DOM
  fadeError: function() {
    new Effect.Fade('flasherrors', {duration: 0.3});
    this.autohide_error = null;
  }
};

var DevelopmentShopCreator = Class.create()
DevelopmentShopCreator.prototype = {
  
  initialize: function(dev_shop_url, refresh_url, job_id) {
    this.development_shop_url = dev_shop_url;
    this.refresh_development_shop_listing_url = refresh_url;
    this.job_id = job_id;
    this.build_status_timer = null;
    this.build_status = null;
    
    if(this.job_id == null) {
      this.create();
    } else {
      this.check_build_status();
    }
  },

  create: function() {
    var self = this;
    
    new Ajax.Request(self.development_shop_url, {
      method: 'post',
      onSuccess: function(transport) {
        self.job_id = transport.responseText;
        setTimeout(self.check_build_status.bind(self), 3000);
      }
    });
  },

  check_build_status: function() {
    if(this.finished_building()) {
      this.refresh_development_shop_listing();
    } else {
      build_status_timer = setTimeout(this.check_build_status.bind(this), 3000);
    }
  },
  
  finished_building: function() {
    var self = this;
    var check_url = this.development_shop_url + '/' + this.job_id;
    
    new Ajax.Request(check_url, {
      method: 'get',
      on202: function(transport) {
        self.build_status = false;
      },
      on404: function(transport) {
        self.build_status = true;
      }
    });
    return self.build_status;
  },
  
  refresh_development_shop_listing: function() {
    new Ajax.Request(this.refresh_development_shop_listing_url, {
      method: 'get',
      onSuccess: function(transport) {}
    });
  }
}