Array.prototype.contains = function(item) {
  return this.indexOf(item) != -1;
};

String.prototype.trim = function()
{
  return this.replace(/^\s*|\s*$/g, '');
};


//=== XHR support

var disableCaching = true;

function loadRemoteFile(url, callback, params) {
  return doHttp("GET", url, null, null, null, null, callback, params, null);
}

// HTTP status codes
var httpStatus = {
  OK: 200,
  ContentCreated: 201,
  NoContent: 204,
  MultiStatus: 207,
  Unauthorized: 401,
  Forbidden: 403,
  NotFound: 404,
  MethodNotAllowed: 405
};

function doHttp(type, url, data, contentType, username, password, callback,
		params, headers) {
  var x = getXMLHttpRequest();
  if (!x)
    return "Can't create XMLHttpRequest object";
  x.onreadystatechange = function() {
    try {
      var status = x.status;
    } catch(ex) {
      status = false;
    }
    if (x.readyState == 4 && callback && (status !== undefined)) {
      if ([0, httpStatus.OK, httpStatus.ContentCreated, httpStatus.NoContent, httpStatus.MultiStatus].contains(status))
	callback(true, params, x.responseText, url, x);
      else
       	callback(false, params, null, url, x);
      x.onreadystatechange = function() {};
      x = null;
    }
  };
  if (window.Components && window.netscape && window.netscape.security
      && document.location.protocol.indexOf("http") == -1)
    window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
  try {
    if (disableCaching)
      url = url + (url.indexOf("?") < 0 ? "?" : "&") + "nocache=" + Math.random();
    x.open(type, url, true, username, password);
    if (data)
      x.setRequestHeader("Content-Type", contentType ? contentType : "application/x-www-form-urlencoded");
    if (x.overrideMimeType)
      x.setRequestHeader("Connection", "close");
    if (headers) {
      for (var n in headers)
	x.setRequestHeader(n, headers[n]);
    }
    x.send(data);
  } catch(ex) {
    return exceptionText(ex);
  }
  return x;
}

function getXMLHttpRequest() {
  try {
    var x = new XMLHttpRequest(); // Modern
  } catch (ex) {
    try {
      x = new ActiveXObject("Msxml2.XMLHTTP"); // IE 6
    } catch (ex2) {
      return null;
    }
  }
  return x;
}

//=== page load fixups

function getEmailAddress() {
  return String.fromCharCode(116, 101, 101, 109, 117, 46, 107, 97,
			     108, 118, 97, 115, 64, 115, 50, 46,
			     111, 114, 103);
}

function fillEmailAddresses() {
  var spans = document.getElementsByTagName('span');
  for (var i = 0; i < spans.length; i++) {
    var span = spans[i];
    if (span.getAttribute('class') == 'email')
      span.innerHTML = getEmailAddress();
  }
}

function fillMenu() {
  var menu = document.getElementById('menu');
  if (menu)
    makeMenu(menu);
}

function getCurrentLocation() {
  var loc = location.pathname.replace('/~chery/', '')
  if (loc)
    return loc;
  else
    return 'index.html';
}

function makeMenu(menu) {
  loadRemoteFile('http://www.s2.org/~chery/navigation',
    function(success, params, data, url, xhr) {
      if (success) {
        var cur = getCurrentLocation();
        var lines = data.split('\n');
	var h = '';
 	var curIndex = 0;
	var items = [];
	for (var i = 0; i < lines.length; i++) {
	  var line = lines[i];
	  if (line) {
  	    var depth = line.length;
	    var name = '';
	    var title = '';
	    for (var j = 0; j < line.length; j++) {
	      var c = line.charAt(j);
	      if (c != ' ') {
	        depth = j;
	        name = line.substr(j);
		title = name;
		var k = name.indexOf(' ');
		if (k != -1) {
		  title = name.substr(k + 1);
		  name = name.substr(0, k);
		}
	        break;
	      }
	    }
	    items.push([depth, name, title]);
	    if (cur == name)
	      curIndex = i;
	  }
	}
	for (var i = 0; i < items.length; i++) {
	  var depth = items[i][0];
	  var name = items[i][1];
	  var title = items[i][2];
	  var hh = '';
	  for (var j = 0; j < depth; j++) {
	    hh = hh + '&nbsp;';
	  }
	  if (i == curIndex)
	    hh = hh + title;
	  else {
	    hh = hh + title.link('./' + name);
 	  }
	  h = h + hh + '<br>';
	}
        menu.innerHTML = h;
      }
    },
    null);
}

