/*
 *    This file builds on top of prototype.js and fbjs to create a standard javascript library 
 */

/* try to use this as little as possible! */
function is_fbml() {
  return !!document.getRootElement;
}

if (is_fbml()) {
  /* add some things to FBJS to make it more like prototype */
  Event = {};
  Element = {};
  
  $F = function(elem) {
  	return $(elem).getValue();
  };
  
  $ = function(elem) {
    if (!elem) return null;
    obj = typeof(elem) == "string" ? document.getElementById(elem) : elem;
    for (var method in Element) {
  	  obj[method] = Element[method].bind(null,obj);
  	}
    return obj;
  };

  Event.observe = function(element, eventName, handler) {
    element.addEventListener(eventName, handler);
  };

  Event.stop = function(e) {
    e.preventDefault();
    e.stopPropagation();
  };

  Element.getWidth = function(element) {
    return $(element).getOffsetWidth();
  };

  Element.remove = function(element) {
    return $(element).getParentNode().removeChild(element);	
  };

  Element.up = function(element, css_class) {
    if (css_class) {
      css_class = css_class.replace('.','');
      if (!element.getParentNode()) {
        return null;
      } else if ($(element.getParentNode()).hasClassName(css_class)) {
        return $(element.getParentNode());
      } else {
        return Element.up(element.getParentNode(), css_class);
      }
    } else {
      return $($(element).getParentNode());
    }
  };
  Element.down = function(element, css_class) {
    if (css_class) {
      return Element.getElementsByClassName(element, css_class.replace('.',''))[0];
    } else {
      return $($(element).getFirstChild());
    }
  };

  Element.hide = function(element) {
    $(element).setStyle('display', 'none');
  };
  Element.show = function(element) {
    $(element).setStyle('display', '');
  };
  Element.toggle = function(element) {
    if ($(element).visible()) { $(element).hide() } else {$(element).show()}
  };
  Element.visible = function(element) {
    return $(element).getStyle('display') != 'none';
  };
  Element.update = function(element, text) {
    $(element).setTextValue(text);
  };

  Element.immediateDescendants = function(element) {
    return element.getChildNodes();
  };
  Element.setAttribute = function(element, attribute, value) {
  	if (attribute == 'title')
  	  return element.setTitle(value);
  	else if (attribute == 'class')
  	  return element.setClassName(value);	
  	else
  	  1/0;
  };
  Element.getElementsByClassName = function(element,className){
    var results = [];	
    var chNodes = element.getElementsByTagName('*');
    for (var i=0; i < chNodes.length; i++){
      if ($(chNodes[i]).hasClassName(className)) {
  		  results[results.length] = $(chNodes[i]);
  		}
  	}	
  	return results;
  };

  Element.hasClassName = function(element,className){
      var classNames = element.getClassName().split(' ');
      for (var i=0; i < classNames.length; i++){
        if (classNames[i] == className){
            return true;
          }
      }
      return false;
  };
  
  Ajax.Request = function(url,opts){
    Ajax.doFB(url, opts);
  };

  Ajax.Updater = function(id,url,opts){
    if (!opts) { opts = {};}
    opts["update_id"] = id;
    Ajax.doFB(url, opts);
  };

  Ajax.doFB = function(url,opts) {
    if (!opts) { opts = {};}
    if (!opts.parameters) {opts.parameters = {};}
    if (fqdn && url.indexOf(fqdn) < 0) { url = fqdn + url; }

    var ajax = new Ajax();
    ajax.onerror = function(data) {
      // conforming to how prototype does callbacks
      if (opts.onFailure) opts.onFailure(data);
      if (opts.onComplete) opts.onComplete(data);
    };
    ajax.ondone = function(data) {
      // conforming to how prototype does callbacks
      if (opts.onSuccess) opts.onSuccess(data);
      if (opts.onComplete) opts.onComplete(data);
      if (opts.update_id) $(opts.update_id).setInnerFBML(data);
    };
    ajax.responseType = opts.evalJSON == 'force' ? Ajax.JSON : Ajax.FBML;
    ajax.requireLogin = opts['requireLogin'];

    new_parameters={};
    for (parm in opts.parameters) {
      key = parm.toString().replace(/%3D/g,'=').replace(/%26/g,'&');
      val = opts.parameters[parm].toString().replace(/%3D/g,'=').replace(/%26/g,'&');
      new_parameters[key]=val;
    }
    new_parameters["_method"] = opts.method || 'post';

    ajax.post(url,new_parameters);	

  };

  var Effect = {};
  Effect.Highlight = function(el,opts){
	  Animation($(el)).to('background', '#ffff99').to('color', '#fcfce3').to('color', '').go();
  };
  Effect.BlindDown = function(el,opts){
	  Animation($(el)).to('height', 'auto').from('0px').to('width', 'auto').from('0px').to('opacity', 1).from(0).blind().show().go();
  }
  
  var openModalWindow = null;
  var ModalWindow = {
    openLinkInModal: function(element, options) {
      options = options || {};
      // get the url off the href and sub out the absolute path, leaving only relative
      var url = element.getHref();
      url = url.replace(/http:\/\/[a-z.]*\/[^/]*/,"");

      // do an ajax request and on complete, open a dialog... 
      new Ajax.Request(url, {
        onSuccess: function(data) {
          if (openModalWindow) openModalWindow.hide();

          if (options['confirmText']) {
            openModalWindow = new Dialog().showChoice(modal_content_title, modal_content_body, options['confirmText'], 'Close');
            openModalWindow.onconfirm = function() { document.setLocation(options['confirmUrl']); }
          } else {
           openModalWindow = new Dialog().showMessage(modal_content_title, modal_content_body, 'Close');
          }
          $('modal_content_body').setInnerFBML(data);
          
          // pull the h1 out of the body adn put it in the title... and set its style directly to override h1 css
          var h1 = document.getElementById('modal_content_body').getElementsByTagName('h1')[0];
          h1.setStyle({color: 'white', margin: 0, padding: 0, border: 0, fontSize: '14px'});
          $('modal_content_title').appendChild(h1);

          // set the width
          if (options['width']) openModalWindow.setStyle('width', (parseInt(options['width'])+42) + 'px');
        }
      });
      return false;
    }
  };
  
  
} else {

  /* add some things to prototype to make it more like FBJS */
  Element.addMethods({
    setDisabled: function(element, val) {
      element.disabled = val;
    },
    getId: function(object) {
      return object.id;	
    },
    walkUp: function(element,className) {
      element = $(element);
      return element.up('.' + className);
    },
    setClassName: function(element,className) {
      element.className = className;
    },
    getClassName: function(element,className) {
			return element.className;
    },
    getTitle: function(element) {
      return element.title;
    },
    setTitle: function(element, new_title) {
      element.title = new_title;
    },
    getParentNode: function(element) {
      return element.parentNode;
    },
    setChecked: function(element, value) {
      element.checked = value;
    },
    getChecked: function(element) {
      return element.checked;
    },
    getLastChild: function(element) {
      return $($(element).descendants().last());
    },
    getSelectedIndex: function(element) {
      return $(element).selectedIndex;
    },
    setSelectedIndex: function(element, value) {
      $(element).selectedIndex = value;
    }
  });
  
  Ajax.Request.addMethods({
    initialize: function($super, url, options) {
      if (!options) options = {};
      if (options['requireLogin'] && !viewerLoggedIn()) {
        try {
          if (options['onFailure']) options['onFailure']();
          if (options['onComplete']) options['onComplete']();
        } catch (e) { }
        $('login-link').onclick();
      } else { 
        $super(options);
        this.transport = Ajax.getTransport();
        this.request(url);
      }
    } 
  });
  
}

