/*
 hotkey.js
  usage :
   var kb = new HotKey;
   kb.add("a",function(){alert("a")});
   kb.add("A",function(){alert("Shift+a")});

http://la.ma.la/blog/diary_200511041713.htm
*/
function HotKey(element){
	this.target = element || document;
	this._keyfunc = {};
	this.init();

}
HotKey.kc2char = function(kc){
	var between = function(a,b){
		return a <= kc && kc <= b
	}
	var _32_40 = "space pageup pagedown end home left up right down".split(" ");
	var kt = {
		8  : "back",
		9  : "tab"  ,
		13 : "enter",
		16 : "shift",
		17 : "ctrl",
    27 : "esc",
		46 : "delete"
	};
	return (
		between(65,90)  ? String.fromCharCode(kc+32) : // a-z
		between(48,57)  ? String.fromCharCode(kc) :    // 0-9
		between(96,105) ? String.fromCharCode(kc-48) : // num 0-9
		between(32,40)  ? _32_40[kc-32] :
		kt.hasOwnProperty(kc) ? kt[kc] : 
		null
	)
}

HotKey.prototype.ignore = /input|textarea/i;
HotKey.prototype.init = function(){
	var self = this;
	var listener = function(e){
		self.onkeydown.call(self,e)
	};
	if(this.target.addEventListener){
		this.target.addEventListener("keydown", listener, true);
	}else{
		this.target.attachEvent("onkeydown", listener)
	}
}
HotKey.prototype.onkeydown = function(e){
	var tag = (e.target || e.srcElement).tagName;
	if(this.ignore.test(tag)) return;
  var input;

  if (e.keyCode == 191 && e.shiftKey) {
    input = '?';
  } else {
    
    input = HotKey.kc2char(e.keyCode);

    if(e.shiftKey && input && input.length == 1){
      input = input.toUpperCase()
    }
    if(e.ctrlKey) input = "C" + input;
  }
	if(this._keyfunc.hasOwnProperty(input)){
		this._keyfunc[input].call(this,e)
	}
}
HotKey.prototype.sendKey = function(key){
	this._keyfunc[key] && this._keyfunc[key]()
}
HotKey.prototype.add = function(key,func){
	if(key.constructor == Array){
		for(var i=0;i<key.length;i++)
			this._keyfunc[key[i]] = func;
	}else{
		this._keyfunc[key] = func;
	}
}

/**
 * Keep a map of scroll positions of the items
 * we need to jump to
 */
var ScrollMap = Class.create({
  map: [],
  itemOffset: 20,

  initialize: function() {
  },

  calc: function(nodes) {
    for (var i=0; i<nodes.length; ++i) {
      var n = nodes[i];
      this.addToMap(n);
    }
    this.orderMap();
    //this.debug();
  },

  destroy: function() {
    this.map = new Array();
  },

  addToMap: function(node) {
    var pos = node.cumulativeOffset();

    // if node.id already exists in the map, 
    // just update it's value
    for (var i=0; i<this.map.length; ++i) {
      var n = this.map[i];
      if (n.id == node.id) {
        this.map[i].y = pos[1]; 
        return;
      }
    }
    this.map.push({id: node.id, y: pos[1]});

  },

  orderMap: function() {
    this.map.sort(function(a, b) {
      return a.y - b.y;
    });
  },

  getNextNode: function(pos, currentItem) {
    for (var i=0; i<this.map.length; ++i) {
      var n = this.map[i];
      if (pos < n.y) {
        if (currentItem && currentItem.id == n.id) return $(this.map[i + 1].id);
        return $(n.id);
      }
    }
    return false;
  },

  getPrevNode: function(pos, currentItem) {
    for (var i=1; i<this.map.length; ++i) {
      var n = this.map[i];
      if (pos <= n.y) {
        if (currentItem && currentItem.id == this.map[i - 1].id) return $(this.map[i - 2].id);
        return $(this.map[i - 1].id);
      }
    }
    return false;
    
/*
    for (var i=this.map.length-1; i>=0; --i) {
      var n = this.map[i];
      if (i == this.map.length-1) {
        if (pos + 35 >= n.y) return $(this.map[i-1].id);
      }

      if (pos - this.itemOffset > n.y) return $(n.id);
    }
    return false;
*/
  },

  debug: function() {
    console.log('Current Y: ' + currentY());
    for (i=0; i<this.map.length; ++i) {
      console.log('ID: ' + this.map[i].id + ' Y: ' + this.map[i].y);
    }
  }
});

var currentY = function() {
  return Math.max(document.body.scrollTop, document.documentElement.scrollTop);
}
