/* Expects vars appid, server_root_url and server_root_common_url to
   be defined - normally in app.xml */

/* Track and redirect to profileURL of the app. Expects appid=NNN&w=source.
   May be useful for email messages in the future.
   
   Don't use it in MySpace messages - external URLs go through
   "phishing quarantine page" - looks ugly and scary. Internally, call
   server with 'stats' function instead. */
var trackCanvasURL = 'canvas.php';

var viewerID = "";
var viewerName = 'Unknown'; /* To be fetched */
var viewerProfileURL = "";
var viewerImageURL = "";
var viewerHasApp = false;
var viewerIsAdmin = false; /* Cache the admin flag */

var friendsMaxPageSize = 40; /* Max. allowed page size on MySpace */
/* Change in MySpace TOS: can only send one message per click, or 10
   app invites, but not more and not both */
var friendsMaxAppInvites = 10;
var friendsMaxMsgs = 10;
/* Backward compatibility */
var friendsMaxSelect = friendsMaxAppInvites;

/* App data fetched from the server */
var appInfo = { };

var menu_ids = [ ];

/* Variables defining app-specific classes and ids of the filler containers.
 * These can be modified in the app-specific .js file. */
var messages_send_id = "messages";
var users_send_id = "users";
var content_container_id = "content";

/* Create a cool spinning wheel or something for a loading page */
var loadingHTML = '<p>Loading...</p>';

/* Global display parameters */
var globalParams = {
  'pageNavTop' : true
  ,'pageNavBottom' : false
  ,'menuItemTag' : 'div'
  /* If true, select the same content again after the message has been sent */
  ,'sendMessageKeepContent' : false
  ,'noSentMsgs' : '<p>You\'ve sent no messages.<br/> Don\'t you have friends?</p><p><a href="javascript:" onclick="showSend({ })">Send them a note!</a></p>'
  ,'noSentMsgs' : '<p>You\'ve sent no messages.<br/> Don\'t you have friends?</p><p><a href="javascript:" onclick="showSend({ })">Send them a note!</a></p>'
  ,'noReceivedMsgs' : '<p>You\'ve got no messages.<br/> Don\'t you have friends?</p><p><a href="javascript:" onclick="showSend({ })">Send them a note!</a></p>'
};

/* Create showArgs class with a reset() function */
function showArgsReset() {
  debug("showArgsReset()");
  this.fn = "showReceived"; /* Name of the page render function */
  this.menu = ""; /* Current menu ID */
  this.page = 1;  /* Current page starting with 1 */
  this.total = 0; /* Total number of entries */
  this.friendsPage = 1; /* Current page of friends starting with 1 */
  this.friendsTotal = -1; /* Total number of friends. -1=undef (can be 0). */
  this.friends = { }; /* all friend objects, indexed by userid */
  this.friendIds = [ ]; /* all friend IDs, listed in order */
  this.inForm = 0; /* Displayed inside 'send message' form */
  /* map[userId=>bool] of selected users to send app invite or a message/comment */
  this.toUsersInvite = { };
  this.toUsersMsg = { };
  /* Counts of selected users to send app invite and message/comment */
  this.usersInviteCount = 0;
  this.usersMsgCount = 0;
  this.sentInvites = 0; /* Track how many invites have been actually sent */
  this.sentMsgs = 0; /* Track how many messages have been actually sent */
  this.messages = [ ]; /* Message objects currently displayed - for forwarding */
  this.messageSelected = -1; /* Selected message - the index in the above array */
}

function showArgsObj() {
  debug("showArgsObj()");
  this.reset = showArgsReset;
  this.reset();
}

var showArgs = new showArgsObj;

function myToStr(obj) {
  if(obj === undefined) { return 'undefined'; }
  if(obj === null) { return 'null'; }
  if(typeof(obj) == 'object') {
    var fields = [ ];
    for(x in obj) { fields.push('"' + x + '" : "' + obj[x] + '"'); }
    return "{ " + fields.join(', ') + " }";
  } else {
    return obj.toString();
  }
}

/* Clone any object */
function clone(obj) {
  var newObj = (obj instanceof Array) ? [] : {};
  for (i in obj) {
    if (obj[i] && typeof obj[i] == "object") {
      newObj[i] = clone(obj[i]);
    } else newObj[i] = obj[i];
  }
  return newObj;
}

function debug(str) {
  var d = document.getElementById('debug');
  if(d != null) d.innerHTML += '<p>'+gadgets.util.escapeString(str)+"<\p>";
}

/* Show / hide the debug window */
function toggleDebug() {
  var d = document.getElementById('debug_window');
  if(d != null) {
    d.style.visibility = (d.style.visibility == "visible")? "hidden" : "visible";
  }
}
function closeDebug() {
  var d = document.getElementById('debug_window');
  if(d != null) {
    d.style.visibility = "hidden";
  }
}

/* Initialize the debugging window */
function initDebug() {
  var debug = document.getElementById('debug_window');
  if(debug != null) {
    debug.innerHTML = '<h3>Debugger</h3>'
      +'<div class="debug_cross">'
      + '<a href="javascript:;" onclick="clearDebug();">Clear window</a>'
      +' <a href="javascript:;" onclick="closeDebug();">Close</a></div>'
      + '<div id="debug" class="debug"></div>';
    /* debug.style.visibility = "visible"; */
  }
}

function disableDebug() {
  var debug = document.getElementById('debug_window');
  if(debug != null) {
    debug.innerHTML = '<h3>Debugger is off</h3>'
      +'<div class="debug_cross">'
      + '<a href="javascript:;" onclick="clearDebug();">Clear window</a>'
      +' <a href="javascript:;" onclick="closeDebug();">Close</a></div>';
  }
}

/* Clear the debugging window */
function clearDebug() {
  var debug = document.getElementById('debug');
  if(debug != null) {
    debug.innerHTML = '';
  }
}

/* Work-around the IE bug: document.getElemntsByName() doesn't work */
function myGetElementsByName(tag, name) {
  var tags = document.getElementsByTagName(tag);
  debug('myGetElementsByName('+tag+', '+name+')');
  var res = new Array();
  var i_52;
  /* Make iteration var unique */
  for(i_52=0; i_52<tags.length; ++i_52) {
    if(tags[i_52].getAttribute('name') == name) {
      res.push(tags[i_52]);
    }
  }
  return res;
}

/* Activate overlay and display 'html' in it */
function showOverlay(html) {
  var d = document.getElementById('overlay');
  if(d == null) {
    debug('showOverlay(): overlay is not found!');
    return;
  }
  d.style.display = 'block';
  d.innerHTML = '<div class="overlay_shadow"></div>'
    +'<div class="overlay_contents">'+html+'</div>';
}

