if (!Fair && top.Fair){
  top.Fair.Content = window;
  var Fair = top.Fair;
} else if (!Fair) Fair = {};
var Local = {};

//Common Scripts for all content pages
Fair.Common = {};

//Link behaviors by type
Fair.Common.Links = {
  
  download: function(link){
    var action = link.hasClass('external') ?
      function(event){ Fair.Common.Overlay.show('external', link.href, 'track'); event.stop(); } :
      function(event){
        if (link.hasClass('downloaded')){ event.stop(); return; }
        link.addClass('downloaded').set('text', 'downloaded');
        Fair.Roar.alert('Your track is being downloaded...');
      };
    link.addEvent('click', action);
  },
  
  permalink: function(link){
    var input = link.getParent().getNext().getFirst().addEvents({
      blur: function(){ this.slide('out'); },
      click: function(){ this.select(); },
      mousedown: function(){ this.select(); }
    }).set('slide', { 'mode': 'horizontal', duration: 300 }).slide('hide');
    link.addEvent('click', function(event){
      input.select();
      input.slide();
      event.stop();
    });
  },
  
  play: function(link){
    var type = link.className.split(' ')[0];
    link.addEvent('click', function(event){
      event.stop();
      var feed = link.get('href'), empty = feed == '#',
          id = type == 'track' ? this.id.parseId() : 0;
      if (link.hasClass('pause')) Fair.Player.fairpause();
      else {
        link.className = 'loading button';
        if (!Fair.Session && empty) feed = '/track/' + id + '.xspf';
        Fair.Player.fairplay(id, empty ? Fair.Params.feed : feed);
      }
    });
  },
  
  show: function(link){
    var persist = link.hasClass('persistent'),
        description = link.getParent().getNext(),
        slide = description.get('slide', { transition: 'quad:out' }).hide();
    
    if (!persist){
      var snippet = description.getElement('div.content');
      snippet = (snippet ? snippet.getElement('p').clone() : new Element('p')).inject(link, 'after');
    }
    
    link.getParent().addEvent('click', function(event){
      var target = $(event.target);
      if (target.get('tag') == 'a' && target != link) return;
      var visible = slide.open;
      link[visible ? 'removeClass' : 'addClass']('active');
      if (snippet) snippet.fade(visible ? 'in' : 'out');
      slide.start(visible ? 'out' : 'in');
      event.stop();
    });
  },
  
  vote: function(link, model){
    var id = link.id.parseId().toInt(),
        owned = Fair.Session[model + 's'];
    
    if (owned && owned.contains(id)){ this.cantvote(link, model); return; }
    link.addEvent('click', function(event){
      event.stop();
      Fair.Common.Votes.vote(model, id);
    });
  },
  
  cantvote: function(link, model){
    link.addEvent('click', function(event){ event.stop(); }).set({
      'class': model + ' cantvote button',
      'title': "You can't vote for your own " + model + "!"
    });
  }
  
};

//restricted actions
['cantadd', 'cantplay', 'cantshare'].each(function(key){
  Fair.Common.Links[key] = function(link){
    link.addEvent('click', function(event){
      event.stop();
    });
  };
});

//overlay actions
['abuse', 'add', 'feedback', 'groups', 'inbox', 'invite', 'overlay', 'password', 'reassign', 'reject', 'share', 'stats'].each(function(key){
  var Key = key.capitalize();
  Fair.Common.Links[key] = function(link, model){
    if (!link) return;
    link.addEvent('click', function(event){
      event.stop();
      Fair.Common.Overlay.show(key, link.href, model);
    });
  };
});

//show edit buttons and admin links in lists
Fair.Common.Admin = {
  
  sync: function(model){
    var owned = Fair.Session[model + 's'],
        admin = Fair.Session.level == 'admin';
    
    if (!owned || !owned.length) return;
    $$('table.track').each(function(item){
      if (admin || owned.contains(item.id.parseId().toInt())){
        var links = $(item.id + '_admin_links');
        if (links) links.show();
      }
    });
  },
  
  update: function(){
    var inbox = $('inbox_count'),
        inbox_count = Fair.Session.inbox_count;
        
    if (inbox){
      if (inbox_count) inbox.set('html', '(' + inbox_count + ')').show();
      else if (inbox_count == 0) inbox.hide(true).set('html', '(0)');
    }
  }
  
};

//Actions for Inviting
Fair.Common.Invite = {
  
  send: function(emails, message){
    var params = { emails: emails };
    if (message) params['message'] = message;
    this.Request.post(params);
  }
  
};

//Show any type of overlay
Fair.Common.Overlay = {
  
  show: function(type){
    if (type == 'overlay') this[type] = new Overlay({ destroy: true, jumpToTop: true });
    if (!this[type]) this[type] = new Overlay[type.capitalize()]();
    this[type].overlay.apply(this[type], Array.slice(arguments, 1));
  }
  
};

//Play behavior for syncronizing all feed and track play buttons
Fair.Common.Plays = {
  
  sync: function(feed_url, track_id, playing){
    var player = Fair.Player;
    if (!player.current_feed) return;
    if (!feed_url) feed_url = player.current_feed();
    if (!track_id) track_id = player.current_track_id();
    if (!playing)  playing  = player.fairplaying();
    
    ['track', 'playlist', 'user', 'radio'].each(function(model){
      var module = Fair[model.capitalize() + 's'];
      if (!module || !module.playButtons) return;
      var text = (model == 'user' ? "member's music" : model);
      module.playButtons.set({'class': model + " play button", 'title': 'Play this ' + text});
    });
    
    var string = feed_url && feed_url.match;
    var radio = string && feed_url.match('button_id');
    var model = string && feed_url.match('playlist|user|radio');
    
    if (model){
      model = model[0];
      var module = Fair[model.capitalize() + 's'],
          text = (model == 'user' ? "member's music" : model),
          button = radio ? $(feed_url.match(/button_id=(radio_\w+)/)[1]) : $(model + '_play_button_' + feed_url.parseId());
      if (button){
        if (playing) button.set({'class': model + ' pause button', 'title': 'Pause this ' + text});
        else button.set({'class': model + ' paused button'});
      }
    }
    
    if (track_id){
      button = $$('[id=track_play_button_' + track_id + ']');
      if (button){
        if (playing) button.set({'class': 'track pause button', 'title': 'Pause this track'});
        else button.set({'class': 'track paused button'});
      }
    }
  }
  
};

