// Depends on ChickenWingSoftware util.js

////////////////////////////////////////////////////////////////////////////////
// Utility functions.
////////////////////////////////////////////////////////////////////////////////
// These functions are designed to work in or out of Facebook.
////////////////////////////////////////////////////////////////////////////////

var nAnimationsGoing = 0;
var anisGoing = [];
var aniCallbacks = [];
var postAniDelay = 200;
var aniTimeout = null;
var onStartCb = null;
var onFinishCb = null;
var inFb = (typeof(Animation) === 'function' && typeof(Animation.resolution) === 'undefined');

/////
// Replaces the "ondone" method of the Animation object, which doesn't
// work inside Facebook.
function doOnDone(ani, fn)
{
  if (inFb) {
    return ani.checkpoint(1, fn);
  } else {
    return ani.ondone(fn);
  }
}

function doAnimation(ani, callback, postDelay, id /* = 0 */)
{
  id = id || 0;
  postDelay = postDelay || postAniDelay;
  doCheckAni('doAnimation');

  if (!nAnimationsGoing && onStartCb) {
    onStartCb();
  }
  nAnimationsGoing++;
  anisGoing.push(id);
  //console.log('ANI: starting ', id, ': ', nAnimationsGoing, ': ', anisGoing);
  if (callback) addAniCallback(callback);
  doOnDone(ani, function() {
    nAnimationsGoing--;
    anisGoing.shift();
    doCheckAni('cb');
    //console.log('ANI: finished ', id, ': ', nAnimationsGoing, ': ', anisGoing);
    setTimeout(function() {
//     console.log('doAnimation callback: nAnimationsGoing ', nAnimationsGoing,
//     	' callbacks ', aniCallbacks);
      while(nAnimationsGoing === 0 && aniCallbacks.length !== 0) {
	var cb = aniCallbacks.shift();
	//       console.log('doAnimation callback: calling callback ', cb);
	cb();
      }
      if (nAnimationsGoing === 0 && onFinishCb) {
	onFinishCb();
      }
    }, postDelay);
  }).go();
  if (!aniTimeout && typeof(Animation.timeout) !== 'undefined') {
    aniTimeout = setTimeout(checkOnAnimation, 1000);
  }
}


var queuedAnimations = [];
function queueAnimation(ani,
			callback /* = null */,
			postDelay /* = postAniDelay */,
			id /* = 0 */)
{
  postDelay = postDelay || postAniDelay;
  callback = callback || null;
  id = id || 0;
  queuedAnimations.push({ani:ani, callback:callback, postDelay:postDelay, id:id});
}

function queueAniCheckpoint()
{
  queuedAnimations.push('checkpoint');
}

function queueAniCallback(fn, start /* = false */)
{
  queuedAnimations.push(fn);
  if (start) startQueuedAnis();
}

function startQueuedAnis(queuedAnimationsCopy /* = null */)
{
  queuedAnimationsCopy = queuedAnimationsCopy || queuedAnimations;
  queuedAnimations = [];
  addAniCallback(function() {
    ForEach(queuedAnimationsCopy, function(aniObj, n) {
      if (aniObj === 'checkpoint') {
	// Wait for animations to finish before continuing.  This
	// doesn't work if any of the callbacks start another set of
	// animations.
	addAniCallback(function() { startQueuedAnis(queuedAnimationsCopy.slice(n+1)); }, true);
	return true;
      } else if (typeof(aniObj) == 'function') {
	aniObj();
      } else {
	doAnimation(aniObj.ani, aniObj.callback, aniObj.postDelay, aniObj.id);
      }
      return false;
    });
  }, true);
}

if (typeof(Animation) !== 'undefined' && Animation.resolution) {
  Animation.resolution = 50;
}