function hideOverlay() {
  var d = document.getElementById('overlay');
  if(d == null) {
    debug('hideOverlay(): overlay is not found!');
    return;
  }
  d.style.display = 'none';
}

/* Ask for action and display action and cancel buttons in the
   overlay. 'text' is the description of the action, 'actionName' is
   the name of the action button, 'fn' is the javascript function to
   call to perform the action. */
function confirmAction(text, actionName, fn) {
  var html = '<table width="100%"><tr><td colspan="2" style="padding-bottom:30px">'
    +text+'</td></tr>'
    +'<td align="center"><button onclick="hideOverlay(); '
    +fn+'()">'+actionName+'</button></td>'
    + '<td align="center"><button onclick="hideOverlay()">Cancel</button></td>'
    +'</tr></table>';
  showOverlay(html);
}

/* Overlay with a bunch of buttons mapped to actions. Cancel button is NOT ADDED. */
function confirmActions(text, actionMap) {
  var html = '<table width="100%"><tr><td style="padding-bottom:30px">'
    +text+'</td></tr>'
    +'<td align="center">';
  for(var name in actionMap) {
    html += '<button onclick="hideOverlay(); '+actionMap[name]+'">'+name+'</button> ';
  }
  html += '</td></tr></table>';
  showOverlay(html);
}

/* Show a message in an overlay with an 'OK' button */
function alertOverlay(text) {
  var html = '<table width="100%"><tr><td style="padding-bottom:30px">'
    +text+'</td></tr>'
    +'<td align="center"><button onclick="hideOverlay()">OK</button></td>'
    +'</tr></table>';
  showOverlay(html);
}

function serverRequestUrl(url, onResponse, postdata) {
  var params = {};
  params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
  /* Should be JSON, but it doesn't seem to parse it anyway */
  params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;
  /* FIXME: must be SIGNED, but doesn't work on MySpace (?) */
  params[gadgets.io.RequestParameters.AUTHENTICATION] = gadgets.io.AuthorizationType.SIGNED;
  /* Add appid to every request, unless already there */
  if(postdata.appid == null) {
    postdata.appid = (appid_master != 0)? appid_master : appid;
    debug('serverRequest: set appid = '+postdata.appid);
  }
  var posttext = gadgets.io.encodeValues(postdata);
  params[gadgets.io.RequestParameters.POST_DATA] = posttext;

  debug("serverRequest(): " + server_root_common_url + url + "?" + posttext);
  gadgets.io.makeRequest(server_root_common_url + url, function (response) {
      debug("serverRequest => onResponse(" + myToStr(response) + ')');
      if(typeof(response.errorMessage) == 'string') {
	debug("Error: "+response.errorMessage);
	onResponse({ error: true, errorMessage : response.errorMessage });
      } else {
	var data = gadgets.json.parse(response.text);
	onResponse(data);
      }
    }, params);
}

function serverRequest(onResponse, postdata) {
  serverRequestUrl('query.php', onResponse, postdata);
}

function updateStats(referrer, count) {
  var postdata = { 'fn' : 'stats',
		   'referrer' : referrer,
		   'count' : count };
  serverRequest(function (r) { }, postdata);
}

/* Check if the current viewer is an app admin */
function isAdmin() {
  /* FIXME: DEBUG */ /* return true; */
  debug('isAdmin() => '+viewerIsAdmin);
  return viewerIsAdmin;
}

/* Fetch OpenSocial.Person structure for the userid, 
   and pass it to the callback */
function getUserData(userid, callback) {
  var os = opensocial.Container.get();  
  var dataReqObj = os.newDataRequest();
  var userReq = os.newFetchPersonRequest(userid);
  dataReqObj.add(userReq, userid);
  dataReqObj.send(function (response) {
      if(response.hadError()) {
	debug('getUserData: error fetching user ('+userid+'): '
	      +response.getErrorMessage());
	return;
      }
      var tmp = response.get(userid);
      if(tmp.hadError()) {
	debug('getUserData: error[2] fetching user ('+userid+'): '
	      +response.getErrorMessage());
	return;
      }
      var user = tmp.getData();
      user.nick = gadgets.util.escapeString(user.getDisplayName());
      callback(user);
    });
}

/* The ad object to display - delay ad init till we're all done,
   especially for SocialReach */
var randomAd = { 'html' : '' };

function initAd(randomAd) {
  /* Init SocialReach ads */
  /* debug('initAd(initFn='+randomAd['initFn']+')'); */
  if(randomAd['initFn'] == 'sr_gof') sr_gof();
}

function init() {
  /* Create the basic HTML structure within div#canvas */
  var d = document.getElementById('canvas');
  /* Save debug message until debugger is initialized */
  var debugMsg = 'init(): server_root_url='+server_root_url;
  debugMsg += ', server_root_common_url='+server_root_common_url;
  if(typeof(server_root_url) == 'undefined' || server_root_url == null) {
    server_root_url='http://www.hitbyapple.com/myspace_apps/';
    server_root_common_url=server_root_url+'common/';
    debugMsg += '<br>init(): Updated: server_root_url='+server_root_url;
  }
  /* Split testing ads - load SocialReach 50% of the time */

  var ads = new Array;
  if(typeof(getAds) == 'function') ads = getAds();
  else {
    /* SocialReach */
    var ad1 = { 'html' : '<div id="sr_6111_728x90"></div>'
		,'initFn' : 'sr_gof'
		/* ,'js' : 'http://ads.socialreach.com/msfa.js.php' */ };
    ads.push(ad1);
    /* other ads */
    var ad2 = { 'html' : '<iframe width="100%" frameborder="0" src="'
		+server_root_common_url+'ads800x120.php?appid='+appid+'"></iframe>' };
    /* Remove these - SocialReach seems to be the best */
    /* ads.push(ad2); */
  }
  randomAd = ads[Math.floor(Math.random()*ads.length)];
  /* This will not work */
  /* if(randomAd['js']) loadjscssfile(randomAd['js'], 'js'); */

  d.innerHTML = '<div id="ads800x120">'
    +randomAd['html']
    +'</div> <!-- end of ads800x120 -->'
    +'<div id="my_ad"><iframe width="100%" frameborder="0" src="'
    +server_root_common_url+'my_ad.php?appid='+appid+'"></iframe></div>'
    +'<div id="debug_window" class="debug_window"></div>'
    +'<div id="overlay" class="overlay"></div>'
    +'<div id="app_core">'
    +'<div id="menu"></div>'
    +'<div id="main"></div>'
    +'</div> <!-- end of app_core -->';

  /* Debug window: originally hidden from view.
   * FIXME: remove from here, init in the menu - save memory */
  initDebug();
  /* Dump saved debug message now */
  debug(debugMsg);

  var os = opensocial.Container.get();  
  var dataReqObj = os.newDataRequest();
  var viewerReq = os.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER);
  dataReqObj.add(viewerReq, 'viewer');
  dataReqObj.send(onInitViewer); 
}