/* this is a place for functions that don't have a place... keep in mind it must be prototype/fbjs agnostic */

var followMe = function(button, viewer_id, pid){
  button = $(button);
  button.up().removeClassName('can-follow');
  button.up().addClassName('now-following');
  new Ajax.Request('/people/' + viewer_id + '/follow', {parameters:{new_friend_id:pid}});
};

var unfollowMe = function(button, viewer_id, pid){
  button = $(button);				
  button.up().removeClassName('now-following');
  button.up().addClassName('can-follow');
  new Ajax.Request('/people/' + viewer_id + '/unfollow', {parameters:{frenemy_id:pid}});
};

var setActionBoxSpinner = function(el, enable) { 
  spinner = $(el).up('.action-wrapper'); 
  if (enable) {
    spinner.addClassName('processing-ajax-request');
  } else {
    spinner.removeClassName('processing-ajax-request');
  }
};

var radioStatusClicked = function(radio, update_status_url, status_id) {
  setActionBoxSpinner(radio, true);
  var onCompleteCallback = function() { setActionBoxSpinner(radio, false); };
  var onFailureCallback = function() { $(radio).setChecked(false); };
  new Ajax.Request(update_status_url, {parameters:{status:status_id, from:'actionbox'}, onComplete: onCompleteCallback, onFailure: onFailureCallback, requireLogin:true});		
};

var radioOwnershipClicked = function(radio, url, status_id) {
  setActionBoxSpinner(radio, true);
  var onCompleteCallback = function() { setActionBoxSpinner(radio, false); };
  var onFailureCallback = function() { $(radio).setChecked(false); };
	new Ajax.Request(url, {parameters:{code:status_id}, onComplete: onCompleteCallback, onFailure: onFailureCallback, requireLogin:true});
};

var popupPlayerWindow = function(el,url) {
	if (is_fbml()) {
    new Dialog().showMessage('Video Player', video_player_dialog, 'Close').setStyle('width', '555px');
		new Ajax.Updater('video-player', url, {requireLogin: true});
  } else {
		ModalWindow.openLinkInModal(el, {requireLogin: true});
	}
	return false;  		  
};

var doubleSubmitProtection = function(el) {
	/* Safari does't like it for some reason: el.setDisabled(true); */
	el.setValue('Submitting');
	return true;
};

var loadingReportProblem = false;

var reportProblemSubmit = function(report_url) {
  if (loadingReportProblem) return;
  loadingReportProblem = true;

  var ajax = new Ajax();
  ajax.responseType = Ajax.FBML;
  ajax.post(report_url, document.getElementById('reportProblemForm').serialize());
  loadingReportProblem = false;

  new Dialog().showMessage('Report has been submitted', "Thank you for submitting the report! We'll try to address this as quickly as possible!");

  return false;
}

var reportProblem = function(item_id, item_type, item_title, item_url, report_url) {
  if (loadingReportProblem) return;
  loadingReportProblem = true;

  if (reportProblemDialog) reportProblemDialog.hide();
  var ajax = new Ajax();
  ajax.responseType = Ajax.FBML;
  ajax.ondone = function(data) {
		document.getElementById('report_problem_dialog').setInnerFBML(data);
		loadingReportProblem = false;
  }
  var data = {'item_id':item_id, 'item_type':item_type, 'item_title':item_title, 'item_url':item_url}
  ajax.post(report_url, data);

  var reportProblemDialog = new Dialog();
  reportProblemDialog.showChoice('Report a Problem: ' + item_title, report_problem_dialog, 'Report');
  reportProblemDialog.onconfirm = function() { reportProblemSubmit(report_url); }

  return false;

}

function submitModerationFormViaAjax(form) {
  Form.request(form, { 
	 onComplete: function(response) { 
        Element.update(ModalWindow.content, response.responseText);
		ModalWindow.refresh();
	 } 
  });
  return false;
}