//A common image uploader
Fair.Common.Uploader = {
  
  init: function(model, id){
    var image = $('main_picture');
    if (!image) return;
    
    var uploader, that = this,
        adjust = $('picture_adjust_button'),
        browse = $('picture_browse_button'),
        message = 'There was a problem uploading the image',
        reset = function(){ image.fade('in'); Fair.Roar.alert(message); };
    
    image.addEvent('load', function(){
      var field = image.getParent();
      if (field.hasClass('fieldWithErrors')){ field.getFirst().inject(field, 'before'); field.destroy(); }
      adjust.show();
      image.fade('in');
    });

    if (browse) browse.addEvent('click', $lambda(false));
    if (adjust) adjust.addEvent('click', function(event){
      event.stop();
      var href = '/pictures/cropper?record_id=' + id + '&record_type=' + model.capitalize();
      Fair.Common.Overlay.show('cropper', href);
    });
    
    var container = new Element('div').setStyles({
      width: '100%',
      height: '14px',
      overflow: 'hidden',
      position: 'relative'
    }).replaces(browse);

    uploader = new Swiff.Uploader({
      data: Fair.Session ? {_session_id: Fair.Session.session_id} : {email: $('user_email').value},
      method: 'POST',
      multiple: false,
      fieldName: 'picture',
      container: container,
      path: '/flash/Swiff.Uploader.swf',
      url: '/' + model + 's/picture/' + id + '?format=json',
      typeFilter: {'Images (*.jpg, *.jpeg, *.gif, *.png)': '*.jpg; *.jpeg; *.gif; *.png'},
      callBacks: {
        onError: reset,
        onAllSelect: function(){ image.fade(0.2); uploader.upload(); },
        onComplete: function(file, response){
          var json = $H(JSON.decode(response, true)), source = json.src + '?' + $time();
          if (json.get('result') != 'success') reset();
          else image.removeClass('default').get('tween').start('opacity', 0).chain(function(){ image.src = source; });
          var cropper = $('image_cropper');
          if (cropper) cropper.destroy();
          that.sync(model, id, source);
        }
      }
    });
    
    container.adopt(browse);
  },
  
  sync: function(model, id, source){
    if (model == 'user' && Fair.Session && Fair.Session.id == id) $('user_avatar').src = source;
  }

};

Fair.Common.Create = {
  
  countryAutocompleter: function(field){
    new Autocompleter.Local(field, Fair.Countries, {
      minLength: 1,
      className: 'country menu',
      filter: function(){
        var query = this.queryValue,
            escaped = query.escapeRegExp(),
            regex = new RegExp('^' + escaped, 'i'),
            regex2 = new RegExp('^' + escaped + '| ' + escaped, 'i'),
            iso = this.tokens.filter(function(token){ return query.length == 2 && regex.test(token[1]); }),
            name = this.tokens.filter(function(token){ return !iso.contains(token) && regex2.test(token[0]); });
        return iso.concat(name);
      },
      injectChoice: function(choice){
        var code = new Element('span', {'class': 'code'}).set('html', this.markQueryValue(choice[1]));
        var el = new Element('li').set('html', this.markQueryValue(choice[0])).setStyle('background-image', 'url(/images/flags/' + choice[1].toLowerCase() + '.gif)');
        code.inject(el, 'top');
        el.inputValue = choice[0];
        this.addChoiceEvents(el).inject(this.choices);
      }
    });
  },
  
  namedAutocompleter: function(controller, model){
    var input = $(controller + '_' + model + '_name'), url = '/autocomplete?model=' + model;
    if (!input) return;
    new Autocompleter.Request.HTML(input, url, {
      delay: 100,
      postVar: 'value',
      onRequest: function(){ input.addClass('loading'); },
      onFailure: function(){ input.removeClass('loading'); },
      onComplete: function(){ input.removeClass('loading'); }
    });
  }

};

//Default Voting behavior
Fair.Common.Votes = {
  
  sync: function(model){
    Fair[model.capitalize() + 's'].voteButtons.set({'class': model + ' vote button', 'title': 'Vote for this ' + model});
    Fair.Session[model + '_votes'].each(function(id){
      var button = $(model + '_vote_button_' + id);
      if (button) button.set({'class': model + ' fanof button', 'title': 'Withdraw your vote'});
    });
  },
  
  vote: function(model, id){
    if (!id) return;
    else if (!Fair.Session){ alert('Login to vote!'); return; }
    else if (!this.Requests[model][id]) this.Requests[model][id] = new Request.JSON({
      link: 'cancel',
      onSuccess: this.respond.bind(this)
    });
    this.request(model, id, !Fair.Session[model + '_votes'].contains(id.toInt()));
  },
  
  request: function(model, id, state){
    var url = (model == 'track' ? '' : model + '_') + 'votes', timeframe = '';
    this.update(model, id, state, '<img src="/images/spinner.gif" alt="loading" />');

    var vote_button = $(model + '_vote_button_' + id);
    if (vote_button) timeframe = '?' + vote_button.href.split('?')[1];
    
    this.Requests[model][id].post('/' + url + '/' + (state ? 'create' : 'destroy') + '/' + id + timeframe);
  },
  
  respond: function(response){
    this.update(response.model, response.id, response.state, response.count);
  },
  
  update: function(model, id, state, count){
    Fair.Session[model+'_votes'][state ? 'include' : 'erase'](id.toInt());
    var vote_count = $(model + "_vote_count_" + id), vote_button = $(model + "_vote_button_" + id);
    if (vote_count) vote_count.set('html', count);
    if (vote_button) vote_button.set({
      'class': (model + ' ' + (state ? 'fanof' : 'vote') + ' button'),
      'title': (state ? 'Withdraw your vote' : 'Vote for this ' + model)
    });
    // Update vote info on player V2 (V3 is backward-compatible)
    if (model == 'track' && id == Fair.Player.current_track_id()) Fair.Player['switch_to_' + (state ? 'unvote' : 'vote')]();
    // Update vote info on player V3, enabled now that V2 is forward-compatible
    Fair.Player[model + (state ? '_voted' : '_unvoted')](id);
  }
  
};