/* Call optional hook function with up to 3 optional arguments. We
   cheat here - only give one fake args parameter, but actually get
   the values from the 'arguments' array */
function call_hook(fn, args) {
  debug('call_hook('+fn+', ['+(arguments.length-1)+'])');
  if(typeof(this[fn]) == 'function') {
    /* Figure out the number of args */
    var n = arguments.length-1; /* fn is arguments[0] */
    if(n == 0) return this[fn]();
    if(n == 1) return this[fn](arguments[1]);
    if(n == 2) return this[fn](arguments[1], arguments[2]);
    if(n >= 3) return this[fn](arguments[1], arguments[2], arguments[3]);
  } else {
    debug('call_hook: '+fn+' is not a function');
    return null;
  }
}

var defaultMenuFn = 'null';

function activateDefaultMenu() {
  debug('activateDefaultMenu: '+defaultMenuFn);
  eval(defaultMenuFn);
}

/* Initialize the app for a guest user (limited functionality) */
function initGuest() {
  debug('initGuest()');
  viewerID = 'guest';
  viewerName = 'guest';
  viewerHasApp = false;
  var postdata = { 'fn' : 'getAppInfo' };
  serverRequest(function (r) { if(!r.error) appInfo = r; }, postdata);
  activateDefaultMenu();
}

function showAddApp(text) {
  if(text == null)
    text = 'Add this app for full functionality, or try it as a guest.';
  confirmAction(text, 'Try it!', 'initGuest');
}

function showMenu() {
  debug('showMenu()');
  var menu = document.getElementById('menu');
  menu.innerHTML = formatMenu(getMenuContent());
}

function onInitViewer(dataResponse) {
  debug("onInitViewer("+myToStr(dataResponse)+")");
  if(dataResponse.hadError() || dataResponse.get('viewer').hadError()) {
    call_hook('init_hook');
    showMenu();
    showAddApp();
    initAd(randomAd);
    return;
  }

  var viewerData = dataResponse.get('viewer').getData();
  call_hook('init_hook', viewerData);
  showMenu();
  /* debug('viewerData = '+myToStr(viewerData));
     debug('viewerData.fields_ = ' + myToStr(viewerData.fields_)); */
  viewerName = gadgets.util.escapeString(viewerData.getDisplayName());
  viewerID = viewerData.getId();
  viewerProfileURL = viewerData.getField('profileUrl');
  viewerImageURL = viewerData.getField('thumbnailUrl');
  /* hasApp doesn't work ??? */
  /* viewerHasApp = viewerData.getField('hasApp'); */

  /* Assume viewer has the app - otherwise we can't fetch this */
  viewerHasApp = true;

  debug("viewerName = " + viewerName);
  debug("viewerID = " + viewerID);
  debug("viewerProfileURL = " + viewerProfileURL);
  debug("viewerImageURL = " + viewerImageURL);
  debug("viewerHasApp = " + viewerHasApp);

  /* Send the user info to the server */
  var postdata = { 'fn' : 'setUserInfo',
		   'userid' : viewerID,
		   'nick' : viewerName,
		   'profileURL' : viewerProfileURL,
		   'thumbnailURL' : viewerImageURL };
  serverRequest(function (r) { }, postdata);
  /* Fetch common app data from the server */
  postdata = { 'fn' : 'getAppInfo' };
  serverRequest(function (r) { if(!r.error) appInfo = r; }, postdata);
  activateDefaultMenu();
  initAd(randomAd);
}

/************************************************************/
/*********************** TOP MENU ***************************/
/************************************************************/

function formatMenu(menuItems) {
  var i_menu;
  var items = new Array;
  menu_ids = [ ];
  for(i_menu=0; i_menu < menuItems.length; ++i_menu) {
    var m = menuItems[i_menu];
    var func;
    if(m.id == 'send') {
      func = 'showSend({ })';
      if(m.default_menu == true) {
	defaultMenuFn = func;
      }
    } else if(m.id == 'sent') {
      func = 'showSent(1)';
      if(m.default_menu == true) {
	defaultMenuFn = func;
      }
    } else if(m.id == 'received') {
      func = 'showReceived(1)';
      if(m.default_menu == true) {
	defaultMenuFn = func;
      }
    } else if(m.id == 'content') {
      func = 'showContent({ })';
      if(m.default_menu == true) {
	defaultMenuFn = func;
      }
    } else if(m.id == 'postContent') {
      func = 'showPostContent()';
      if(m.default_menu == true) {
	defaultMenuFn = func;
      }
    } else if(m.id == 'admin') {
      func = 'showAdmin(1)';
      if(m.default_menu == true) {
	defaultMenuFn = func;
      }
    } else if(m.id == 'debug') {
      func = 'toggleDebug()'; /* initDebug(); */
    }
    else {
      func = 'showCustomPage(\''+m.id+'\')';
      if(m.default_menu == true) {
	defaultMenuFn = func;
      }
    }
    var cls = (showArgs.menu == 'menu_'+m.id)? ' class="menu_current"' : '';
    debug('formatMenu(): current: '+showArgs.menu+', m.id='+m.id+', class: '+cls);
    var itag = globalParams['menuItemTag'];
    items.push('<li><a href="javascript:;" onclick="'+func
	       +'"><'+itag+' id="menu_'+m.id+'"'+cls+'>'+m.name+'</'+itag+'></a></li>');
    menu_ids.push('menu_'+m.id);
  }
  return '<ul>'+items.join('')+'</ul>';
}

function menuSelect(menuId) {
  var i;
  showArgs.menu = menuId;
  for(i = 0; i<menu_ids.length; ++i) {
    var m = document.getElementById(menu_ids[i]);
    if(menuId == menu_ids[i]) m.className = 'menu_current';
    else m.className = '';
  }
}

/************************************************************/
/************** SEND MESSAGE PAGE ***************************/
/************************************************************/

/* Pre-selected message to display on the page (for forwarding / replies) */
var showSendParams = null;

function showSend(params) {
  debug('showSend('+myToStr(params)+')');
  showSendParams = params;
  showArgs.reset();
  menuSelect('menu_send');
  document.getElementById('main').innerHTML = formatSendPage();
  if(params['displayContent'] === false) {
    if(params.message != null) selectMessageSend(params.message);
  } else {
    displayContentToSend(1);
  }
  displayFriendsToSend(1, params);
  if(params.statusMessage) displayStatus(params.statusMessage, params.status);
}