var AutoGrow = function(element, options) {
  this.element = $(element);
  this.element.setStyle({overflow: 'hidden'});
  this.options = options || {};
  if (!this.options['minHeight']) this.options['minHeight'] = this.element.getClientHeight ? this.element.getClientHeight() : parseInt(this.element.getStyle('height'));

  this.dummy = $(document.createElement('div'));
  this.dummy.setStyle({
    'position': 'absolute',
    'top': '-10000px',
    'left': '-10000px',
    'wordWrap': 'break-word'
  });
  this.element.getParentNode().appendChild(this.dummy);

  // NOTE: if the textarea is display:none on dom load, updateSize won't compute the right height so when you go to show it, it'll be tiny until you focus
  //   Event.observe(this.element, 'focus', function() { this.interval = setInterval(this.updateSize.bind(this), 250); }.bind(this));
  //   Event.observe(this.element, 'blur', function() { clearInterval(this.interval) }.bind(this));
  //   this.updateSize();
  
  // NOTE: This isn't as efficient, but it's safer
  this.updateSize();
};


// NOTE: STUPID BUG... in the facebook profile tab within safari, if you have things like <br/> in a string, you get a syntax
//       error and the carousel won't work.  the work around seems to be breaking up the strings a bit and concating them
//       together so facebook doesn't try to sanitize them
AutoGrow.prototype.updateSize = function(event) {
  var dummy_text = this.element.getValue().replace(/\n/g, '<'+'br'+'/'+'>') + ' <'+'br'+'/'+'> <'+'br'+'/'+'> <'+'br'+'/'+'>';
  this.dummy.setInnerXHTML ? this.dummy.setInnerXHTML("<"+"div"+">" + dummy_text + "<"+"/"+"div"+">") : this.dummy.update(dummy_text);
  this.dummy.setStyle({width: this.element.getClientWidth ? this.element.getClientWidth() + 'px' : this.element.getStyle('width')});
  var dummy_height = this.dummy.getClientHeight ? this.dummy.getClientHeight() + 'px' : this.dummy.getStyle('height');
  var element_height = this.element.getClientHeight ? this.element.getClientHeight() + 'px' : this.element.getStyle('height');
  var new_height = Math.max(parseInt(dummy_height), parseInt(this.options['minHeight']));
  if (new_height != element_height) this.element.setStyle({height: new_height + 'px'});
  setTimeout(this.updateSize.bind(this), 250);
};

var Carousel = function(obj, options) {
  this.table = $(obj);
  this.tr = this.table.getElementsByTagName('tr')[0];
  this.offset = 0;
  this.offsetInterval = 0;
  this.totalEntries = options['total_entries'];
  this.perPage = options['per_page'];
  this.currentPage = 1
  this.paginateUrl = options['paginate_url'];
  this.canLoadNextPage = true;
  this.items = [];
  this.currentEntries = 0;
  this.scrollWrapper = this.table.up();
  this.innerWrapper = this.scrollWrapper.up();
  this.wrapper = this.innerWrapper.up();
  
  /* shift 15px every 50ms.... if we get within 1 second of the end, load the next page */
  this.pixelsPerCycle = 15;
  this.timePerCycle = 50;
  this.bufferPixels = 1000 / this.timePerCycle * this.pixelsPerCycle;

  /* add left button */
  this.scrollLeftButton = $(document.createElement('div'));
  this.scrollLeftButton.addClassName('scroll-left');
  this.wrapper.appendChild(this.scrollLeftButton);

  /* add right button */
  this.scrollRightButton = this.wrapper.getElementsByClassName('scroll-right')[0]
  if (!this.scrollRightButton) {
    this.scrollRightButton = $(document.createElement('div'));
    this.scrollRightButton.addClassName('scroll-right');
    this.wrapper.appendChild(this.scrollRightButton);
  }

  /* events for left button */
  Event.observe(this.scrollLeftButton, 'mousedown', this.onLeftMouseDown.bind(this));
  Event.observe(this.scrollLeftButton, 'mouseup', this.onLeftMouseUp.bind(this));
  Event.observe(this.scrollLeftButton, 'mouseover', this.onLeftMouseOver.bind(this));
  Event.observe(this.scrollLeftButton, 'mouseout', this.onLeftMouseOut.bind(this));

  /* events for right button */
  Event.observe(this.scrollRightButton, 'mousedown', this.onRightMouseDown.bind(this));
  Event.observe(this.scrollRightButton, 'mouseup', this.onRightMouseUp.bind(this));
  Event.observe(this.scrollRightButton, 'mouseover', this.onRightMouseOver.bind(this));
  Event.observe(this.scrollRightButton, 'mouseout', this.onRightMouseOut.bind(this));

  /* loading next page indicators */
  this.loadingNextPage = $(document.createElement('td'));
  this.loadingNextPage.addClassName('indicator');
  var tmpDiv = $(document.createElement('div'));
  this.loadingNextPage.appendChild(tmpDiv);

  /* pre-cache images for other states */
  var precaches = ['scroll-left-hover', 'scroll-left-click', 'scroll-right-hover', 'scroll-right-click'];
  for (var i=0; i < precaches.length; i++) {
    var klass=precaches[i];
    var tmpDiv = $(document.createElement('div'));
    tmpDiv.addClassName('scroll-cache');
    tmpDiv.addClassName(klass);
    this.wrapper.appendChild(tmpDiv);
  }

  /* load initial entries and put in an indicator if need be */
  var initial_tds = this.tr.getElementsByTagName('td');
  for (var i=0; i < initial_tds.length; i++) {
    this.items.push(initial_tds[i]);
    this.currentEntries += 1;
  }
  this.updateScroll();
  
  /* depending on when the images load, sometimes the table width isn't accurate and needs to be recomputed */
  this.periodicUpdater = setInterval(this.updateScroll.bind(this), 1000);
};