//Common Initialization
Fair.Common.init = function(){
  if (window.Roar) Fair.Roar = new Roar({ container: $('container') });
  Fair.Scroller = new Fx.Scroll(document.body, { offset: { y: -20 } });
  
  //radios don't have their own js module yet as the only place we have buttons for them is on the home page
  var buttons = $$('a.radio.play.button');
  buttons.each(function(button){ Fair.Common.Links.play(button); });
  Fair.Radios = { playButtons: buttons };
  
  this.Votes.Requests = { track: {}, playlist: {} };
  this.Invite.Request = new Request.JSON({ url: '/invites/create' });
  
  if (Fair.Messages){
    var input = $('search-text'), clear = false;
    if (input){
      if (Fair.Messages.controller == 'users') Fair.Messages.controller = 'community';
      if (!Fair.Messages.search){
        clear = true;
        Fair.Messages.search = 'Search in ' + Fair.Messages.controller;
      }
      else input.addClass('active');
      input.addEvents({
        blur: function(){ if (clear && this.value.clean() == '') this.value = Fair.Messages.search; },
        focus: function(){ if (clear && this.value == Fair.Messages.search) this.value = ''; }
      }).value = Fair.Messages.search;
      
      $('search-submit').addEvent('click', function(event){
        event.stop();
        if (!Fair.Session || input.value == Fair.Messages.search) return;
        this.getParent().submit();
      });
    }
    
    if (Fair.Roar && Fair.Messages.flash) Fair.Roar.alert(Fair.Messages.flash);
  }
  
  $$('div.tab-container').each(function(container){
    new TabContainer(container, {
      initialize: function(){
        this.tabs.each(function(tab, index){
          var feed = tab.get('href');
          if (!feed || !feed.match('.xspf')) return;
          if (Fair.Player && Fair.Player.preload_feed) Fair.Player.preload_feed(feed);
          this.panes[index].getElements('a.track.play.button').set('href', feed);
        }.bind(this));
      }
    });
  });
  
  $$('[feed]').each(function(container){
    container.getElements('a.track.play.button').set('href', container.get('feed'));
  });
  
  $$('div.features a.track.play.button', 'table.explore a.track.play.button').each(function(link){
    if (link.get('href') == '#') link.href = '/track/' + link.id.parseId() + '.xspf';
  });

  $$('a.download, a.feedback, a.inbox, a.overlay, a.password, a.permalink, a.show').each(function(link){
    this.Links[link.className.split(' ')[0]](link);
  }, this);
  
  if (Fair.Session && Fair.Fixed) this.Admin.update();
};

window.addEvents({
  domready: Fair.Common.init.bind(Fair.Common),
  load: function(){
    if (!Fair.Tracks || !Fair.Playlists) return;
    else if (Fair.Tracks.loaded && Fair.Playlists.loaded && Fair.Users.loaded){
      if (Fair.Player) Fair.Common.Plays.sync();
    } else arguments.callee.delay(50);
  }
});

function ShowFlashMessage(title, message){
  if (Fair.Roar) Fair.Roar.alert(title, message || '');
}

//magic
Request.JSON.implement({
  onSuccess: function(response){
    if (response){
      var message = response.alert || response.notice || response.flash,
          errors = response.errors;
      if (Fair.Roar && message) Fair.Roar.alert(message);
    }
    this.parent.apply(this, arguments);
  }
});
//Common Base Overlay Class
var Overlay = new Class({

  Implements: [Events, Options],

  options: {
    onHide: $empty,
    onShow: $empty,
    destroy: false,
    jumpToTop: false
  },

  initialize: function(options){
    this.setOptions(options);
    this.content = $('content');
    this.wrapper = $('overlay');
    this.container = $('overlays');
    this.show = this.toggle.bind(this, true);
    this.hide = this.toggle.bind(this, false);
    this.close = (function(event){
      if (event.key == 'esc') this.hide();
    }).bind(this);
  },

  getPanel: function(){
    return false;
  },

  getRequest: function(){
    return new Request({
      evalScripts: true,
      onSuccess: this.build.bind(this)
    });
  },

  toggle: function(state){
    if (this.previous){
      if (state){
        this.wrapper.getChildren().hide(true);
        this.content.mask();
        this.previous.show();
        if (this.options.jumpToTop) window.scrollTo(0, 0);
        this.container.removeClass('signin').setStyle('top', window.getScrollTop().max(80)).show();
        document.addEvent('keydown', this.close);
      } else {
        this.content.unmask();
        this.previous.hide(true);
        this.container.removeClass('signin').hide(true);
        document.removeEvent('keydown', this.close);
        if (this.options.destroy) this.previous.destroy();
      }
    }
    this.fireEvent((state ? 'onShow' : 'onHide'), this);
  },

  overlay: function(href){
    var panel = this.getPanel.apply(this, arguments);
    if (!this.request) this.request = this.getRequest();
    if (!panel) this.request.get(href);
    else {
      this.previous = panel;
      this.show();
    }
  },

  build: function(response){
    var panel = new Element('div').set('html', response).getFirst().hide(true).inject(this.wrapper);
    panel.getElements('a.close, a.cancel').each(function(link){
      link.addEvent('click', function(event){ this.hide(); event.stop(); }.bind(this));
    }, this);
    this.previous = panel;
    this.show();
  }

});

//Sign in / Join Overlay
Overlay.Signin = new Class({
  
  Extends: Overlay,
  
  options: {
    onShow: function(){ this.container.addClass('signin'); }
  },
  
  getPanel: function(){
    return $('signin-overlay');
  },
  
  overlay: function(link){
    if (!this.built) this.build();
    var panel = this.getPanel();
    this.previous = panel;
    this.show();
    $(link.get('text') == 'join' ? 'invite_email' : 'login').focus();
  },
  
  build: function(){
    var panel = this.getPanel();
    this.wrapper.adopt(panel);
    panel.getElements('a.close, a.cancel').each(function(link){
      link.addEvent('click', function(event){ this.hide(); event.stop(); }.bind(this));
    }, this);
    this.built = true;
  }
  
});

//Report Abuse Overlay
Overlay.Abuse = new Class({

  Extends: Overlay,

  getPanel: function(href, model){
    return $('report_' + model + '_' + href.parseId());
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        form = panel.getElement('form'),
        textarea = form.getElement('textarea'),
        label = form.getElement('label span strong');

    new MaxLength(textarea, {
      initialize: function(){ this.check(); },
      onChange: function(input, length){ label.set('text', (0).max(this.max - length)); }
    });

    var request = new Request.JSON({
      url: form.action,
      onComplete: function(){
        this.hide();
        form.reset();
        label.set('text', '500');
      }.bind(this)
    });

    form.addEvent('submit', function(event){
      request.post(form);
      event.stop();
    });
  }

});