function formatPagingBar(page, pageSize, total, fn) {
  var pages = Math.ceil(total / pageSize);
  if(pages <= 1) {
    return '<div id="pagenav"><ul class="pagenav">'
      +'<li><span class="inactive">&laquo; Prev</span></li>'
      +'<li><span class="current">1</span></li>'
      +'<li><span class="inactive">Next &raquo;</span></li>'
      +'</ul></div>';
  }
  var pageNav = '<div id="pagenav"><ul class="pagenav">';
  if(page > 1) {
    var prevPage = page-1;
    pageNav += '<li><a href="javascript:;" onclick="' + fn + '(' + prevPage +');">&laquo; Prev</a></li>';
  }
  else {
    pageNav += '<li><span class="inactive">&laquo; Prev</span></li>';
  }
  /* Array of page #s to display */
  pageNums = [ 1 ]; /* Page 1 is always there */
  for(i=page-2; i<=page+2; ++i) {
    if(i<=1) { i=1; continue; }
    if(i>pages) { break; }
    pageNums.push(i);
  }
  if(pageNums[pageNums.length-1] != pages) { pageNums.push(pages); }
  var nextPage=1;
  for(i=0; i<pageNums.length; ++i) {
    p=pageNums[i];
    if(p!=nextPage) {
      pageNav += '<li><span class="gap">&hellip;</span></li>';
      nextPage = p;
    }
    ++nextPage;
    if(p == page) {
      pageNav += '<li><span class="current">'+p+'</span></li>';
    } else {
      pageNav += '<li><a href="javascript:;" onclick="' + fn + '(' + p +')">'+p+'</a></li>';
    }
  }
  if(page < pages) {
    var nextPage = page + 1;
    pageNav += '<li><a href="javascript:;" onclick="' + fn + '(' + nextPage +')">Next &raquo;</a></li>';
  }
  else {
    pageNav += '<li><span class="inactive">Next &raquo;</span></li>';
  }
  pageNav += '</div>\n';
  return pageNav;
}

/* Fetch 'page' of content objects from the server, update the progress bar,
   and return the list of message objects through the callback()
   function */
function displayContentToSend(page) {
  var d = document.getElementById(messages_send_id);
  d.innerHTML = loadingHTML;
  showArgs.fn = 'displayContentToSend';
  showArgs.page = page;
  showArgs.inForm = 1;
  var postdata = { 'fn' : 'getContent',
		   'userid' : viewerID,
		   'page' : page,
		   'pageSize' : pageSize };
  if(showSendParams['sortby'] != null) {
    postdata['sortby'] = showSendParams['sortby'];
  }
  if(showSendParams['category'] != null) {
    postdata['category'] = showSendParams['category'];
  }
  /* If there is a master app, get the content from the master */
  if(appid_master != 0) postdata['appid'] = appid_master;
  serverRequest(onDisplayContentToSend, postdata);
}

function onDisplayContentToSend(response) {
  var d = document.getElementById(messages_send_id);
  if(response.error) {
    d.innerHTML =
      '<p class="error">Error: couldn\'t fetch the data - '
      + response.errorMessage+'.<br/>'
      +' Please <a href="javascript:;" onclick="' + showArgs.fn
      +'('+showArgs.page+')">try again</a> or report a bug</p>';
    return;
  }
  if(response.content == null || response.content.length == 0) {
    d.innerHTML = '<p>No content found</p>';
    return;
  }
  var pageNav = formatPagingBar(showArgs.page, pageSize,
				response.unlocked, showArgs.fn);
  if(globalParams['pageNavTop']) d.innerHTML = pageNav;
  showArgs.messages = response.content;
  var i;
  var contentArray = [ ];
  for(i=0; i<response.content.length; ++i) {
    var c = response.content[i];
    var item = '<li><a href="javascript:" onclick="onclickSelectMessageSend('+i+')">'
      +formatMessageSend(c)+'</a></li>';
    contentArray.push(item);
  }
  d.innerHTML += '<ul class="chooser">'+contentArray.join('')+'</ul>';
  if(globalParams['pageNavBottom']) d.innerHTML += pageNav;
  // Select the first one
  if(showSendParams != null && showSendParams.message != null) {
    selectMessageSend(showSendParams.message);
  } else {
    onclickSelectMessageSend(0);
  }
  call_hook('updateUnlocked', response);
  if(response.admin == 1) {
    viewerIsAdmin = true;
    showMenu(); /* Redraw the menu - it may change for admins */
  }
}

function onclickSelectMessageSend(i) {
  var msg = showArgs.messages[i];
  /* Provide the default text for the message */
  if(msg.content_text == null) msg.content_text = msg.text;
  selectMessageSend(msg);
}

/* Fetch friends starting from 'first'. If 'has_app' is true,
   fetch only those who have the app, and update the already fetched ones. */
function fetchFriends(page, has_app) {
  debug('fetchFriends(page='+page+', has_app='+has_app+')');
  var os = opensocial.Container.get();  
  var req = os.newDataRequest();  
  var idspec = opensocial.newIdSpec({ "userId" : "VIEWER", "groupId" : "FRIENDS" });
  var opts = { };
  /* FIXME: fetch ALL friends (may have to iterate through pages) and all friends with the app, then sort it out, then display one page from local cache. */
  opts[opensocial.DataRequest.PeopleRequestFields.MAX] = friendsMaxPageSize;
  opts[opensocial.DataRequest.PeopleRequestFields.FIRST] = (page-1)*friendsMaxPageSize+1;
  if(has_app) {
    opts[opensocial.DataRequest.PeopleRequestFields.FILTER] = opensocial.DataRequest.FilterType.HAS_APP;
  }
  var viewerReq = os.newFetchPeopleRequest(idspec, opts);
  req.add(viewerReq, 'friends');
  /* Use dynamic recursive function call. Reminds me of good old SML days :-) */
  req.send(function (response) {
      if(!response ||response.hadError() || response.get('friends').hadError()) {
	showArgs.friendsTotal=-1;
	var d = document.getElementById(users_send_id);
	if(typeof(d) == 'object') d.innerHTML = 'No friends?...';
	return;
      }
      var friendsObj = response.get('friends').getData();
      var total = friendsObj.getTotalSize();
      var friends = friendsObj.asArray();
      debug('onFetchFriends(total='+total+', #friends='+friends.length
	    +', has_app='+has_app+')');
      if(has_app) { /* Update the data structures */
	for(var i in friends) {
	  showArgs.friends[friends[i].getId()].has_app = true;
	}
      } else { /* Populate the data structures */
	showArgs.friendsTotal = total;
	for(var i in friends) {
	  var f = friends[i];
	  f.has_app = false;
	  f.nick = gadgets.util.escapeString(f.getDisplayName());
	  showArgs.friends[f.getId()] = f;
	  showArgs.friendIds.push(f.getId());
	}
      }
      /* Recursive calls. Note: MySpace screws up the total count with filters.
	 We have to page through all the friends to find all those filtered. */
      if(page*friendsMaxPageSize < showArgs.friendsTotal)
	fetchFriends(page+1, has_app);
      else if(!has_app) fetchFriends(1, true);
      else displayFriendsToSend(showArgs.friendsPage, showSendParams); /* Done - call back */
    });
}