Carousel.prototype.insertPagesAtEnd = function(html) {
  var tmpDiv = $(document.createElement('div'));
  var entites_before_insert = this.currentEntries;
  tmpDiv.setInnerFBML ? tmpDiv.setInnerFBML(html) : Element.update(tmpDiv, html);
  
  var child = null;
  while (child = tmpDiv.getFirstChild ? tmpDiv.getFirstChild() : tmpDiv.firstChild) {
    var td = $(document.createElement('td'));
    td.appendChild(child);
    this.tr.appendChild(td);
    this.items.push(td);
    this.currentEntries += 1;
  }
  
  return this.currentEntries - entites_before_insert;
};

Carousel.prototype.killEvent = function(e) {
  if (Event && Event.stop) Event.stop(e);
};

Carousel.prototype.startScrollTimer = function(increment) {
  if (this.timeout) clearTimeout(this.timeout);
  this.timeout = setTimeout(this.startScrollTimer.bind(this, increment), this.timePerCycle);
  this.offset += increment;
  this.updateScroll();
};

Carousel.prototype.updateScroll = function() {
  /* are we at the end? */
  var min_offset = -1 * Math.max(Element.getWidth(this.table) - Element.getWidth(this.innerWrapper), 0);
  if (this.offset < min_offset) this.offset = min_offset;

  /* if they're within the limit, load the next page */
  if ((this.currentEntries < this.totalEntries) && (min_offset - this.offset > -1 * this.bufferPixels) && this.canLoadNextPage) {
    this.tr.appendChild(this.loadingNextPage);
    this.loadingNextPage.show();
    this.canLoadNextPage = false;
    this.currentPage += 1;
    new Ajax.Request(this.paginateUrl + (this.paginateUrl.indexOf('?') == -1 ? '?' : '&') + "page=" + this.currentPage, {
      onComplete: function(data) {
        data = data.responseText || data;
        this.loadingNextPage.hide();

        /* if we inserted rows, mark that we can load another page...
           if not, set totalEntries to the amount we have already so arrows disappear
           and we don't try to load it again  */
        if (this.insertPagesAtEnd(data) > 0) {
          this.canLoadNextPage = true;
        } else {
          this.totalEntries = this.currentEntries;
        }
      }.bind(this)
    });
  }

  if ((this.offset == min_offset) && (this.currentEntries == this.totalEntries)) {
    Element.hide(this.scrollRightButton)
  } else {
    Element.show(this.scrollRightButton);
  }

  /* are we at the beginning? */
  if (this.offset > 0) this.offset = 0;
  if (this.offset == 0) {
    Element.hide(this.scrollLeftButton);
  } else {
    Element.show(this.scrollLeftButton);
  }

  /* shift the table relatively */
  this.scrollWrapper.setStyle({marginLeft: this.offset + 'px'});
};

Carousel.prototype.stopScrollTimer = function(increment) {
  if (this.timeout) clearInterval(this.timeout);
  this.timeout = null;
}

Carousel.prototype.onLeftMouseDown = function(e) {
  if (e) Event.stop(e);
  this.scrollLeftButton.addClassName('scroll-left-click');
  this.startScrollTimer(this.pixelsPerCycle);
};

Carousel.prototype.onLeftMouseUp = function(e) {
  // if we stop this event, the profile_main box in facebook gets wacky and starts dragging
  //if (e) Event.stop(e);
  this.stopScrollTimer();
  this.scrollLeftButton.removeClassName('scroll-left-click');
};

Carousel.prototype.onLeftMouseOver = function(e) {
  if (e) Event.stop(e);
  this.scrollLeftButton.addClassName('scroll-left-hover');
};

Carousel.prototype.onLeftMouseOut = function(e) {
  if (e) Event.stop(e);
  this.scrollLeftButton.removeClassName('scroll-left-hover');
  this.onLeftMouseUp();
};

Carousel.prototype.onRightMouseDown = function(e) {
  if (e) Event.stop(e);
  this.scrollRightButton.addClassName('scroll-right-click');
  this.startScrollTimer(-1 * this.pixelsPerCycle);
};

Carousel.prototype.onRightMouseUp = function(e) {
  // if we stop this event, the profile_main box in facebook gets wacky and starts dragging
  //if (e) Event.stop(e);
  this.stopScrollTimer();
  this.scrollRightButton.removeClassName('scroll-right-click');
};

Carousel.prototype.onRightMouseOver = function(e) {
  if (e) Event.stop(e);
  this.scrollRightButton.addClassName('scroll-right-hover');
};

Carousel.prototype.onRightMouseOut = function(e) {
  if (e) Event.stop(e);
  this.scrollRightButton.removeClassName('scroll-right-hover');
  this.onRightMouseUp();
};
var InputHelptext = function(element, options) {
	this.el = $(element);
  this.options = options || {};
	this.reset();
	Event.observe(this.el, 'blur', this.reset.bind(this));
	Event.observe(this.el, 'focus', this.focus.bind(this));
};
InputHelptext.prototype.reset = function(){
	if (!this.el.getValue() || this.el.getValue() == '' || this.el.getValue() == this.el.getTitle()) {	
		this.el.setStyle({color: '#ccc'});
		this.el.setValue(this.el.getTitle());
		if (this.options['onReset']) this.options['onReset']();
	}
};
InputHelptext.prototype.focus = function(){
	if (this.el.getValue() == this.el.title || this.el.getValue() == this.el.getTitle()) {
		this.el.setStyle({color: 'black'});
		this.el.setValue('');
	}
};
var loadingReportProblem = false;

var reportProblemSubmit = function(report_url) {
  if (loadingReportProblem) return;
  loadingReportProblem = true;

  var ajax = new Ajax();
  ajax.responseType = Ajax.FBML;
  ajax.post(report_url, document.getElementById('reportProblemForm').serialize());
  loadingReportProblem = false;

  new Dialog().showMessage('Report has been submitted', "Thank you for submitting the report! We'll try to address this as quickly as possible!");

  return false;
}