function doCheckAni(place)
{
  if (typeof(Animation.timeout) !== 'undefined' && !Animation.timeout && nAnimationsGoing) {
    //console.log('ANI: ', place, ': Animation.timeout is false. Resetting nAnimationsGoing (',
	//	nAnimationsGoing, ', ', anisGoing, ')');
    nAnimationsGoing = 0;
    anisGoing = [];
    return true;
  }
  return false;
}

function checkOnAnimation()
{
  if (doCheckAni('checkOnAnimation')) {
    //console.log('ANI: checkOnAnimation: calling callbacks');
    while(nAnimationsGoing == 0 && aniCallbacks.length != 0) {
      var cb = aniCallbacks.shift();
//       console.log('ANI: doAnimation callback: calling callback ', cb);
      cb();
    }
    if (nAnimationsGoing == 0 && onFinishCb) { onFinishCb(); }
    if (typeof(Animation.resolution) !== 'undefined') {
      Animation.resolution = Math.min(Math.floor(Animation.resolution * 1.2), 200);
    }
  }
  if (nAnimationsGoing) {
    aniTimeout = setTimeout(checkOnAnimation, 1000);
  } else {
    aniTimeout = null;
  }
}

////
// Register a function that will be called the next time animation finishes.
function addAniCallback(fn, canGoNow)
{
  doCheckAni('addAniCallback');
  if (canGoNow && nAnimationsGoing === 0) {
//     console.log('ANI: addAniCallback: calling now ', fn);
    fn();
  } else {
    aniCallbacks.push(fn);
//      console.log('addAniCallback: nAnimationsGoing ', nAnimationsGoing,
//  		' calling later ', fn, ' callbacks ', aniCallbacks);
  }
}

function setGlobalAniCallbacks(onStart, onFinish)
{
  onStartCb = onStart;
  onFinishCb = onFinish;
}

function setElementsDisplay(els, display)
{
  for (var i = 0; i < els.length; i++) {
    var el = (typeof(els[i]) == 'string') ? fbGetEl(els[i]) : els[i];
    if (el) {
      if (el.setStyle) {
	el.setStyle('display', display);
      } else {
	el.style.display = display;
      }
    }
  }
}

function showElements(els)
{
  setElementsDisplay(els, '');
}

function hideElements(els)
{
  setElementsDisplay(els, 'none');
}

function placeElement(el, x, y, animate, batch, extras /* = {} */)
{
  x = Math.floor(x) + 'px';
  y = Math.floor(y) + 'px';
  //console.log('placeElement ', el, ' x ', x, ' y ', y, ' animate ', animate);
  if (el.setStyle) {
    if (animate && Animation) {
      queueAniCallback(function() {
	el.setStyle({position: 'absolute', display: ''});
      });
      var ani = Animation(el).to('left', x).to('top', y);
      if (extras) {
	for (param in extras) {
	  ani.to(param, extras[param]);
	}
      }
      queueAnimation(ani);
      if (!batch) {
	startQueuedAnis();
      }
    } else {
      var params = extras || {};
      params.position = 'absolute';
      params.left = x;
      params.top = y;
      params.display = '';
      params.opacity = 1;
      el.setStyle(params);
    }
  } else {
    el.style.position = 'absolute';
    el.style.left = x + 'px';
    el.style.top = y + 'px';
  }
}



function makeImg(parentNode, src, left, top, styleParams)
{
  if (styleParams) {
    styleParams.position = 'absolute';
  } else {
    styleParams = {position:'absolute'};
  }
  return makeEl({elType:'img', src:src, parentNode:parentNode, left:left, top:top},
		styleParams);

}