/* Hold the value of a user to select when we fetch the friends */

function displayFriendsToSend(page, params) {
  showArgs.friendsPage = page;
  showSendParams = params;
  /* Optional parameters: 'userid' - make that friend the only one selected */
  if(params) {
    if(params.userid != null) {
      debug('displayFriendsToSend(): set selectUser = '+params.userid);
      showArgs.usersInviteCount = 0;
      showArgs.usersMsgCount = 0;
      showArgs.toUsersInvite = { };
      showArgs.toUsersMsg = { };
    }
  }
  var d = document.getElementById(users_send_id);
  d.innerHTML = loadingHTML;
  if(showArgs.friendsTotal < 0) {
    fetchFriends(1, false);
    /* Return for now. We'll get called again when fetching is done. */
    return;
  }
  /* Deal with the parameters */
  if(showSendParams != null && showSendParams.userid != null) {
    var userid = showSendParams.userid;
    var f = showArgs.friends[userid];
    if(f != null) {
      if(f.has_app) {
	showArgs.toUsersMsg[userid] = true; 
	showArgs.usersMsgCount = 1;
      } else {
	showArgs.toUsersInvite[userid] = true;
	showArgs.usersInviteCount = 1;
      }
    }
  }
  var first = (page-1)*friendsPageSize;
  var end = first+friendsPageSize;
  if(end > showArgs.friendsTotal) end = showArgs.friendsTotal;
  d.innerHTML = formatPagingBar(showArgs.friendsPage, friendsPageSize,
				showArgs.friendsTotal, 'displayFriendsToSend');
  var friendsHTML = [ ];
  var selectedIds = [ ];
  for(var i=first; i<end; ++i) {
    var id = showArgs.friendIds[i];
    var f = showArgs.friends[id];
    var html = '<td><a class="user_thumb" href="javascript:" onclick="onclickFriendToSend(\''+id
      +'\')" title="'+f.nick+'">'+formatFriendSend(f)+'</a></td>';
    friendsHTML.push(html);
    if(isUserSelected(id)) selectedIds.push(id);
  }
  var row; var col;
  var html = '<table border="0">';
  for(row = 0; row < friendsRows; ++row) {
    html += '<tr>';
    for(col = 0; col < friendsCols; ++col) {
      var i = row*friendsCols+col;
      if(i < friendsHTML.length) html += friendsHTML[i];
      else html += '<td></td>';
    }
    html += '</tr>';
  }
  html += '</table>';
  d.innerHTML += html;
  /* Display the already selected friends */
  for(i in selectedIds) {
    call_hook('selectUserSend', showArgs.friends[selectedIds[i]]);
  }
}

/* Search showArgs.toUsers array */
function isUserSelected(id) {
 return (showArgs.toUsersInvite[id] === true || showArgs.toUsersMsg[id] === true);
}

/* Return true on success, false on failure (too many users selected) */
function addUserSelected(id, has_app) {
  debug('addUserSelected('+id+', has_app='+has_app+')');
  if(!has_app) {
    if(showArgs.usersInviteCount >= friendsMaxAppInvites) return false;
    showArgs.toUsersInvite[id] = true;
    showArgs.usersInviteCount++;
  } /* Send message regardless */
  if(showArgs.usersMsgCount >= friendsMaxMsgs) return false;
  showArgs.toUsersMsg[id] = true;
  showArgs.usersMsgCount++;
  return true;
}

function removeUserSelected(id, has_app) {
  debug('removeUserSelected('+id+', has_app='+has_app+')');
  if(showArgs.toUsersInvite[id]) {
    showArgs.toUsersInvite[id] = false;
    showArgs.usersInviteCount--;
  }
  if(showArgs.toUsersMsg[id] === true) {
    showArgs.toUsersMsg[id] = false;
    showArgs.usersMsgCount--;
  }
}

/* Return one of the selected user IDs, or false */
function findUserSelected() {
  var user = false;
  for(var id in showArgs.toUsersInvite) {
    if(showArgs.toUsersInvite[id]) user = id;
  }
  if(user) return user;
  for(var id in showArgs.toUsersMsg) {
    if(showArgs.toUsersMsg[id]) user = id;
  }
  return user;
}

function onclickFriendToSend(id) {
  debug('onclickFriendToSend('+id+')');
  var friend = showArgs.friends[id];
  if(typeof friend != 'object') {
    debug('onclickFriendToSend('+id+'): friend not found');
    return;
  }
  if(isUserSelected(id)) {
    removeUserSelected(id, friend.has_app);
    /* Pick a remaining selected user, if any, and deselect the current one */
    var otherUser = findUserSelected();
    if(otherUser) otherUser = showArgs.friends[otherUser];
    var params = {user: otherUser,
		  inviteCount: showArgs.usersInviteCount,
		  messageCount: showArgs.usersMsgCount};
    call_hook('deselectUserSend', friend, params);
  } else { /* Not selected - select now */
    if(addUserSelected(id, friend.has_app)) {
      var params = {user: friend,
		    inviteCount: showArgs.usersInviteCount,
		    messageCount: showArgs.usersMsgCount};
      call_hook('selectUserSend', friend, params);
    } else {
      displayStatus('Max number of friends already selected', 'error');
    }
  }
}

function sendMessage(message) {
  if(!viewerHasApp) {
    showAddApp('Add this app to send a message, or try it with limited functionality as a guest');
    return;
  }
  var text = message.text;
  var content_id = message.content_id;
  if(!content_id) content_id = message.id;
  var toUsersInvite = [ ]; /* Compute from selected friends */
  var toUsersMsg = [ ]; /* Compute from selected friends */
  var toUsers = [ ]; /* Union of the two */
  for(var id in showArgs.toUsersInvite) {
    if(showArgs.toUsersInvite[id]) {
      toUsersInvite.push(id);
      toUsers.push(id);
    }
  }
  for(var id in showArgs.toUsersMsg) {
    if(showArgs.toUsersMsg[id]) {
      toUsersMsg.push(id);
      if(!showArgs.toUsersInvite[id]) toUsers.push(id);
    }
  }
  if(toUsers.length == 0) {
    displayStatus('Please select some friends', 'error');
    return;
  }
  postdata = { 'fn' : 'sendMessage',
	       'contentid' : content_id,
	       'text' : text,
	       'fromUser' : viewerID,
	       'toUsers' : toUsers.join(',') };
  displayStatus('Sending message&hellip;', 'warning');
  serverRequest(function (response) {
      if(!response.error) {
	displayStatus('Your message has been sent.');
	/* Send invites and MySpace messages/comments. This function also clears the list of friends to whome messages have actually been sent, and re-displays the list of friends. */
	sendAppInvitesAndMessages(toUsersInvite, toUsersMsg, message);
      } else {
	displayStatus('Error: message was NOT sent. Please try again.', 'error');
      }
    }, postdata);
}