var reportProblem = function(item_id, item_type, item_title, item_url, report_url) {
  if (loadingReportProblem) return;
  loadingReportProblem = true;

  if (reportProblemDialog) reportProblemDialog.hide();
  var ajax = new Ajax();
  ajax.responseType = Ajax.FBML;
  ajax.ondone = function(data) {
		document.getElementById('report_problem_dialog').setInnerFBML(data);
		loadingReportProblem = false;
  }
  var data = {'item_id':item_id, 'item_type':item_type, 'item_title':item_title, 'item_url':item_url}
  ajax.post(report_url, data);

  var reportProblemDialog = new Dialog();
  reportProblemDialog.showChoice('Report a Problem: ' + item_title, report_problem_dialog, 'Report');
  reportProblemDialog.onconfirm = function() { reportProblemSubmit(report_url); }

  return false;

}

function submitModerationFormViaAjax(form) {
  Form.request(form, { 
	 onComplete: function(response) { 
        Element.update(ModalWindow.content, response.responseText);
		ModalWindow.refresh();
	 } 
  });
  return false;
}

var ratingClicked = function(el,val,entity_id, ajax_url){
	var topElement = $(el).up('.rating-wrapper');
	var viewer_rating = $(topElement).down('.viewer');
	var old_width = viewer_rating.getWidth();
	viewer_rating.setStyle({width: val + "0%"});
	if (val > 0) {
	  topElement.down('.clearx').setStyle({visibility:'visible'});
    } else {
	  topElement.down('.clearx').setStyle({visibility:'hidden'});
    }
	new Ajax.Request(ajax_url, {
	  requireLogin: true,
	  parameters: {rating:val},
	  onSuccess: function() {
		$(topElement).setTitle(val);
    	// Looks horrible in IE 6
        //new Effect.Highlight(topElement, {duration:0.4});
  	},
  	onFailure: function() {
  	    viewer_rating.setStyle({width: old_width + "px"})
    	$(topElement).setTitle('');
  	}
  });
  return false;
}

var ratingMouseOver = function(el) { $(el).up('.rating-wrapper').down('.viewer').hide(); }
var ratingMouseOut = function(el)  { $(el).up('.rating-wrapper').down('.viewer').show(); }


var submitUsefulness = function(target,url){
	new Ajax.Updater(target.getParentNode(), url, {requireLogin:true});
};

var editMyReview = function(){
	$('review-submitter').setStyle({display:'block'});
	$('existing-review').setStyle({display:'none'});
};

var updateStatusFromSearch = function(el,status,from,url){
  pNode = $(el).up('.pResult');
  if (status == 0) {
	updateSearchStatus(pNode, 'Saving to Collection...');
  } else if (status == -1) {
	updateSearchStatus(pNode, 'Generating Recommendation...');
  } else {
	updateSearchStatus(pNode, 'Saving to Collection & Generating Recommendation...');
  }
  new Ajax.Request(url, {
    parameters: {status:status, from:from}, 
    evalScripts:true, 
    requireLogin: true,
    method: 'POST',
    onSuccess: function(transport) {
	  hideSearchStatus(pNode);
      pNode.setInnerFBML ? pNode.setInnerFBML(transport) : Element.update(pNode,transport.responseText);
      textarea = pNode.down(".entity_review_textarea");
      if (textarea) { new Effect.Highlight(textarea, {duration:0.7}) }
    }
 });
};

var saveAndPublishSearchReview = function(el, url, rec_url){
 pNode = $(el).up('.pResult');
 review = $F(pNode.down('.entity_review_textarea'));
 if (/\S/.test(review)){
	updateSearchStatus(pNode, 'Saving Review...');
 	new Ajax.Request(url, {
      parameters:{review:review,method:'feedStory',source:'search',optedtopublish:'yes'},
      requireLogin: true,
      evalJSON: 'force',
      method: "POST",
      onSuccess: function(transport) {
        Facebook.showFeedDialog(transport.content.feed.template_id, transport.content.feed.template_data, null, null, function(){newRecommendation(el,rec_url)}, 'What did you think of this?', {value:review});
      }
    });
  } else {
  	el.value = 'Enter a review!';
  	setTimeout(function(){el.value="Save review";},500);
  }
};

var saveSearchReview = function(el, url, rec_url){
 pNode = $(el).up('.pResult');
 review = $F(pNode.down('.entity_review_textarea'));
 if (/\S/.test(review)){
	updateSearchStatus(pNode, 'Saving Review...');
 	new Ajax.Request(url, {
      parameters:{review:review,source:'search',optedtopublish:'no'},
      requireLogin: true,
      method: "POST",
      onSuccess: function(transport) {
        newRecommendation(el,rec_url);
      }
    });
  } else {
  	el.value = 'Enter a review!';
  	setTimeout(function(){el.value="Save review";},500);
  }
};

var newRecommendation = function(el,url){
  pNode = $(el).up('.pResult');
  updateSearchStatus(pNode, 'Generating Recommendation...');
  new Ajax.Request(url, {
      requireLogin: true,
      method: "GET",
      onSuccess: function(transport) {
	    hideSearchStatus(pNode);
        pNode.setInnerFBML ? pNode.setInnerFBML(transport) : Element.update(pNode,transport.responseText);
      }
  });
};

var updateSearchStatus = function(pNode, txt) {
  Element.update(pNode.up().down('.reloading_txt'),txt);
  pNode.up().down('.reloading').show();	
}

var hideSearchStatus = function(pNode) {
  pNode.up().down('.reloading').hide();	
}

var ownershipChanged = function(el, url){
  new Effect.Highlight(el);
  new Ajax.Request(url, {parameters:{code:el.getValue()}, requireLogin: true});
};


var ChallengeList = {};
ChallengeList.toggleChallenge = function(el){
	var container = $(el).up('.todo-item');
  if (container.hasClassName('expanded')){
	  container.removeClassName('expanded');
	  container.addClassName('collapsed');		
	}
	else{
	  container.removeClassName('collapsed');
	  container.addClassName('expanded');		
	}
};
ChallengeList.hideChallenge = function(el, person_id, task_identifier){
	Element.remove($(el).up('.todo-item'));
	new Ajax.Request('/people/' + person_id + '/task_hides?task_identifier=' + task_identifier);	
	if ($('todo-list').getElementsByClassName('todo-item').length < 1){
		Element.remove($('todo-list'));
	}
};