//Add Track to Playlist Overlay
Overlay.Add = new Class({

  Extends: Overlay,

  getPanel: function(href){
    return $('add_track_' + href.parseId());
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        form = panel.getElement('form'),
        name = form.getElement('input'),
        list = panel.getElement('ul.playlists'),
        selectPlaylistBox = panel.getElement('#select-playlist'),
        noPlaylistsBox = panel.getElement('#no-playlists');
        playlistAdditionOrderBox = panel.getElement('#playlist-addition-order-div');

    panel.getElements('ul.playlists li').each(function(playlist){
      this.playlistInit(playlist);
    }, this);

    form.addEvent('submit', function(event){
      event.stop();
      name.value = name.value.trim();
      if (!name.value){ name.addClass('error'); return; }
      name.removeClass('error');
      new Request.HTML({
        url: '/playlist_tracks/',
        onSuccess: function(response){
          var newPlaylist = $(response[0]);
          list.adopt(newPlaylist);
          if (!selectPlaylistBox.visible()){
            selectPlaylistBox.show();
            playlistAdditionOrderBox.show();
            noPlaylistsBox.hide();
          }
          this.playlistInit(newPlaylist);
          form.reset();
          this.hide();
        }.bind(this)
      }).send(form);
    }.bind(this));
  },

  playlistInit: function(playlist){
    var button = playlist.getFirst();
    button.addEvent('click', function(event){
      var playlistId = playlist.id.parseId(),
          trackId = playlist.getParent().id.parseId(),
          queryParams = {
            playlist_id: playlistId,
            track_id: trackId
          };
          
          if (!button.hasClass('added')){
            var additionOrderSelect = $$('select.playlist-addition-order')[0],
            additionOrder = additionOrderSelect.options[additionOrderSelect.selectedIndex].value;
            
            queryParams['addition_order'] = additionOrder;
          }
          
      new Request.HTML({
        url: '/playlist_tracks/' + (button.hasClass('added') ? 'destroy' : 'create'),
        onSuccess: function(response){
          var newPlaylist = $(response[0]);
          newPlaylist.replaces(playlist);
          this.playlistInit(newPlaylist);
          newPlaylist.set('tween', { onComplete: this.hide }).highlight();
        }.bind(this)
      }).post(queryParams);
      new Element('a', {'href': '#', 'class': 'loading button'}).replaces(button);
      event.stop();
    }.bind(this));
  }

});

//Picture Cropper Overlay
Overlay.Cropper = new Class({

  Extends: Overlay,

  getPanel: function(){
    return $('image_cropper');
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        container = $('cropper'),
        image = container.getFirst(),
        form = panel.getElement('form'),
        source = image.src + '?' + $time();

    image.destroy();
    image = $('main_picture').addEvent('load', function(){ this.fade('in'); });

    var cropper = new Cropper(container, source);
    var request = new Request.JSON({
      onSuccess: function(){
        this.hide();
        image.get('tween', { property: 'opacity' }).start(0).chain(function(){
          var source = image.src + '?' + $time();
          Fair.Common.Uploader.sync(source);
          image.src = source;
        });
      }.bind(this)
    });

    form.addEvent('submit', function(event){
      request.post(form.action, cropper.serialize());
      event.stop();
    });
  }

});

//External Download Panel
Overlay.External = new Class({

  Extends: Overlay,

  getPanel: function(href, model){
    return $(model + '_' + href.parseId() + '_download');
  }

});

//Site Feedback Overlay
Overlay.Feedback = new Class({

  Extends: Overlay,

  getPanel: function(){
    return $('user_feedback');
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        form = panel.getElement('form'),
        textarea = form.getElement('textarea'),
        label = form.getElement('label span strong');

    new MaxLength(textarea, {
      initialize: function(){ this.check(); },
      onChange: function(input, length){ label.set('text', (0).max(this.max - length)); }
    });

    var request = new Request.JSON({
      url: form.action,
      onComplete: function(){
        this.hide();
        form.reset();
        label.set('text', '500');
      }.bind(this)
    });

    form.addEvent('submit', function(event){
      request.post(form);
      event.stop();
    });

    $('bug_report_page').value = document.location.href.replace(/(\?|&)no_frameset=true/, '');
    
    var browser,
        version = Browser.Engine.version,
        platform = Browser.Platform.name.capitalize(),
        flash = Browser.Plugins.Flash;
    
    switch(Browser.Engine.name){
      case 'gecko':   browser = 'Firefox ' + (version == 18 ? 2 : 3); break;
      case 'trident': browser = 'IE '      + (version == 4 ? 6 : 7); break;
      case 'webkit':  browser = 'Safari '  + (version == 419 ? 2 : 3); break;
      case 'presto':  browser = 'Opera'; break;
      default: browser = 'Unknown';
    }
    
    $('bug_report_config').value = "Browser : " + browser + ', Platform : ' + platform.capitalize() + ', Flash : version ' + flash.version + ' build ' + flash.build;
  }

});

//Private Groups Panel
Overlay.Groups = new Class({

  Extends: Overlay,

  initialize: function(options){
    this.parent(options);
    this.addEvent('onHide', function(){
      var groups = $('track_private_groups');
      if (groups) this.updateGroups(groups);
    }.bind(this));
  },

  getPanel: function(){
    return $('private_groups_panel');
  },
  
  build: function(response){
    this.parent(response);
    var panel = this.previous;
        
    this.current = false;
    this.groups = $('user_groups');
    this.friends = $$('#group_friends li a');
    this.nameInput = $('group_name');
    this.saveButton = $('group_save');
    this.selectables = new Selectables(this.friends);
    
    $$('#user_groups li').each(this.setup.bind(this));
    $('create_group_link').addEvent('click', this.create.bind(this));
    this.saveButton.addEvent('click', this.save.bind(this));
    
    this.request = new Request.HTML({
      url: '/private_groups',
      onSuccess: this.update.bind(this)
    });
  },
  
  setup: function(item){
    var remove = item.getFirst(),
        link = remove.getNext(),
        name = link.get('text'),
        id = item.id.parseId();
    
    link.addEvent('click', this.load.bindWithEvent(this, [item, name, id]));
    remove.addEvent('click', this.remove.bindWithEvent(this, [item, name, id]));
  },
  
  create: function(event){
    event.stop();
    this.selectables.deselectAll();
    this.current = false;
    this.nameInput.value = 'My New Group';
    this.nameInput.focus();
    this.nameInput.select();
    this.saveButton.value = 'Create Group';
  },
  
  remove: function(event, item, name, id){
    event.stop();
    if (!confirm("Are you sure you want to remove '" + name + "'?")) return;
    new Request().post('/private_groups/destroy/' + id);
    item.destroy();
  },
  
  load: function(event, item, name, id){
    event.stop();
    this.current = item;
    this.selectables.deselectAll();
    this.nameInput.value = name;
    this.saveButton.value = 'Save Group';
    var selected = Fair.Groups[id];
    this.selectables.selectAll(this.friends.filter(function(link){
      return selected.contains(link.id.parseId().toInt());
    }));
  },
  
  save: function(){
    this.selected = this.selectables.serialize(function(friend){
      return friend.id.parseId().toInt();
    });
    var url = '/private_groups/' + (this.current ? 'update/' + this.current.id.parseId() : 'create');
    var data = {
      'format': 'js',
      'private_group[name]': this.nameInput.value,
      'private_group[user_ids]': this.selected.join(',')
    };
    this.request.post(url, data);
  },
  
  update: function(response){
    var newGroup = $(response[0]), id = newGroup.id.parseId();
    Fair.Groups[id] = this.selected;
    this.current ? newGroup.replaces(this.current) : this.groups.adopt(newGroup);
    this.current = newGroup;
    this.setup(newGroup);
  },
  
  updateGroups: function(list){
    var groups = this.groups.getChildren().map(function(group){
      var link = new Element('a', {
        id: 'private_group_' + group.id.parseId(),
        text: group.getFirst().getNext().get('text')
      });
      return new Element('li').adopt(link);
    });
    list.empty().adopt(groups);
    $('track_private_groups_string').value = '';
    Local.TrackEdit.Create.privateGroups();
  }
  
});