//--- on-demand load

var config = {};

function ensureWikiCode(callback) {
  if (typeof wikiCodeLoaded == 'undefined') {
    loadWikiCode(callback);
    wikiCodeLoaded = true;
  } else {
    callback();
  }
}

var wikiCodeFilenames = ['config.js', 'formatter_helper.js', 'formatter.js', 'wikifier.js', 'callback.js'];

function loadWikiCode(callback) {
  config.callback = callback;
  var head = document.getElementsByTagName('head')[0];
  for (var i = 0; i < wikiCodeFilenames.length; i++) {
    var filename = wikiCodeFilenames[i];
    var ref = document.createElement('script');
    ref.setAttribute('type', 'text/javascript');
    ref.setAttribute('src', filename);
    head.appendChild(ref);
  }
}

//--- auto-scrolling

function makeVisible(elem) {
  window.scrollTo(0, ensureVisible(elem));
}

function ensureVisible(e) {
  var posTop = findPosY(e);
  var posBot = posTop + e.offsetHeight;
  var winTop = findScrollY();
  var winHeight = findWindowHeight();
  var winBot = winTop + winHeight;
  if (posTop < winTop) {
    return posTop;
  } else if (posBot > winBot) {
    if (e.offsetHeight < winHeight)
      return posTop - (winHeight - e.offsetHeight);
    else
      return posTop;
  } else {
    return winTop;
  }
}

function findWindowHeight()
{
  return window.innerHeight ? window.innerHeight : document.documentElement.clientHeight;
}

function findScrollY()
{
  return window.scrollY ? window.scrollY : document.documentElement.scrollTop;
}

function findPosY(obj)
{
  var curtop = 0;
  while (obj.offsetParent) {
    curtop += obj.offsetTop;
    obj = obj.offsetParent;
  }
  return curtop;
}

//--- cookies

function setCookie(name, value) {
  var dt = new Date();
  dt.setYear(dt.getYear() + 1);
  expires = dt.toGMTString();
  document.cookie = name + '=' + value + '; expires=' + expires;
}

function getCookie(name, def) {
  var cs = document.cookie.split(';');
  for (var i = 0; i < cs.length; i++) {
    var p = cs[i].indexOf('=');
    if (p != -1) {
      var n = cs[i].substr(0, p).trim();
      var v = cs[i].substr(p + 1).trim();
      if (n == name) {
        return v;
      }
    }
  }
  return def;
}

//--- comment system

var largestCommentNumber = -1;

function loadComments(comments) {
  doHttp('GET',
	 'http://www.s2.org/~chery/comment/list/' + getCurrentLocation(),
	 '', 'text/html', null, null,
	 function (success, params, responseText, url, xhr) {
	   if (success) {
	     lines = responseText.split('\n');
	     for (var i = 0; i < lines.length; i++) {
	       var line = lines[i];
	       if (line) {
	         var m = line.match(/^([0-9]+)./);
		 if (m) {
		   var num = +(m[1]);
		   if (num > largestCommentNumber) {
		     largestCommentNumber = num;
		   }
		 }
	       }
	     }
	     loadNextComment(comments, lines, 0);
	   }
	 },
	 null, null);
}

// this could work: comment-div(text, float right, clear all)