function makeExcerpt(text, size) {
  if(text.length > size) {
    return text.substring(0, size-3)+'...';
  }
  return text;
}

var sendMessagesParams = { };

/* Daisy-chain the sends */
function sendAppInvitesAndMessages(usersInvite, usersMsg, msg) {
  showArgs.sentInvites = 0;
  showArgs.sentMsgs = 0;
  sendMessagesParams = {'usersInvite' : usersInvite,
			'usersMsg' : usersMsg,
			'msg' : msg };
  if(usersInvite.length > 0) {
    var actionMap = { 'Send App Invites': 'sendAppInvitesAction(1)',
		      'Skip Invites' : 'sendAppInvitesAction(0)',
		      'Cancel All' : 'refreshSendPageAction()' };
    var confirmMsg = 'You\'ve sent a message, but '+usersInvite.length+' of your friends do not have this App installed. Invite them to the App!';
    if(typeof formatAppInviteQuestion == 'function') {
      confirmMsg = formatAppInviteQuestion(usersInvite);
    }
    confirmActions(confirmMsg, actionMap);
  } else {
    sendUserMessages(usersMsg, msg);
  }
}

/* If confirmed==true, send app invites, followed by
   messages. Otherwise, just send messages. Needed data is stored in
   sendMessagesParams. */
function sendAppInvitesAction(confirmed) {
  var msg = sendMessagesParams['msg'];
  var usersInvite = sendMessagesParams['usersInvite'];
  var usersMsg = sendMessagesParams['usersMsg'];
  if(confirmed) {
    var params = { }; /* Don't realy need any params */
    var text = formatAppInvite(msg);
    var message = opensocial.newMessage(text, params);
    opensocial.requestShareApp
      (usersInvite, message,
       function(response){
	 debug('requestShareApp('+myToStr(response)+')');
	 if(!response.hadError()) showArgs.sentInvites = response.getData();
	 updateStats('app invites', showArgs.sentInvites);
	 sendUserMessages(usersMsg, msg);
       });
  } else {
    sendUserMessages(usersMsg, msg);
  }
}

/* Recursive function: sends to the first user in the list and calls
 itself from the call-back with the remaining users.  MySpace does not
 support multiple recepients for messages, so we daisy-chain the
 requests. */
function sendUserMessages(userids, msg) {
  if(userids.length == 0) {
    if(showArgs.menu == 'menu_send') refreshSendPage(msg);
    return;
  }
  var user = userids.shift(); /* Removes and returns first user */
  sendMessagesParams = { 'user' : user,
			 'userids' : userids,
			 'msg' : msg };
  var actionMap = { 'Post Comment': 'sendUserMessageAction(1)',
		    'Skip This Friend' : 'sendUserMessageAction(0)',
		    'Skip All' : 'refreshSendPageAction()' };
  var confirmMsg = 'Post a comment about your message to your friend\'s profile, '
    +showArgs.friends[user].nick+' ('+userids.length+' more remaining):';
  if(typeof formatUserCommentQuestion == 'function') {
    confirmMsg = formatUserCommentQuestion(user, userids);
  }
  confirmActions(confirmMsg, actionMap);
}

function sendUserMessageAction(confirmed) {
  var user = sendMessagesParams['user'];
  var userids = sendMessagesParams['userids'];
  var msg = sendMessagesParams['msg'];
  if(confirmed) {
    var params = { };
    /* Profile comment */
    params[opensocial.Message.Field.TYPE] = opensocial.Message.Type.PUBLIC_MESSAGE;
    /* TITLE doesn't show in profile comments */
    /* params[opensocial.Message.Field.TITLE] = viewerName+' sent you a beautiful fractal'; */
    var text = formatUserComment(msg);
    debug('sendUserMessages(): text = "'+text+'"');
    var message = opensocial.newMessage(text, params);
    opensocial.requestSendMessage
      (user, message,
       function(response){
	 debug('requestSendMessage('+myToStr(response)+')');
	 if(!response.hadError() && response.getData() > 0) {
	   showArgs.sentMsgs += response.getData();
	   updateStats('comments', response.getData());
	 }
	 sendUserMessages(userids, msg);
       });
  } else { /* Skip this user, send to the rest */
    sendUserMessages(userids, msg);
  }
}

function refreshSendPageAction() {
  var msg = sendMessagesParams['msg'];
  refreshSendPage(msg);
}

function refreshSendPage(msg) {
  /* Recompute the counts */
  var sentTotal = showArgs.sentInvites + showArgs.sentMsgs;
  var params = { statusMessage: 'Your message has been sent. '+sentTotal+' friends notified.'};
  if(showSendParams['displayContent'] === false) params['displayContent'] = false;
  if(globalParams['sendMessageKeepContent']) params['message'] = msg;
  showSend(params);
  call_hook('sendMessageHook', msg);
}

/************************************************************/
/************** SENT MESSAGES PAGE **************************/
/************************************************************/

function showSent(page) {
  if(!viewerHasApp) {
    showAddApp('Add this app to view messages you\'ve sent, or continue exploring it as a guest.');
    return;
  }
  showArgs.reset();
  menuSelect('menu_sent');
  document.getElementById('main').innerHTML = formatSentPage();
  displayContentSent(1);
}

function displayContentSent(page) {
  var d = document.getElementById(messages_send_id);
  d.innerHTML = loadingHTML;
  showArgs.fn = 'displayContentSent';
  showArgs.page = page;
  var postdata = { 'fn' : 'getMessages',
		   'kind' : 'sent',
		   'userid' : viewerID,
		   'page' : page,
		   'pageSize' : pageSize };
  serverRequest(onDisplayContentSent, postdata);
  /* Fetch user info to update the unlocked progress bar */
  postdata = { 'fn' : 'getUserInfo',
	       'userid' : viewerID };
  serverRequest(function (r) {
      if(!r.error) {
	if(r.admin == 1) {
	  viewerIsAdmin = true;
	  showMenu(); /* Redraw the menu - it may change for admins */
	}
	call_hook('updateUnlocked', r);
      }
    },
    postdata);
}