//News Feed Overlay
Overlay.Inbox = new Class({

  Extends: Overlay,

  options: {
    destroy: true
  },

  initialize: function(options){
    this.parent(options);
    this.addEvent('onHide', function(){
      var inbox = $('inbox_count');
      if (inbox) inbox.hide(true).set('html', '(0)');
    }.bind(this));
  },

  getPanel: function(){
    return $('inbox_overlay');
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        request = new Request.JSON({ onSuccess: this.updateCounts });

    panel.getElements('td a').each(function(link){
      var href = link.get('href');
      if (link.hasClass('delete')){
        link.addEvent('click', function(event){
          event.stop();
          if (!confirm('Are you sure you want to remove this news item?')) return;
          this.getParent('table').destroy();
          request.DELETE(this.href);
        });
      } else if (document.location.href.indexOf(href.split('?')[0]) != -1){
        link.addEvent('mousedown', function(event){
          this.hide();
          if (href.indexOf('#') == -1) event.stop();
        }.bind(this));
      }
    });

    this.buildCategories(panel);
  },

  buildCategories: function(panel){
    var categories = panel.getElements('ul.categories li a'),
        events = panel.getElements('table');

    new Selectables(categories, {
      min: 1, max: 1,
      selected: [categories[0]],
      onChange: function(selected, link){
        if (!this.selected.length) return;
        var category = link.className.replace('_category selected', '');
        events.each(function(event){
          if (category == 'All' || event.className.match(category)) event.show();
          else event.hide(true);
        });
      }
    });
  },

  updateCounts: function(response){
    if (!response) return;
    Hash.each(response, function(value, key){
      $(key + '_category_count').set('html', value.toInt());
    });
  }

});

//Invite Overlay
Overlay.Invite = new Class({

  Extends: Overlay,

  options: {
    destroy: true
  },

  getPanel: function(){
    return $('user_invites');
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        request = new Request.JSON(),
        invitesForm = panel.getElement('form.invites');

    new TabContainer(panel);
    panel.getElements('a.resend').addEvent('click', function(event){
      event.stop();
      request.post(this.href);
    });
    panel.getElements('a.delete').addEvent('click', function(event){
      event.stop();
      if (!confirm('Are you sure you want to remove this invite?')) return;
      this.getParent('tr').destroy();
      request.DELETE(this.href);
    });

    if (!invitesForm) return;
    this.buildInvites(panel, invitesForm);
  },

  buildInvites: function(panel, form){
    form.addEvent('submit', function(event){
      var input = form.getElement('input.emails'),
          message = form.getElement('textarea.message'), 
          invites = [];
      if (!input) return;
      form.getElements('input.email').each(function(email){
        email.value = email.value.clean();
        if (email && email.value) invites.push(email.value);
      });
      var emails = input.value = invites.join(',');
      if (invites.length) Fair.Common.Invite.send(emails, message.value);
      this.hide();
      event.stop();
    }.bind(this));
  }

});

//Forgot Password Overlay
Overlay.Password = new Class({

  Extends: Overlay,

  getPanel: function(){
    return $('forgot_password');
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        form = panel.getElement('form'),
        email = $('forgot_password_email');

    var request = new Request.JSON({
      url: form.action,
      onComplete: function(){
        this.hide();
        form.reset();
      }.bind(this)
    });

    form.addEvent('submit', function(event){
      if (!email.value || !email.value.test('@')) email.addClass('error');
      else { email.removeClass('error'); request.post(form); }
      event.stop();
    });

    email.focus();
  }

});

//Reassign Track Overlay
Overlay.Reassign = new Class({

  Extends: Overlay,

  getPanel: function(href){
    var model = href.match(/(\w+)_ownership_changes/)[1];
    return $('reassign_' + model + '_' + href.parseId());
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        form = panel.getElement('form'),
        input = panel.getElement('input[type=text]'),
        url = '/autocomplete?model=user';
    
    if (!input) return;
    new Autocompleter.Request.HTML(input, url, {
      delay: 100,
      postVar: 'value',
      onRequest: function(){ input.addClass('loading'); },
      onFailure: function(){ input.removeClass('loading'); },
      onComplete: function(){ input.removeClass('loading'); }
    });
    
    var request = new Request.JSON({
      url: form.action,
      onComplete: function(){
        this.hide();
        form.reset();
      }.bind(this)
    });
    
    form.addEvent('submit', function(event){
      request.post(form);
      event.stop();
    });
  }

});

//Reject Track Overlay
Overlay.Reject = new Class({

  Extends: Overlay,

  getPanel: function(href){
    return $('reject_track_' + href.parseId());
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        form = panel.getElement('form'),
        textarea = form.getElement('textarea'),
        label = form.getElement('label span strong');
    
    new MaxLength(textarea, {
      initialize: function(){ this.check(); },
      onChange: function(input, length){ label.set('text', (0).max(this.max - length)); }
    });
  }

});