function loadNextComment(comments, lines, index) {
  while (!lines[index] && index < lines.length)
    index++;
  if (index < lines.length) {
    doHttp('GET',
	   'http://www.s2.org/~chery/comment/get/' + getCurrentLocation() + '/' + lines[index],
	   '', 'text/html', null, null,
	   function (success, params, responseText, url, xhr) {
	     if (success) {
	       commentCount++;
	       var comment = createElem(comments, 'div', null, 'comment');
	       comment.innerHTML = responseText;
	       loadNextComment(comments, lines, index + 1);
	       updateStatus();
	     }
	   },
	   null, null);
  }
}

function submitComment(source, html, commenter) {
  setCookie('CBSusername', commenter);
  largestCommentNumber++;
  doHttp('POST',
	 'http://www.s2.org/~chery/comment/put/raw/' + getCurrentLocation() + '/' + largestCommentNumber,
	 source, 'text/html', null, null,
	 function (success, params, responseText, url, xhr) {
	   if (success) {
	     var m = responseText.match(/^OK ([0-9.]+)/);
	     if (m) {
	       var name = m[1];
	       doHttp('POST',
		      'http://www.s2.org/~chery/comment/put/html/' + getCurrentLocation() + '/' + name,
		      html, 'text/html', null, null,
		      function (success, params, responseText, url, xhr) {
		        if (success) {
			  doHttp('POST',
				 'http://www.s2.org/~chery/comment/put/name/' + getCurrentLocation() + '/' + name,
				 commenter, 'text/html', null, null,
				 function (success, params, responseText, url, xhr) {
				   if (success) {
				     //alert('comment submitted');
				   }
				 },
				 null, null);
			}
		      },
		      null, null);
	     }
	   }
	 },
	 null, null);
}

function removeChildren(div) {
  while (div.childNodes.length)
    div.removeChild(div.firstChild);
}

function updateStatus() {
  var status = document.getElementById('status');
  var text = '' + commentCount + ' kommentti';
  if (commentCount != 1)
    text += 'a';
  if (commentShow)
    text += ' piilota';
  else
    text += ' näytä ja kommentoi';
  status.firstChild.nodeValue = text;
}