function submitLoginFormViaAjax(form) {
  if ($("login-flash-error")) {
    Element.hide("login-flash-error");
    ModalWindow.refresh();
  }
  
  Form.request(form, {
    onComplete: function(response) {
      Element.update(ModalWindow.content, response.responseText);
      ModalWindow.refresh();
    }
  });
  
  return false;
}

var WordWheel = function(obj, options) {
  this.cache = {};
  this.obj = $(obj);

  // Setup the events we're listening to
  Event.observe(this.obj, 'focus', this.onfocus.bind(this));
  Event.observe(this.obj, 'blur', this.onblur.bind(this));
  Event.observe(this.obj, 'keyup', this.onkeyup.bind(this));
  Event.observe(this.obj, 'keydown', this.onkeydown.bind(this));
  Event.observe(this.obj, 'keypress', this.onkeypress.bind(this));

  // Create the dropdown list that contains our suggestions
  this.list = $(document.createElement('div'));
  this.list.addClassName('suggest_list');
  this.list.setStyle({width: (options['width'] || Element.getWidth(this.obj)-2)+'px', display: 'none'});
  Element.up(this.obj).appendChild(this.list);

  // Various flags
  this.focused = true;

  this.scrollDownOnDraw = false; // this is so ghetto, forget it. options.scrollDownOnDraw == null ? false : options.scrollDownOnDraw
  this.options = options == null ? {} : options;
  this.selectedindex = -1;
  this.delayTime = options.delayTime == null ? 700 : options.delayTime;
  this.preMsgTxt = options.preMsgTxt == null ? "type for suggestions" : options.preMsgTxt;
  this.normOpac = options.menuOpacity == null ? 94 : options.menuOpacity;
	this.clearValueAfterSelection = options.clearValueAfterSelection == null ? false : options.clearValueAfterSelection;
  this.curOpac = this.normOpac;
  this.showResultsCount = options.showResultsCount == null ? true : options.showResultsCount;
  this.obj.setStyle({margin: "0px"});

  if(!options.focus) {
    if (this.obj.getValue().length == 0) {
      this.preMsg = true;
      this.obj.setValue(this.preMsgTxt);
      this.obj.addClassName("suggest_pretext");
    }
  } else {
    this.obj.focus();
    this.preMsg = false;
    if (this.validValue()) {
      this.updateResults();
    }
  }
};

// Show suggestions when the user focuses the text field
WordWheel.prototype.onfocus = function(event) {
  if(this.preMsg) {
    this.obj.setValue("");
    this.obj.removeClassName("suggest_pretext");
    this.preMsg = false;
  }
  this.focused = true;
  if (this.validValue()) {
    this.updateResults();
    this.obj.removeClassName('suggest_found');
    if (this.dataResultsLength && this.dataResultsLength > 0)
      this.show();
  }
};
WordWheel.prototype.validValue = function(event) {
  current = this.obj.getValue();
  if (this.obj.getValue() == "" || this.obj.getValue() == this.preMsgTxt) { 
    return false;
  } else {
    return true;
  }
};
// ...and hide it when they leave the text field
WordWheel.prototype.onblur = function() {
  if(this.obj.getValue() == "") {
    this.preMsg = true;
    this.obj.setValue(this.preMsgTxt);
    this.obj.addClassName("suggest_pretext");
  }
  this.focused = false;
  this.hide();
};

// Every keypress updates the suggestions
WordWheel.prototype.onkeyup = function(event) {
  switch (event.keyCode) {
    case 27: // escape
    this.hide();
    this.obj.removeClassName('suggest_found');
    break;
    case 13: // enter
    if(this.options!=null && this.options.onEnter!=null) {
      this.hide();
      this.options.onEnter(event);

      if(this.options.clearOnEnter == true) {
        this.obj.setValue('');
        this.hide();
        this.obj.removeClassName('suggest_found');
      }
    }
    break;
    case 0:  
    case 37: // left
    case 9:  // tab
    case 38: // up
    case 39: // right
    case 40: // down
    break;
    default:
    this.selectedindex = -1;
    if (this.validValue()) {
      this.updateResults();
    }
    this.obj.removeClassName('suggest_found');
    break;
  }
};

// We want interactive stuff to happen on keydown to make it feel snappy
WordWheel.prototype.onkeydown = function(event) {
  switch (event.keyCode) {
    case 9: // tab
    case 13: // enter
      if (Element.visible(this.list) && (this.results[this.selectedindex])) {
				this.chooseSelected();
        event.preventDefault();
      }
    break;

    case 38: // up
      this.select(this.selectedindex - 1);
      event.preventDefault();
    break;

    case 40: // down
      this.select(this.selectedindex + 1);
      event.preventDefault();
    break;
  }
};

// Override these events so they don't actually do anything
WordWheel.prototype.onkeypress = function(event) {
  switch (event.keyCode) {
    case 9:  // tab
      if (Element.visible(this.list)) event.preventDefault();
    break;
    case 13: // return
    case 38: // up
    case 40: // down
      event.preventDefault();
    break;
  }
};

// Select a given index
WordWheel.prototype.select = function(index) {
  var children = [];
  var tmp_children = Element.immediateDescendants(this.list);
  for (var i=0; i < tmp_children.length; i++) {
    if (tmp_children[i].hasClassName('suggest_suggestion')) {
      children[children.length] = tmp_children[i];
    }
  }

  if(children != null && children.length > 0) {
    if (index<0) index = 0;
    if (index >= children.length) index = children.length - 1;

    if (this.selectedindex >=0 && this.selectedindex < children.length )
      children[this.selectedindex].removeClassName('suggest_selected');
    children[(this.selectedindex=index)].addClassName('suggest_selected');
  }
};