//Sharing Panel Overlay
Overlay.Share = new Class({

  Extends: Overlay,

  initialize: function(options){
    this.parent(options);
    this.addEvent('onShow', function(){
      if (!this.tabs) return;
      this.tabs.fireEvent('onSwap', this.tabs.tabs[this.tabs.active]);
      if (this.buildEmbedCode) this.buildEmbedCode();
    }.bind(this));
    this.addEvent('onHide', function(){
      var preview = $(this.previous.id + '_embed_preview');
      if (!preview) return;
      var player = preview.getFirst();
      if (player) player.destroy();
      preview.set('html', '');
    }.bind(this));
  },

  getPanel: function(href, model){
    return $('share_' + model + '_' + href.parseId());
  },

  build: function(response){
    this.parent(response);
    var panel = this.previous,
        preview = $(panel.id + '_embed_preview'),
        emailForm = panel.getElement('form.message.email'),
        friendForm = panel.getElement('form.message.friends'),
        self = this;

    var check = function(tab){
      if (!Browser.Engine.gecko || document.getElementsByClassName) return;
      self.content.mask(true, ((/embed/i).test(tab.get('text')) ? 1 : 0.8));
    };

    if (!panel.getElement('ul.tabs')) return;
    this.tabs = new TabContainer(panel, { onSwap: check });
    
    this.buildEmbed(panel);
    this.buildPermalink(panel);
    if (!emailForm || !friendForm){
      check(this.tabs.tabs[0]);
      return;
    }
    
    this.buildEmail(panel, emailForm);
    this.buildFriends(panel, friendForm);

    [friendForm, emailForm].each(function(form){
      form.set('send', { evalScripts: true, onComplete: function(){ form.reset(); } });
    });
  },

  buildFriends: function(panel, form){
    var groups = form.getElement('fieldset.groups'),
        friends = form.getElement('fieldset.friends');
    
    var selectables = new Selectables(form.getElements('ul.selection li a'), {
      initialize: function(){ this.input = form.getElement('input.recipients'); },
      onChange: function(selected){
        if (!this.input) return;
        this.input.value = this.serialize(function(item){
          if (item.hasClass('group')) return '*' + item.get('text') + '*';
          else if (item.hasClass('friend')) return item.getNext().get('text');
          else return item.get('text');
        }).join(',');
      }
    });
    
    var allfriends = friends.getElements('ul.selection a');
    form.getElement('a.select-all').addEvent('click', function(event){ event.stop(); selectables.selectAll(allfriends); });
    form.getElement('a.select-none').addEvent('click', function(event){ event.stop(); selectables.deselectAll(allfriends); });
    form.getElement('a.select-group').addEvent('click', function(event){ event.stop(); Fair.Scroller.toElement(groups); });
    
    form.addEvent('submit', function(event){
      this.hide();
      form.send();
      selectables.deselectAll();
      event.stop();
    }.bind(this));
  },

  buildEmail: function(panel, form){
    var inputs = form.getElements('input.email').set('value', '');
    form.addEvent('submit', function(event){
      var input = form.getElement('input.recipients'),
          recipients = [],
          invites = [];
      if (!input) return;
      inputs.each(function(email){
        var invite = email.getParent().getNext().getFirst().checked;
        email.value = email.value.clean();
        if (email && email.value){
          if (invite) invites.push(email.value);
          recipients.push(email.value);
        }
      });
      if (invites.length) Fair.Common.Invite.send(invites.join(','));
      input.value = recipients.join(',');
      this.hide();
      form.send();
      event.stop();
    }.bind(this));
  },

  buildPermalink: function(panel){
    var input = $(panel.id + '_permalink'),
        select = function(){ input.select(); };
    input.addEvents({ click: select });
    if (!input.value) input.value = input.getNext().href;
  },

  buildEmbed: function(panel){
    var items, values, id = panel.id.parseId(),
        model = panel.id.match('track|playlist|user')[0],

        input = $(panel.id + '_embed_code'),
        preview = $(panel.id + '_embed_preview'),
        shuffle = $(panel.id + '_embed_shuffle'),
        autostart = $(panel.id + '_embed_autostart'),
        skin = $(panel.id + '_embed_skin'),

        select = function(){ input.select(); },
        defaults = { size: 'large', shuffle: 0, autostart: 0, destination: 'anywhere' },
        sizes = { large: [220, 350], medium: [110, 180], small: [160, 40], tiny: [16, 16] },
        domain = document.location.protocol + '//' + document.location.hostname,
        feed = domain + '/' + model + '/' + id;
    if (skin) defaults.skin = skin.value;

    var buildEmbedCode = function(options){
      defaults = $merge(defaults, options);
      //replace the L700 with L701 to fix the 'frameset in the iframe' bug
      var params = {fairplayer: defaults.size};
      //var params = {fairplayer: defaults.size, no_frameset: true};
      if (defaults.shuffle) params.shuffle = 1;
      if (defaults.autostart) params.autoplay = 1;
      if (defaults.skin) params.skin = defaults.skin;
      var iframesource = feed + '?' + Hash.toQueryString(params);
      values = {
        anywhere: '<iframe name="fairplayer" scrolling="no" frameborder="0" width="' + sizes[defaults.size][0] + '" height="' + (sizes[defaults.size][1] + (defaults.size == 'large' ? 30 : 0)) + '" src="' + iframesource + '"></iframe>',
        myspace:  (defaults.size == 'large' ? '<table border="0"><tr><td style="padding:2px;">' : '') +
                  '<object type="application/x-shockwave-flash" ' +
                  ' width="' + sizes[defaults.size][0] + '" height="' + sizes[defaults.size][1] + '"' +
                  ' data="' + domain + "/flash/fairplayer-" + defaults.size + ".swf?feed=" + encodeURIComponent(feed) + '.xspf">' +
                  '<param name="flashvars" value="autoplay=' + defaults.autostart + '&shuffle=' + defaults.shuffle +
                    (defaults.skin ? '&skin=' + defaults.skin : '') + '" />' +
                  '<param name="quality" value="best" />' +
                  '<param name="wmode" value="transparent" />' +
                  '</object>' +
                  (defaults.size == 'large' ? '</td></tr><tr><td style="padding:2px;text-align:center;">' +
                    '<a style="font-family:Helvetica,Arial,sans-serif;font-size:14px;"' +
                      ' href="' + feed + '" target="fairtilizer">' +
                      'Get this player from Fairtilizer!' +
                    '</a>' +
                  '</td></tr></table>' : '')
      };
      input.highlight().value = values[defaults.destination];
      preview.set('html', values.myspace.replace('transparent', 'opaque'));
    };

    new Selectables($(panel.id + '_embed_size').getElements('a'), {
      min: 1, max: 1, selected: 0, onChange: function(selected, item){ buildEmbedCode({ size: item.getParent().className }); }
    });

    new Selectables($(panel.id + '_embed_destination').getElements('a'), {
      min: 1, max: 1, selected: 0, onChange: function(selected, item){ buildEmbedCode({ destination: item.getParent().className }); }
    });

    if (shuffle) shuffle.addEvent('click', function(){ buildEmbedCode({ shuffle: (this.checked ? 1 : 0) }); });
    if (autostart) autostart.addEvent('click', function(){ buildEmbedCode({ autostart: (this.checked ? 1 : 0) }); });

    input.addEvents({ click: select }).value = '';
    this.buildEmbedCode = buildEmbedCode;
    buildEmbedCode();
  }

});

//Stats Overlay
Overlay.Stats = new Class({

  Extends: Overlay,

  getPanel: function(href){
    return $('track_' + href.parseId() + '_stats');
  }

});//Tracks
Fair.Tracks = { Links: {} };