function fbjsMakeEl(el, params, styleParams)
{
  if (params.id) el.setId(params.id);
  if (params.className) el.setClassName(params.className);
  if (typeof(params.left) != 'undefined') el.setStyle('left', params.left);
  if (typeof(params.top) != 'undefined') el.setStyle('top', params.top);
  if (params.src) el.setSrc(params.src);
  if (params.href) el.setHref(params.href);
  if (params.value) el.setValue(params.value);
  if (params.name) el.setName(params.name);
  if (params.type) el.setType(params.type);
  if (params.title) el.setTitle(params.title);
  if (params.rowSpan) el.setRowSpan(params.rowSpan);
  if (params.colSpan) el.setColSpan(params.colSpan);
  if (params.text) {
    if (typeof(params.text) == 'string') {
      el.setTextValue(params.text);
    } else {
      el.appendChild(params.text);
    }
  }
  if (styleParams) {
    el.setStyle(styleParams);
  }
  if (params.parentNode) {
    var parentEl;
    if (typeof(params.parentNode) == 'string') {
      parentEl = fbGetEl(params.parentNode);
    } else {
      parentEl = params.parentNode;
    }
    parentEl.appendChild(el);
  }
  return el;
}

function makeEl(params, styleParams)
{
  //console.log('makeEl, params ', params);
  var el;
  if (typeof(fbCreateEl) != 'undefined') {
    el = fbCreateEl(params.elType || 'div');
  } else {
    el = document.createElement(params.elType || 'div');
  }
  if (el.setStyle) {
    return fbjsMakeEl(el, params, styleParams);
  }
  if (params.id) el.id = params.id;
  if (params.className) el.className = params.className;
  if (params.text) el.appendChild(document.createTextNode(params.text));
  if (typeof(params.left) != 'undefined') el.style.left = params.left;
  if (typeof(params.top) != 'undefined') el.style.top = params.top;
  if (params.src) el.src = params.src;
  if (params.href) el.href = params.href;
  if (params.value) el.value = params.value;
  if (params.name) el.name = params.name;
  if (params.type) el.type = params.type;
  if (params.title) el.title = params.title;
  if (params.rowSpan) el.rowSpan = params.rowSpan;
  if (params.colSpan) el.colSpan = params.colSpan;
  if (styleParams) {
    for(var p in styleParams) {
      el.style[p] = styleParams[p];
    }
  }
  if (params.parentNode) {
    var parentEl;
    if (typeof(params.parentNode) == 'string') {
      parentEl = fbGetEl(params.parentNode);
    } else {
      parentEl = params.parentNode;
    }
    parentEl.appendChild(el);
  }
  return el;
}

function makeArray(param)
{
  var ret;
  if (typeof(param) == 'number') {
    ret = [];
    ret.length = param;
    return ret;
  } else {
    return [param];
  }
}

function setBg(el, color) {
  if (el.setStyle) {
    el.setStyle('backgroundColor', color);
  } else {
    el.style.backgroundColor = color;
  }
}

function getOffsetWidth(el)
{
    if (el.getOffsetWidth) {
	return el.getOffsetWidth();
    } else {
	return el.offsetWidth;
    }
}

function getOffsetHeight(el)
{
    if (el.getOffsetHeight) {
	return el.getOffsetHeight();
    } else {
	return el.offsetHeight;
    }
}

function getParentNode(el) {
  if (el.getParentNode) {
    return el.getParentNode();
  } else {
    return el.parentNode;
  }
}

function setClassName(el, className) {
  if (el.setClassName) {
    el.setClassName(className);
  } else {
    el.className = className;
  }
}

function getClassName(el) {
  if (el.getClassName) {
    return el.getClassName();
  } else {
    return el.className;
  }
}

function makeImage(src, className, idName)
{
  var ret = fbCreateEl('img');
  ret.setSrc(src);
  if (idName) {
    ret.setId(idName);
  }
  ret.setStyle({top:'0', left:'0'});
  setClassName(ret, className);
  return ret;
}

function removeAllChildNodes(el, deleteThem)
{
  if (typeof(el) == 'string') el = fbGetEl(el);
  // ES: getChildNodes is FB specific.
  ForEach(el.getChildNodes(), function(childNode) {
    el.removeChild(childNode);
    if (deleteThem) delete childNode;
  });
}