WordWheel.prototype.prepareForm = function(){
	var inTheList = $('selected-results').getElementsByClassName('suggest_selected_list_item');
	var fields = '';
	var listEntryData = $('selected-results-hiddens');
	for (var i=0; i < listEntryData.length; i++) {
		listEntryData[i].remove();
	}
	var hiddenInputs = ['<div>'];
	
	for (var i=0; i < inTheList.length; i++){
    var entity_id = $(inTheList[i]).getClassName().split('-');
		entity_id = entity_id[entity_id.length - 1];
		hiddenInputs.push('<input type="hidden" name="new_list_entity_attributes[' + entity_id + ']" value="' + i + '"/>');
	}

  hiddenInputs.push('</div>');
	listEntryData[(typeof Facebook == 'undefined') ? 'update' : 'setInnerXHTML'](hiddenInputs.join(''));
	
  return true;
}

WordWheel.prototype.onajaxdone = function(data) {
  data = data.responseJSON || data;
  this.obj.removeClassName("searching");
  // save to the cache
  this.cache[data.fortext] = data;			
  // if its valid, update the UI
  this.drawResults(data, data.fortext);
  this.results = data.results;
};

WordWheel.prototype.getNormTyped = function() {
  return this.obj.getValue().toLowerCase();
};

WordWheel.prototype.getValue = function() {
  return (this.preMsg?"":this.obj.getValue());
};

WordWheel.prototype.drawResults = function(data, typed) {
  Element.update(this.list, '');
  if (data.results == null || data.results.length == 0) {
    this.hide();
    return;
  }
  this.dataResultslength = data.results.length;  
	
  if (this.showResultsCount) {
	  var child = $(document.createElement('span'));
	  Element.update(child, "Showing " + data.results.length + " results of " + data.total + ".");
	  this.list.appendChild(child);
	}

  for ( var i = 0; i < data.results.length; i++ ) {
    var node = $(this.buildResultNode(data.results[i], i, true));
    this.list.appendChild(node);
  }
  if ((typeof window != 'undefined') && window.scrollTo && this.scrollDownOnDraw){
	  window.scrollTo(0,999999);
  }
  this.show();
};

WordWheel.prototype.chooseSelected = function(){
  new_value = this.results[this.selectedindex].value || this.results[this.selectedindex].name;
	if (this.clearValueAfterSelection){
    this.obj.removeClassName('suggest_found');							
    this.obj.setValue('');						
    var node = this.buildSelectedNode(this.results[this.selectedindex], this.selectedindex, false);	
		$('selected-results').appendChild(node);
    node.setStyle({'zoom':1});
		Sortable.create($('selected-results'), {tag:'div'});
		$('results-wrapper').show();
	}
  else {
    this.obj.addClassName('suggest_found');		
    this.obj.setValue(new_value);		
	}
  this.hide();	
}

WordWheel.prototype.buildResultNode = function(data, i) {
	var item = $(document.createElement('div'));
  item.addClassName('suggest_suggestion');

  if (data.thumb) {
    var thumb = $(document.createElement('div'));
    thumb.addClassName('suggest_thumb');

		var thumbImage = $(document.createElement('img'));
		thumbImage.setAttribute('src',data.thumb);
		
		thumb.appendChild(thumbImage);    
		item.appendChild(thumb);
	}
	
	
  Event.observe(item, 'mouseover', function(i) {
    this.select(i);
  }.bind(this, i));
  
  Event.observe(item, 'mousedown', function(event) {
		this.chooseSelected();
  }.bind(this));

  var child = $(document.createElement('em'));
  Element.update(child, data.name);
  item.appendChild(child);

  child = $(document.createElement('small'));
  Element.update(child, data.description);
  item.appendChild(child);
	
	if (data.people_count) {
		var nextRow = $(document.createElement('div'));
    var child = $(document.createElement('small'));
    Element.update(child, data.people_count);
		nextRow.appendChild(child);
    item.appendChild(nextRow);
	}

	var clearer = $(document.createElement('div'));
	clearer.setStyle({clear:'both'});
	item.appendChild(clearer);
	return item;
};

WordWheel.prototype.removeSelection = function(item) {
	item.remove();
}


WordWheel.prototype.buildSelectedNode = function(data, i) {
	var item = $(document.createElement('div'));
  item.addClassName('suggest_selected_list_item');
  item.addClassName('entity-' + data.id);

  if (data.thumb) {
    var thumb = $(document.createElement('div'));
    thumb.addClassName('suggest_thumb');

		var thumbImage = $(document.createElement('img'));
		thumbImage.setAttribute('src',data.thumb);
		
		thumb.appendChild(thumbImage);    
		item.appendChild(thumb);
	}

  var closer = $(document.createElement('div'));
  closer.addClassName('remove_selection');
  item.appendChild(closer);

  Event.observe(closer, 'mousedown', function() {
    this.removeSelection(item);
  }.bind(this));
  

  var child = $(document.createElement('em'));
  Element.update(child, data.name);
  item.appendChild(child);

  child = $(document.createElement('small'));
  Element.update(child, data.description);
  item.appendChild(child);
	
	if (data.people_count) {
		var nextRow = $(document.createElement('div'));
    var child = $(document.createElement('small'));
    Element.update(child, data.people_count);
		nextRow.appendChild(child);
    item.appendChild(nextRow);
	}

	var clearer = $(document.createElement('div'));
	clearer.setStyle({clear:'both'});
	item.appendChild(clearer);
	return item;
};

WordWheel.prototype.sendAjrequest = function(val) {
  this.obj.addClassName("searching");
  new Ajax.Request(this.options.ajaxUrl + escape(val), { onComplete: this.onajaxdone.bind(this), evalJSON: 'force' });
};