//Track Statistics Actions - uses the following json
//Local.Stats = {"1745": [9, 2, 3], "1800": [4, 1, 0], "index": {"votes": 1, "plays": 0, "playlists": 2}, ...};
Fair.Tracks.Stats = {
  
  update: function(){
    new Request.JSON({ onSuccess: this.sync.bind(this) }).get(window.location.href);
  },
  
  sync: function(data){
    data = data || Local.Stats;
    var index = { play: data.index.plays, vote: data.index.votes, add: data.index.playlists };
    var keys = data.index, plays = keys['plays'], votes = keys['votes'], adds = keys['playlists'];
    var tracks = $$('table.track').map(function(track){
      return track.id.replace('track_', '');
    });
    
    for (var i = tracks.length; i--;){
      var track = tracks[i], obj = data[track];
      if (!obj) continue;
      for (track_event in index){
        var event_count = $('track_' + track_event + '_count_' + track, false);
        if (event_count) event_count.innerHTML = obj[index[track_event]];
      }
    }
  }
  
};

//Track Charting Sync - uses the following json
//Local.Charts = {"tracks": [1804, 1783, 512, 1421, ...], "ranks": [1, 2, 3, 4, ...], "changes": [2, 'new', -1, 0, ...]}
Fair.Tracks.Charts = {

  sync: function(data){
    data = data || Local.Charts;
    if (data){
      var tracks = data.tracks, ranks = data.ranks, changes = data.changes;
      for (var i = tracks.length; i--;){
        var track = 'track_' + tracks[i] + '_';
        var rank = $(track + 'rank', false);
        var status = $(track + 'status', false);
        var change = changes[i], klass = 'stay', text = '=';

        if (change == 'new'){ klass = 'new';  text = 'new!'; }
        else if (change > 0){ klass = 'rise'; text = '+' + change; }
        else if (change < 0){ klass = 'drop'; text = change; }

        if (rank) rank.innerHTML = ranks[i];
        if (status){
          status.innerHTML = text;
          status.className = klass;
        }
      }
    }
    
    $$('div.ranking').show();
  }

};

//Tracks Initialization
Fair.Tracks.init = function(){
  var callback = function(link){ Fair.Common.Links[link.className.split(' ')[1]](link, 'track'); },
      action = Fair.Session ? callback : Local.Landing.tease;
  
  $$('a.track').each(action);
  this.playButtons = $$('a.track.play.button');
  this.voteButtons = $$('a.track.vote.button');
    
  this.Charts.sync();
  
  if (Local.Stats) this.Stats.sync();
  if (Fair.Session){
    Fair.Common.Admin.sync('track');
    Fair.Common.Votes.sync('track');
  }
  
  var pwd_field = $('pwd');
  if (pwd_field) pwd_field.value = '';
  
  var private_info = $('private_track_info');
  if (private_info){
    var visible = true;
    private_info.getElement('textarea').addEvent('mouseup', function(){ this.select(); });
    $('toggle_private_track_info').addEvent('click', function(){
      this.set('text', visible ? 'show' : 'hide');
      private_info.slide(visible ? 'out' : 'in');
      visible = !visible;
    });
  }
  
  this.loaded = true;
};

window.addEvent('domready', Fair.Tracks.init.bind(Fair.Tracks));//Playlists
Fair.Playlists = { Links: {} };

//Playlists Initialization
Fair.Playlists.init = function(){
  var callback = function(link){ Fair.Common.Links[link.className.split(' ')[1]](link, 'playlist'); },
      action = Fair.Session ? callback : Local.Landing.tease;
  
  $$('a.playlist').each(action);
  this.playButtons = $$('a.playlist.play.button');
  this.voteButtons = $$('a.playlist.vote.button');
  
  if (Fair.Session){
    Fair.Common.Admin.sync('playlist');
    Fair.Common.Votes.sync('playlist');
  }
  
  this.loaded = true;
};

window.addEvent('domready', Fair.Playlists.init.bind(Fair.Playlists));//Users
Fair.Users = {};

Fair.Users.Manage = {
  
  init: function(){
    if (Fair.Content.$('manage_users')){
     this.featureToggleRequest = null;
      // var users = $('manage_users').getChildren('tr').filter(function(tr){
      //   return tr.get('id').match('_manage_user');
      // });

      Fair.Content.$$('input.featured_toggle').each(function(user){
        user.addEvent('click', function(){
          var id = user.get('id').match(/user_(\d+)_featured/)[1];
          this.featureToggleRequest = new Request.JSON({
            url: '/users/' + id + ';toggle_featured', 
            method: 'post',
            onComplete: function(result){
              Fair.Content.$('user_' + result.id + '_featured').set('checked',result.featured);
              if (result.no_picture){
                alert(result.name + " cannot be selected because there is no avatar.");  
              };
            } 
          }).post();
        }.bind(this));
      }, this);
    };
  }
  
};

//Overrides for Common Links
Fair.Users.Links = {
  
  vote: function(link){
    var id = link.id.parseId().toInt();
    if (id == Fair.Session.id){ this.cantvote(link); return; }
    
    link.addEvent('click', function(event){
      event.stop();
      var type = this.className.match(/friend|fanof|isfan|vote/);
      Fair.Users.Votes.vote(id, type && type[0]);
    });
  },
  
  cantvote: function(link){
    link.addEvent('click', function(event){ event.stop(); }).set({
      'class': 'user cantvote button',
      'title': "You can't subscribe to yourself!"
    });
  }
  
};

//Actions for Users Votes
Fair.Users.Votes = {
  
  sync: function(){
    Fair.Users.voteButtons.set({'class': 'user vote button', 'title': "Subscribe to this member"});
    ['friend', 'isfan', 'fanof'].each(function(type){
      var info = Fair.Users.Types[type];
      Fair.Session[info.collection].each(function(id){
        var button = $('user_vote_button_' + id);
        if (button) button.set({'class': 'user ' + type + ' button', 'title': info.title});
      });
    });
    var button = $('user_vote_button_' + Fair.Session.id);
    if (button) button.set({ 'class': 'user cantvote button', 'title': "You can't subscribe to yourself!" });
  },
  
  vote: function(id, type){
    if (!id) return;
    else if (!Fair.Session){ alert('Login to vote!'); return; }
    else if (!this.Requests[id]) this.Requests[id] = new Request.JSON({
      link: 'cancel',
      onSuccess: this.respond.bind(this)
    });
    
    var state = (type && type.test(/friend|fanof/)) ? false : true;
    this.request(id, state);
  },
  
  request: function(id, state){
    this.update(id, state, '<img src="/images/spinner.gif" alt="loading" />');
    this.Requests[id].post('/friendships/' + (state ? 'create' : 'destroy') + '/' + id);
  },
  
  respond: function(response){
    this.update(response.id, response.state, response.count);
  },
  
  update: function(id, state, count){
    var vote_count = $("user_vote_count_" + id), vote_button = $("user_vote_button_" + id);
    if (vote_count) vote_count.set('html', count);
    if (vote_button){
      var type = vote_button.className.match(/friend|fanof|isfan|vote/)[0],
          types = Fair.Users.Types, next = types[type].next;
      
      if ((state && (/friend|fanof/).test(type)) || (!state && (/isfan|vote/).test(type))) return;
      vote_button.set({
        'class': 'user ' + next + ' button',
        'title': types[next].title
      });
    }
  }
  
};