function makeCommentSystem(main) {
  //alert(document.cookie);
  //chkBackstage=false; txtMoreTab=Missing; Kalenteri=1|695433.569N|270107.180E; txtMainTab=All; chkSliderOptionsPanel=true
  var statusbar = createElem(main, 'div', 'statusbar', 'toolbar');
  var comments = createElem(main, 'div', 'comments', 'comments');
  var toolbar = createElem(main, 'div', 'toolbar', 'toolbar');
  var preview = createElem(main, 'div', 'preview', 'preview');
  var editor = createElem(main, 'div', 'editor', 'editor');
  var textarea = createElem(editor, 'textarea', null, null, null,
      	                    {'rows': 10});
  createElem(editor, 'span', null, null, 'Nimi: ');
  var commenterName = createElem(editor, 'input', null, null, '',
      		      		 {'value': getCookie('CBSusername', ''),
      		      		  'type': 'text'});
  var commentsButton = createElem(statusbar, 'a', 'status', 'button', '',
      		                 {'href': 'javascript:;', 'name': 'comments'});
  var previewButton = createElem(toolbar, 'a', null, 'button', 'esikatsele',
      		                 {'href': 'javascript:;', 'name': 'preview'});
  var cancelButton = createElem(toolbar, 'a', null, 'button', 'peru',
      		                {'href': 'javascript:;', 'name': 'cancel'});
  var publishButton = createElem(toolbar, 'a', null, 'button', 'julkaise',
      		                 {'href': 'javascript:;', 'name': 'publish'});
  var editButton = createElem(toolbar, 'a', null, 'button', 'muokkaa',
      		                 {'href': 'javascript:;', 'name': 'edit'});
  commentsButton.onclick = function() {
    if (commentShow) {
      comments.style.display = 'none';
      toolbar.style.display = 'none';
      editor.style.display = 'none';
      preview.style.display = 'none';
      commentShow = false;
    } else {
      comments.style.display = 'block';
      toolbar.style.display = 'block';
      editor.style.display = 'block';
      textarea.value = '';
      makeVisible(editor);
      previewButton.style.display = 'inline';
      publishButton.style.display = 'none';
      editButton.style.display = 'none';
      commentShow = true;
    }
    updateStatus();
  };
  previewButton.onclick = function() {
    editor.style.display = 'none';
    preview.style.display = 'block';
    previewButton.style.display = 'none';
    publishButton.style.display = 'inline';
    editButton.style.display = 'inline';
    var comment = createElem(preview, 'div', null, 'comment');
    var container = createElem(comment, 'div', null, null, null);
    ensureWikiCode(function() {
      wikify(textarea.value, container, false, null);
    });
    var now = new Date();
    var nowString = padZero(now.getFullYear(), 4) + '-' + padZero(now.getMonth(), 2) + '-' + padZero(now.getDate(), 2) + ' ' + padZero(now.getHours(), 2) + ':' + padZero(now.getMinutes(), 2)
    createElem(comment, 'div', null, 'meta',
    	       commenterName.value + ' - ' + nowString);
    makeVisible(comment);
  };
  publishButton.onclick = function() {
    editor.style.display = 'block';
    preview.style.display = 'none';
    previewButton.style.display = 'inline';
    publishButton.style.display = 'none';
    editButton.style.display = 'none';
    submitComment(textarea.value, preview.firstChild.firstChild.innerHTML, commenterName.value);
    textarea.value = '';
    // Preserve commenter name even though comment text is removed.
    var comment = createElem(null, 'div', null, 'comment');
    comments.insertBefore(comment, comments.firstChild);
    comment.innerHTML = preview.firstChild.innerHTML;
    removeChildren(preview);
    commentCount++;
    makeVisible(comment);
    updateStatus();
  };
  editButton.onclick = function() {
    editor.style.display = 'block';
    preview.style.display = 'none';
    previewButton.style.display = 'inline';
    publishButton.style.display = 'none';
    editButton.style.display = 'none';
    removeChildren(preview);
  };
  cancelButton.onclick = function() {
    editor.style.display = 'block';
    preview.style.display = 'none';
    previewButton.style.display = 'inline';
    publishButton.style.display = 'none';
    editButton.style.display = 'none';
    removeChildren(preview);
    textarea.value = '';
  };
  updateStatus();
  comments.style.display = 'none';
  toolbar.style.display = 'none';
  preview.style.display = 'none';
  editor.style.display = 'none';
  loadComments(comments);
}

function fillStatusbar() {
  var main = document.getElementById('main');
  var mainleft = document.getElementById('mainleft');
  if (main && !mainleft)
    makeCommentSystem(main);
}

function onLoadFixups() {
  fillEmailAddresses();
  fillMenu();
  fillStatusbar();
}

var commentCount = 0;
var commentShow = false;

//--- helpers

function createText(node, text) {
  return node.appendChild(document.createTextNode(text));
}

function createElem(parent, elem, id, class, text, attribs) {
  var e = document.createElement(elem);
  if (class != null)
    e.className = class;
  if (id != null)
    e.setAttribute('id', id);
  if (text != null)
    createText(e, text);
  if (attribs) {
    for (var n in attribs) {
      e.setAttribute(n, attribs[n]);
    }
  }
  if (parent != null)
    parent.appendChild(e);
  return e;
}

function addClass(elem, class) {
  var curr = elem.className.split(" ");
  if (curr.indexOf(class) == -1)
    elem.className += " " + class;
}

function removeClass(elem, class) {
  var curr = elem.className.split(" ");
  var i = curr.indexOf(class);
  while (i != -1) {
    curr.splice(i, 1);
    i = curr.indexOf(class);
  }
  elem.className = curr.join(" ");
}

function hasClass(elem, class) {
  if (elem.className) {
    if (elem.className.split(" ").indexOf(class) != -1)
      return true;
  }
  return false;
}

function padZero(n, count) {
  var v = String(n);
  while (v.length < count) v = '0' + v;
  return v;
}