// This is called every keypress to update the suggestions
WordWheel.prototype.updateResults = function() {
  // Search the list of potential results and find ones that match what we have so far
  this.searchValue = this.getNormTyped();

  if(this.cache[this.searchValue] != null) {
    // pull from el cache
    this.drawResults(this.cache[this.searchValue],this.searchValue);
    this.results = this.cache[this.searchValue].results;
  } else {
    if(this.requestTimer == null){
      this.requestTimer = setTimeout(
        function() { 
          this.sendAjrequest(this.searchValue); 
          this.requestTimer = null;
        }.bind(this), this.delayTime);
    }
  }
};

WordWheel.prototype.cleanup = function() {
  this.hide();
  this.obj.setValue('');
  this.obj.removeClassName('suggest_found');
}

WordWheel.prototype.show = function() {
  Element.show(this.list);
};

WordWheel.prototype.hide = function() {
  Element.hide(this.list);
};

var SuperReview = {
	updateSuperReviewImpl: function(textarea, reviewable_id) {
    var len = textarea.getValue().split(/[\s\n]+/).length
    var srBadge = $('super-review-' + reviewable_id);
    var classTarget = $(srBadge.getElementsByClassName('super-review-badge')[0]);
    var wordCounter = $(srBadge.getElementsByClassName('word-count')[0]);
    var notYet = classTarget.getElementsByClassName('not-super-review-yet-text')[0];    
    var sut = classTarget.getElementsByClassName('super-review-text')[0];        
    wordCounter.update(150 - len);
    if (len > 149) {
      notYet.hide();
      sut.show();    
      classTarget.setClassName('super-review-badge super');
    } else {
      notYet.show();
      sut.hide();          
      if (len > 100) {
        classTarget.setClassName('super-review-badge better');      
      } else if (len > 25) {
        classTarget.setClassName('super-review-badge good');      
      } else {
        classTarget.setClassName('super-review-badge ok');      
      }
    }
  },
  updateSuperReview: function(textarea,reviewable_id){
	  if (SuperReview.currentTimeout) {clearTimeout(SuperReview.currentTimeout)}
		SuperReview.currentTimeout = setTimeout(function(){SuperReview.updateSuperReviewImpl(textarea,reviewable_id)}, 300);
	}
}
var FeedEvents = {
	commentOnFeed: function(link){
		$($(link).up('.story').getElementsByClassName('comment-publisher')[0]).toggle();
	},
	moreEvents: function(css_id, url){
		new Ajax.Updater(css_id, url);
	},
	submitFeedComment: function(button){
		var story = $(button).up('.story');
		var review = $(story.getElementsByTagName('textarea')[0]).getValue();
		$(button).setDisabled(true);
		$(button).setValue('Saving...');
		new Ajax.Request('/feed_events/' + story.getId().split('-')[1] + '/add_comment',{parameters:{comment:review}, onSuccess:function(resp){FeedEvents.feedSubmitted(resp,story,button)}})
	},
  destroyFeedComment: function(link,comment_id){
		try {
		  if (confirm('Are you sure you want to remove this comment?')) {
		    FeedEvents.actualDestroyFeedComment(link, comment_id);
		  }
		} catch(e) {
			dlg = new Dialog(Dialog.DIALOG_CONTEXTUAL);
			dlg.setContext(link);
			dlg.showChoice('Removing', 'Remove this comment?', 'Yes', 'No'); 
			dlg.onconfirm = function() { FeedEvents.actualDestroyFeedComment(link, comment_id); }
		}
	},
	actualDestroyFeedComment: function(link,comment_id){
		var story = $(link).up('.story');
		link.up('.existing-comment').remove();
		new Ajax.Request('/feed_events/' + story.getId().split('-')[1] + '/destroy_comment',{parameters:{comment_id:comment_id}})	
	},
  feedSubmitted: function(text,story,button){
		var existingComments = story.down('.existing-comments');
		if (text.responseText)
		    new Insertion.Bottom(existingComments, text.responseText);
		else {
			var node = document.createElement('div');
			node.setInnerFBML(text);
			existingComments.appendChild(node);
		}
	  story.getElementsByTagName('textarea')[0].setValue('');
		$(button).setDisabled(false);
		$(button).setValue('Comment');
		FeedEvents.displayEnticer(button);
	},
  displayFullArea: function(input){
		var sa = $(input).up('.submission-area');
		var submitter = sa.down('.comment-submitter');
		var enticer = sa.down('.comment-enticer')
		enticer.hide();		
		submitter.show();
		submitter.getElementsByTagName('textarea')[0].focus();
	},
	displayEnticer: function(input){
		var sa = $(input).up('.submission-area');
		var ta = sa.getElementsByTagName('textarea')[0];
		if (!ta.getValue() || ta.getValue() == ''){
			var submitter = sa.down('.comment-submitter');
			sa.down('.comment-enticer').show();		
			submitter.hide();	
		}
	}
}
var GlobalHeaderMoreMenu = function() {
  this.timer = null;
  this.more_button = $('more-link');
  this.more_menu = $('header-more-menu');
  if (this.more_button) {
    Event.observe(this.more_button, 'mouseover', this.onMouseOver.bind(this));
    Event.observe(this.more_menu, 'mouseover', this.onMouseOver.bind(this));
    Event.observe(this.more_menu, 'mouseout', this.onMouseOut.bind(this));
  }
};

GlobalHeaderMoreMenu.prototype.onMouseOver = function(event) {
  if (this.timer) {
    clearTimeout(this.timer);
    this.timer = null;
  }
  if (this.more_menu.hasClassName('hidden')) this.more_menu.removeClassName('hidden');
};

GlobalHeaderMoreMenu.prototype.onMouseOut = function(event) {
  if (!this.timer) {
    this.timer = setTimeout(this.hideMenu.bind(this), 500);
  }
};

GlobalHeaderMoreMenu.prototype.hideMenu = function(event) {
  this.more_menu.addClassName('hidden');
};