/******************************************************************************
 * Available params:
 *  onOk - Click callback
 *  messages - Array of strings or DOM elements (strings will be 'p's)
 *  title
 *  header
 *  buttons - list of buttons. If given, Okay button is hidden.
 ******************************************************************************/
function MakeDialog(params)
{
  fbGetEl('dialogTitle').setTextValue(params.title || "Scopa");
  fbGetEl('dialogHeader').setTextValue(params.header || "");

  var dialogMessageEl = fbGetEl('dialogMessage');
  removeAllChildNodes(dialogMessageEl, true);

  ForEach(params.messages, function(el) {
    if (typeof(el) == 'string') {
      makeEl({elType:'p', parentNode:dialogMessageEl, text:el});
    } else {
      dialogMessageEl.appendChild(el);
    }
  });
  var dialogEl = fbGetEl('dialog');
  if (params.buttons) {
    hideElements(['dialogOkCell']);
    var buttonRowEl = fbGetEl('dialogButtonRow');
    removeAllChildNodes(buttonRowEl, false);
    ForEach(params.buttons, function(buttonDesc) {
      var href = (typeof(buttonDesc.onClick) == 'string') ? buttonDesc.onClick : '#';
      var tdEl = makeEl({elType:'td', parentNode:buttonRowEl});
      var aEl = makeEl({elType:'a', href:href, text:buttonDesc.label, parentNode:tdEl});
      var onClickType = typeof(buttonDesc.onClick);
      if (onClickType == 'function' || onClickType == 'undefined') {
	makeEvent(aEl, 'click', function(event) {
	  this.purgeEventListeners('click');
	  if (onClickType == 'undefined' || buttonDesc.onClick()) {
	    dialogEl.setStyle('display', 'none');
	    // ES: Parameterize this.
	    if (typeof(catchupMessages) == 'function') {
	      catchupMessages();
	    }
	  }
	  return false;
	});
      }
    });
  } else {
    showElements(['dialogOkCell']);
    makeEvent(fbGetEl('dialogOk'), 'click',
	      function(event) {
		this.purgeEventListeners('click');
		if (params.onOk(event)) {
		  dialogEl.setStyle('display', 'none');
		  // ES: Parameterize this.
		  if (typeof(catchupMessages) == 'function') {
		    catchupMessages();
		  }
		}
		return false;
	      });
  }

  dialogEl.setStyle({display:'block', opacity:1});
}

function IsDialogUp()
{
  var dialogEl = fbGetEl('dialog');
  return (dialogEl && dialogEl.getStyle('display') == 'block');
}

////
// Returns a string describing a number of things. Like "a thing" or "2 things".
function oneOrMore(thing, n, suffix /* = 's' */,
		   singleSuffix /* = '' */)
{
  if (suffix == undefined) suffix = 's';
  if (singleSuffix == undefined) singleSuffix = '';
  if (n == 1) {
    return 'a ' + thing + singleSuffix;
  } else {
    return '' + n + ' ' + thing + suffix;
  }
}


// ES: Migrate over to using this namespace.

if (typeof(util) == 'undefined') {
  util = {};
}

util.httpRequest = function(url, params, isPost, // isPost is ignored for Facebook!
		       success, failure, responseType /* = Ajax.RAW */)
{
  if (typeof(Ajax) != 'undefined') {
    if (responseType == undefined) responseType = Ajax.RAW;
    var ajax = new Ajax();
    ajax.responseType = responseType;
    ajax.ondone = function(resp) {
      if (success) success(resp);
    };
    ajax.onerror = function() {
      if (failure) failure();
    };
    ajax.post(url, params);
  } else {
    doHttpRequest(url, params, isPost, success, failure);
  }
};

util.setDocumentLocation = function(newLocation)
{
  if (document.setLocation != undefined) {
    // In Facebook
    document.setLocation(newLocation);
  } else {
    document.location = newLocation;
  }
};