//Hash of User Relationships and States
Fair.Users.Types = {
  vote:   { next: 'fanof',  title: 'Subscribe to this member', collection: false },
  fanof:  { next: 'vote',   title: 'Stop subscribing to this member', collection: 'followings' },
  isfan:  { next: 'friend', title: 'Add this member to your friends', collection: 'followers' },
  friend: { next: 'isfan',  title: 'Drop this member from your friends', collection: 'friends' }
};

//Users Initialization
Fair.Users.init = function(){
  this.Votes.Requests = {};
  
  var callback = function(link){
    var action = link.className.split(' ')[1], callback = this.Links[action];
    callback = callback ? callback.bind(this.Links) : Fair.Common.Links[action];
    callback(link, 'user');
  }.bind(this), action = Fair.Session ? callback : Local.Landing.tease;
  
  $$('a.user').each(action);
  this.playButtons = $$('a.user.play.button');
  this.voteButtons = $$('a.user.vote.button');
  
  $$('a.more-profile').addEvent('click', function(event){
    var profile = this.getParent(), hidden = profile.hasClass('less-profile');
    profile.className = hidden ? 'more-profile' : 'less-profile';
    this.innerHTML = hidden ? '&#9650;' : '&#9660;';
    event.stop();
  });
  
  if (Fair.Session) this.Votes.sync();
  
  this.Manage.init();
  
  this.loaded = true;
};

window.addEvent('domready', Fair.Users.init.bind(Fair.Users));//Comment handling actions
Local.Comments = {
  
  init: function(){
    var post = $('comment_form');
    if (!Fair.Session || !post) return;
    
    this.user = Fair.Session.id;
    this.admin = (Fair.Session.level == 'admin');
    this.request = new Request();
    this.buildPost(post);
    
    $$('tr.comment').each(this.initComment, this);
  },
  
  initComment: function(comment){
    this.initReply(comment, comment.getElement('span.comment_links').show().getFirst());
    if (!this.admin && this.user != comment.getFirst().id.parseId().toInt()) return;
    var links = comment.getElement('span.comment_modify_links').show();
    this.initEdit(comment, links.getElement('a.edit'));
    this.initRemove(comment, links.getElement('a.remove'));
  },
  
  initReply: function(comment, reply){
    var container = $(comment.id + '_reply_form'),
        textarea = container.getElement('textarea');
    reply.addEvent('click', function(event){
      event.stop();
      if (!container.hasClass('initialized')) this.buildReply(container, textarea);
      container.toggle(true);
      textarea.focus();
    }.bind(this));
  },
  
  initEdit: function(comment, edit){
    edit.addEvent('click', function(event){
      event.stop();
      new Request({
        onComplete: function(response){
          this.buildEdit(response, comment);
        }.bind(this)
      }).GET(edit.href);
    }.bind(this));
  },
  
  initRemove: function(comment, remove){
    remove.addEvent('click', function(event){
      event.stop();
      if (!confirm('Are you sure you want to remove this comment?')) return;
      this.request.DELETE(remove.href);
      comment.destroy();
    }.bind(this));
  },
  
  buildComment: function(response, container){
    var comment = this.buildRow(response, container);
    Fair.Scroller.toElement(comment.getPrevious());
    comment.getElements('tr.comment').each(this.initComment, this);
    return comment;
  },
  
  buildRow: function(response, container){
    var table = '<table><tbody>' + response + '</tbody></table>';
    table = new Element('div').hide('true').inject(document.body).set('html', table);
    var row = table.getElement('tr').inject(container, 'after').highlight();
    table.destroy();
    return row;
  },
  
  buildPost: function(post){
    var form = post.getElement('form'),
        submit = form.getElement('input[type=submit]'),
        textarea = form.getElement('textarea');
    
    form.set('send', {
      evalScripts: true,
      onComplete: function(response){
        this.initComment(this.buildComment(response, post));
        submit.removeClass('processing').value = 'Post';
        textarea.value = '';
      }.bind(this)
    }).addEvent('submit', function(event){
      event.stop();
      if (!textarea.value.clean() || submit.hasClass('processing')) return;
      submit.addClass('processing').value = 'Processing';
      this.send();
    });
  },
  
  buildReply: function(container, textarea){
    var form = container.getElement('form'),
        submit = form.getElement('input[type=submit]'),
        cancel = form.getElement('a.cancel');
    textarea.value = '';
    
    form.set('send', {
      evalScripts: true,
      onComplete: function(response){
        this.initComment(this.buildComment(response, container));
        submit.removeClass('processing').value = 'Reply';
        container.hide(true);
        textarea.value = '';
      }.bind(this)
    }).addEvent('submit', function(event){
      event.stop();
      if (!textarea.value.clean() || submit.hasClass('processing')) return;
      submit.addClass('processing').value = 'Processing';
      this.send();
    });
    
    cancel.addEvent('click', function(event){
      container.hide(true);
      event.stop();
    });
    
    container.addClass('initialized');
  },
  
  buildEdit: function(response, comment){
    var container = this.buildRow(response, comment),
        form = container.getElement('form'),
        submit = form.getElement('input[type=submit]'),
        textarea = form.getElement('textarea'),
        cancel = form.getElement('a.cancel');
    comment.hide(true);
    
    form.set('send', {
      evalScripts: true,
      onComplete: function(response){
        this.initComment(this.buildComment(response, container));
        submit.removeClass('processing').value = 'Update';
        container.destroy();
        comment.destroy();
      }.bind(this)
    }).addEvent('submit', function(event){
      event.stop();
      if (!textarea.value.clean() || submit.hasClass('processing')) return;
      submit.addClass('processing').value = 'Processing';
      this.send();
    });
    
    cancel.addEvent('click', function(event){
      container.destroy();
      comment.show();
      event.stop();
    });
  }
  
};

window.addEvent('domready', Local.Comments.init.bind(Local.Comments));