function onDisplayContentSent(response) {
  var d = document.getElementById(messages_send_id);
  if(response.error) {
    d.innerHTML =
      '<p class="error">Error: couldn\'t fetch the data - '
      + response.errorMessage+'.<br/>'
      +' Please <a href="javascript:;" onclick="' + showArgs.fn
      +'('+showArgs.page+')">try again</a> or report a bug</p>';
    return;
  }
  if(response.total <= 0) {
    d.innerHTML = globalParams['noSentMsgs'];
    return;
  }
  var pageNav = formatPagingBar(showArgs.page, pageSize,
				response.total, showArgs.fn);
  if(globalParams['pageNavTop']) d.innerHTML = pageNav;
  if(response.messages == null || response.messages.length == 0) {
    d.innerHTML += '<p>No messages on this page. Hmm... Try previous page?</p>';
  }
  showArgs.messages = response.messages;
  var i;
  var contentArray = [ ];
  for(i=0; i<response.messages.length; ++i) {
    var c = response.messages[i];
    var item;
    if(typeof(formatMessageSentCustom) == 'function') {
      item = formatMessageSentCustom(c, i);
    } else {
      item = '<li><a href="javascript:" onclick="onclickSelectMessageSent('+i+')">'
	+formatMessageSent(c)+'</a></li>';
    }
    contentArray.push(item);
  }
  d.innerHTML += '<ul class="chooser">'+contentArray.join('')+'</ul>';
  if(globalParams['pageNavBottom']) d.innerHTML += pageNav;
  call_hook('displaySentHook', showArgs.messages);
  // Select the first one
  onclickSelectMessageSent(0);
}

function onclickSelectMessageSent(i) {
  var msg = showArgs.messages[i];
  /* Provide the default text for the message */
  if(msg.content_text == null) msg.content_text = msg.text;
  call_hook('selectMessageSent', msg);
}

/************************************************************/
/************** RECEIVED MESSAGES PAGE **********************/
/************************************************************/

function showReceived(page) {
  if(!viewerHasApp) {
    showAddApp('Add this app to view messages you\'ve received, or keep trying it as a guest.');
    return;
  }
  showArgs.reset();
  menuSelect('menu_received');
  document.getElementById('main').innerHTML = formatReceivedPage();
  displayContentReceived(1);
}

function deleteMessage(message) {
  debug('deleteMessage('+myToStr(message)+')');
  if(message == null || message.id == null) return;
  var postdata = { 'fn' : 'deleteMessage',
		   'msgid' : message.id };
  displayStatus('Deleting message...');
  serverRequest(function (r) {
      if(r.error) {
	displayStatus('Error: Cannot delete message - please try again.', 'error');
      } else {
	displayStatus('Message deleted');
	displayContentReceived(showArgs.page);
      }
    }, postdata);
}

function displayContentReceived(page) {
  var d = document.getElementById(messages_send_id);
  d.innerHTML = loadingHTML;
  showArgs.fn = 'displayContentReceived';
  showArgs.page = page;
  var postdata = { 'fn' : 'getMessages',
		   'kind' : 'received',
		   'userid' : viewerID,
		   'page' : page,
		   'pageSize' : pageSize };
  serverRequest(onDisplayContentReceived, postdata);
  /* Fetch user info to update the unlocked progress bar */
  postdata = { 'fn' : 'getUserInfo',
	       'userid' : viewerID };
  serverRequest(function (r) {
      if(!r.error) {
	if(r.admin == 1) {
	  viewerIsAdmin = true;
	  showMenu(); /* Redraw the menu - it may change for admins */
	}
	call_hook('updateUnlocked', r);
      }
    },
    postdata);
}

function onDisplayContentReceived(response) {
  var d = document.getElementById(messages_send_id);
  if(response.error) {
    d.innerHTML =
      '<p class="error">Error: couldn\'t fetch the data - '
      + response.errorMessage+'.<br/>'
      +' Please <a href="javascript:;" onclick="' + showArgs.fn
      +'('+showArgs.page+')">try again</a> or report a bug</p>';
    return;
  }
  if(response.total <= 0) {
    d.innerHTML = globalParams['noReceivedMsgs'];
    return;
  }
  var pageNav = formatPagingBar(showArgs.page, pageSize,
				response.total, showArgs.fn);
  if(globalParams['pageNavTop']) d.innerHTML = pageNav;
  if(response.messages == null || response.messages.length == 0) {
    d.innerHTML += '<p>No messages on this page. Hmm... Try previous page?</p>';
  }
  showArgs.messages = response.messages;
  var i;
  var contentArray = [ ];
  for(i=0; i<response.messages.length; ++i) {
    var c = response.messages[i];
    var item;
    if(typeof(formatMessageReceivedCustom) == 'function') {
      item = formatMessageReceivedCustom(c, i);
    } else {
      item = '<li><a href="javascript:" onclick="onclickSelectMessageReceived('+i+')">'
	+formatMessageReceived(c)+'</a></li>';
    }
    contentArray.push(item);
  }
  d.innerHTML += '<ul class="chooser">'+contentArray.join('')+'</ul>';
  if(globalParams['pageNavBottom']) d.innerHTML += pageNav;
  call_hook('displayReceivedHook', showArgs.messages);
  // Select the first one
  onclickSelectMessageReceived(0);
}

function onclickSelectMessageReceived(i) {
  var msg = showArgs.messages[i];
  /* Provide the default text for the message */
  if(msg.content_text == null) msg.content_text = msg.text;
  call_hook('selectMessageReceived', msg);
}

/************************************************************/
/***************** PUBLIC CONTENT PAGE **********************/
/************************************************************/

var showContentParams = null;

/* May be bound to multiple menus; default menu_id = 'content' */
function showContent(params) {
  debug('showContent('+myToStr(params)+')');
  showContentParams = params;
  showArgs.reset();
  if(params['menu_id'] != null) menuSelect('menu_'+params['menu_id']);
  else menuSelect('menu_content');
  document.getElementById('main').innerHTML = formatContentPage();
  displayContent(1);
  if(params.statusMessage) displayStatus(params.statusMessage, params.status);
}

function displayContent(page) {
  var d = document.getElementById(content_container_id);
  d.innerHTML = loadingHTML;
  showArgs.fn = 'displayContent';
  showArgs.page = page;
  var postdata = { 'fn' : 'getContentAll',
		   'userid' : viewerID,
		   'page' : page,
		   'pageSize' : pageSize };
  if(showContentParams['sortby'] != null) {
    postdata['sortby'] = showContentParams['sortby'];
  }
  if(showContentParams['category'] != null) {
    postdata['category'] = showContentParams['category'];
  }
  if(showContentParams['fromUser'] != null) {
    postdata['fromUser'] = showContentParams['fromUser'];
  }
  /* If there is a master app, get the content from the master */
  if(appid_master != 0) postdata['appid'] = appid_master;
  serverRequest(onDisplayContent, postdata);
}

function onDisplayContent(response) {
  var d = document.getElementById(content_container_id);
  if(response.error) {
    d.innerHTML =
      '<p class="error">Error: couldn\'t fetch the data - '
      + response.errorMessage+'.<br/>'
      +' Please <a href="javascript:;" onclick="' + showArgs.fn
      +'('+showArgs.page+')">try again</a> or report a bug</p>';
    return;
  } else if(response.content == null || response.content.length == 0) {
    d.innerHTML = '<p>No content found</p>';
  } else { /* There is content to display */
    var pageNav = formatPagingBar(showArgs.page, pageSize,
				  response.total, showArgs.fn);
    if(globalParams['pageNavTop']) d.innerHTML = pageNav;
    showArgs.messages = response.content;
    var i;
    var contentArray = [ ];
    for(i=0; i<response.content.length; ++i) {
      var c = response.content[i];
      var item = '<li>'+formatContentItem(c, i)+'</li>';
      contentArray.push(item);
    }
    d.innerHTML += '<ul class="content">'+contentArray.join('')+'</ul>';
    if(globalParams['pageNavBottom']) d.innerHTML += pageNav;
  }
  if(response.admin == 1) {
    viewerIsAdmin = true;
    showMenu(); /* Redraw the menu - it may change for admins */
  }
}

function rateContent(content_id, rating) {
  var postdata = { 'fn' : 'rateContent',
		   'contentid' : content_id,
		   'rating' : rating };
  if(appid_master != 0) postdata['appid'] = appid_master;
  serverRequest(function (r) { }, postdata);
}

function reportContent(content_id) {
  var postdata = { 'fn' : 'reportContent',
		   'contentid' : content_id };
  if(appid_master != 0) postdata['appid'] = appid_master;
  serverRequest(function (r) { }, postdata);
}

function deleteContent(content_id, callback) {
  var postdata = { 'fn' : 'deleteContent',
		   'contentid' : content_id };
  if(appid_master != 0) postdata['appid'] = appid_master;
  serverRequest(function (r) { callback(r); }, postdata);
}

/************************************************************/
/******************* POST CONTENT PAGE **********************/
/************************************************************/

function showPostContent() {
  debug('showPostContent()');
  showArgs.reset();
  menuSelect('menu_postContent');
  document.getElementById('main').innerHTML = formatPostContentPage();
  if(!viewerHasApp) {
    alertOverlay('Add this app to post content, or try it with limited functionality as a guest');
    return;
  }
}

/* Submit new content to the app - to be added to the content pool
 * available for everyone else.
 * If the app has a master (appid_master != 0), submit it to the master. */
function postContent(content) {
  if(!viewerHasApp) {
    alertOverlay('Add this app to post content, or try it with limited functionality as a guest');
    return;
  }
  var postdata = clone(content);
  postdata['fn'] = 'postContent';
  postdata['fromUser'] = viewerID;
  if(appid_master != 0) postdata['appid'] = appid_master;
  /* Check the parameters */
  if(!postdata['text'] && !postdata['link'] && !postdata['preview']) {
    alertOverlay('Your post is incomplete - fill in the required fields');
    return;
  }
  displayStatus('Posting content&hellip;', 'warning');
  serverRequest(function (response) {
      if(!response.error) {
	displayStatus('Your content has been posted.');
	call_hook('postContentSuccess');
      } else {
	displayStatus('Error: content was NOT posted. Please try again.', 'error');
      }
    }, postdata);
}

/************************************************************/
/********************** ADMIN PAGE **************************/
/************************************************************/

function showAdmin(page) {
  debug('showAdmin('+myToStr(page)+')');
  showArgs.reset();
  menuSelect('menu_admin');
  document.getElementById('main').innerHTML = formatAdminPage();
  displayContentAdmin(1);
  displayFriendsAdmin(1);
}

function displayContentAdmin(page) {
  var d = document.getElementById(messages_send_id);
  d.innerHTML = loadingHTML;
  showArgs.fn = 'displayContentAdmin';
  showArgs.page = page;
  showArgs.inForm = 1;
  var postdata = { 'fn' : 'getContentAll',
		   'userid' : viewerID,
		   'page' : page,
		   'pageSize' : pageSize };
  serverRequest(onDisplayContentAdmin, postdata);
}

function onDisplayContentAdmin(response) {
  var d = document.getElementById(messages_send_id);
  if(response.error) {
    d.innerHTML =
      '<p class="error">Error: couldn\'t fetch the data - '
      + response.errorMessage+'.<br/>'
      +' Please <a href="javascript:;" onclick="' + showArgs.fn
      +'('+showArgs.page+')">try again</a> or report a bug</p>';
    return;
  }
  d.innerHTML = formatPagingBar(showArgs.page, pageSize,
				response.total, showArgs.fn);
  if(response.content == null || response.content.length == 0) {
    d.innerHTML += '<p>No content found</p>';
    return;
  }
  showArgs.messages = response.content;
  var i;
  var contentArray = [ ];
  for(i=0; i<response.content.length; ++i) {
    var c = response.content[i];
    var item = '<li><a href="javascript:" onclick="onclickSelectMessageAdmin('+i+')">'
      +formatMessageAdmin(c)+'</a></li>';
    contentArray.push(item);
  }
  d.innerHTML += '<ul class="chooser">'+contentArray.join('')+'</ul>';
  // Select the first one
  onclickSelectMessageAdmin(0);
  call_hook('updateUnlocked', response);
  if(response.admin == 1) {
    viewerIsAdmin = true;
    showMenu(); /* Redraw the menu - it may change for admins */
  }
}

function onclickSelectMessageAdmin(i) {
  var msg = showArgs.messages[i];
  /* Provide the default text for the message */
  if(msg.content_text == null) msg.content_text = msg.text;
  selectMessageAdmin(msg);
}

function dispaylFriendsAdmin(page) {
  /* FIXME */
}

/************************************************************/
/********************* CUSTOM PAGE **************************/
/************************************************************/

function showCustomPage(pageId) {
  showArgs.reset();
  menuSelect('menu_'+pageId);
  displayCustomPage(pageId);
}

/* Call this in app.xml */
/* gadgets.util.registerOnLoadHandler(init); */
/* init(); */

