////////// tom.core.js //////////
var tom = {
  VERSION: "3.0.1",
  COPYRIGHT: "www.tom.com",
  AUTHOR: "wudi msn:woodlessr@hotmail.com blog:http://blog.tom.com/woodless;",
  fnEmpty: function() {},
  fnTrue: function() { return true; },
  fnFalse: function() { return false; }
};

tom.config = {
  alert: {
  	_fnCallBack: function(msg, ico, fn, autoHide) {
  	  var cb = fn ? ((fn instanceof Function) ? fn : ((typeof(fn) == "string") ? new Function("e", fn) : tom.fnTrue)) : tom.fnTrue;
      alert(msg);
      cb();
  	},
  	getCallBack: function() {
  	  return this._fnCallBack;
  	}
  },
  information: {
  	_fnCallBack: function(msg, autoHide, fn) {
      var cb = fn ? ((fn instanceof Function) ? fn : ((typeof(fn) == "string") ? new Function("e", fn) : tom.fnTrue)) : tom.fnTrue;
      alert(msg);
      cb();
  	},
  	getCallBack: function() {
  	  return this._fnCallBack;
  	}
  },
  confirm: {
  	_fnCallBack: function(msg, fnOk, fnCancel, title) {
      var cbOk = fnOk ? ((fnOk instanceof Function) ? fnOk : ((typeof(fnOk) == "string") ? new Function("e", fnOk) : tom.fnTrue)) : tom.fnTrue;
      var cbCancel = fnCancel ? ((fnCancel instanceof Function) ? fnCancel : ((typeof(fnCancel) == "string") ? new Function("e", fnCancel) : tom.fnTrue)) : tom.fnTrue;
      confirm(msg) ? cbOk() : cbCancel();
  	},
  	getCallBack: function() {
  	  return this._fnCallBack;
  	}
  },
  login: {
  	_fnCallBack: function(backUrl) {
      alert("TODO. back to " + backUrl);
  	},
  	getCallBack: function() {
  	  return this._fnCallBack;
  	}
  }
};

tom.Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
};

if (typeof($) == 'undefined') {
  $ = function(elem) {
    if (arguments.length > 1) {
      for (var i = 0, elems = [], length = arguments.length; i < length; i++)
        elems.push($(arguments[i]));
      return elems;
    }
    if (typeof elem == 'string') {
      return document.getElementById(elem);
    } else {
    	return elem;
    }
  };
}

if (typeof($A) == 'undefined') {
  $A = function(a) {
    var results = [];
    for (var i = 0, length = a.length; i < length; i++) {
      results.push(a[i]);
    }
    return results;
  };
}

tom.extend = function(dist) {
  var srcs = $A(arguments);
  srcs.splice(0, 1);
  for (var i = 0; i < srcs.length; i++) {
    var src = srcs[i];
    for (var p in src) {
      dist[p] = src[p];
    }
  }
  return dist;
}

tom.extend(
  String.prototype,
  {
  	trim: function() {
      return this.replace(/^\s+|\s+$/g, "");
    },
    startsWith: function(pf) {
      return pf == "" ? true : this.indexOf(pf) == 0;
    },
    endsWith: function (sf) {
      return sf == "" ? true : this.lastIndexOf(sf) == this.length - String(sf).length;
    }
  }
);

tom.extend(Array.prototype, {
  contains: function(o) {
    for (var i = 0, len = this.length; i < len; i++) {
      if (this[i] == o) {
      	return true;
      }
    }
    return false;
  }
});

tom.Element = {
  getStyle: function(element, style) {
   var elem = typeof element == "string" ? $(element) : element;
    if (['float','cssFloat'].contains(style)) {
      style = (typeof elem.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
    }
    var value = elem.style[style];
    if (!value) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        var css = document.defaultView.getComputedStyle(elem, null);
        value = css ? css[style] : null;
      } else if (elem.currentStyle) {
        value = elem.currentStyle[style];
      }
    }
    if((value == 'auto') && ['width','height'].contains(style) && (this.getStyle(elem, 'display') != 'none')) {
      value = elem['offset'+style.charAt(0).toUpperCase()+style.substring(1, style.length)] + 'px';
    }
    if (window.opera && ['left', 'top', 'right', 'bottom'].contains(style)) {
      if (this.getStyle(elem, 'position') == 'static') value = 'auto';
    }
    if(style == 'opacity') {
      if(value) return parseFloat(value);
      if(value = (elem.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if(value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }
    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style, value) {
    var elem = typeof element == "string" ? $(element) : element;
    if(style == 'opacity') {
      if (value == 1) {
        value = (/Gecko/.test(navigator.userAgent) &&
          !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
        if(/MSIE/.test(navigator.userAgent) && !window.opera)
          elem.style.filter = elem.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
      } else if(value === '') {
        if(/MSIE/.test(navigator.userAgent) && !window.opera)
          elem.style.filter = elem.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
      } else {
        if(value < 0.00001) value = 0;
        if(/MSIE/.test(navigator.userAgent) && !window.opera)
          elem.style.filter = elem.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
            'alpha(opacity='+value*100+')';
      }
    } else if(['float','cssFloat'].contains(name)) {
    	name = (typeof elem.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
    }
    elem.style[style] = value;
    return elem;
  },
  toggle: function(elem) {
    if (this.getStyle(elem, "display") == "none") {
      this.setStyle(elem, "display", "");    
    } else {
      this.setStyle(elem, "display", "none");  
    }
  },
  hide: function(elem) {
    $(elem).style.display = 'none';
    return elem;
  },
  show: function(elem) {
    $(elem).style.display = '';
    return elem;
  }
};

tom.Event = {
  addEvent: function(elem, name, fn, useCapture) {
    if (elem.addEventListener) {
      elem.addEventListener(name, fn, useCapture);
    } else if (elem.attachEvent) {
      elem.attachEvent('on' + name, fn);
    }
  },
  removeEvent: function(elem, name, fn, useCapture) {
    if (elem.removeEventListener) {
      elem.removeEventListener(name, fn, useCapture);
    } else if (elem.detachEvent) {
      elem.detachEvent('on' + name, fn);
    }
  },
  pointer: function(e) {
    return {x: this.pointerX(e), y: this.pointerY(e)};
  },
  pointerX: function(e) {
    return e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
  },
  pointerY: function(e) {
    return e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
  },
  stop: function(e) {
    if (e.preventDefault) {
      e.preventDefault();
      e.stopPropagation();
    } else {
      e.returnValue = false;
      e.cancelBubble = true;
    }
  },
  isLeftClick: function(e) {
    return (((e.which) && (e.which == 1)) || ((e.button) && (e.button == 1)));
  }
};

tom.Position = {
  pointer: function(e) {
    return {x: (e.pageX || e.clientX), y: (e.pageY || e.clientY)};
  },
  pointerX: function(e) {
    return e.clientX || (e.pageX - tom.Position.getWindowScrollLeft());
  },
  pointerY: function(e) {
    return e.clientY || (e.pageY - tom.Position.getWindowScrollTop());
  },
  prepare: function() {
    this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
    this.deltaY =  window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
  },
  cumulativeOffset: function(elem) {
    var x = 0, y = 0;
    do {
      y += elem.offsetTop  || 0;
      x += elem.offsetLeft || 0;
      elem = elem.offsetParent;
    } while (elem);
    return {left: x, top: y};
  },
  within: function(elem, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(elem, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(elem);
    return (y >= this.offset.top &&
            y <  this.offset.top + elem.offsetHeight &&
            x >= this.offset.left &&
            x <  this.offset.left + elem.offsetWidth);
  },
  withinVertical: function(elem, x) {
    this.offset = this.cumulativeOffset(elem);
    return (x >= this.offset.left && x < this.offset.left + elem.offsetWidth);
  },
  withinIncludingScrolloffsets: function(elem, x, y) {
    var offsetcache = this.realOffset(elem);
    this.xcomp = x + offsetcache.left - this.deltaX;
    this.ycomp = y + offsetcache.top - this.deltaY;
    this.offset = this.cumulativeOffset(elem);
    return (this.ycomp >= this.offset.top &&
            this.ycomp <  this.offset.top + elem.offsetHeight &&
            this.xcomp >= this.offset.left &&
            this.xcomp <  this.offset.left + elem.offsetWidth);
  },
  bound: function(elem) {
  	var pos = this.cumulativeOffset(elem);
    return { x: pos.left, y: pos.top, w: elem.offsetWidth, h: elem.offsetHeight };
  },
  getWindowClientWidth: function() {
    return window.innerWidth 
        || document.documentElement.clientWidth
        || document.body.clientWidth
        || 0;
  },
  getWindowClientHeight: function() {
    return window.innerHeight 
        || document.documentElement.clientHeight
        || document.body.clientHeight
        || 0;
  },
  getWindowScrollWidth: function() {
    return window.scrollWidth 
        || document.documentElement.scrollWidth
        || document.body.scrollWidth;
  },
  getWindowScrollHeight: function() {
    return window.scrollHeight
        || document.documentElement.scrollHeight
        || document.body.scrollHeight;
  },
  getWindowScrollLeft: function() {
    if (window.scrollWidth) {
      return window.scrollLeft;
    } else if (document.documentElement.scrollWidth) {
      return document.documentElement.scrollLeft;
    } else if (document.body.scrollWidth) {
      return document.body.scrollLeft
    } else {
      return 0;
    }
  },
  getWindowScrollTop: function() {
    if (window.scrollWidth) {
      return window.scrollTop;
    } else if (document.documentElement.scrollWidth) {
      return document.documentElement.scrollTop;
    } else if (document.body.scrollWidth) {
      return document.body.scrollTop;
    } else {
      return 0;
    }
  }
};

tom.Effect = {
  setOpacity: function(elem, val) {
    if (document.all) {
      elem.style.filter = "alpha(opacity=" + val * 100 + ")";
    } else {
      elem.style.opacity = val;
    }
  }
};

tom.Image = {
  resizeImage: function(img, mw, mh) {
    var w = img.offsetWidth;
    var h = img.offsetHeight;
    if (w / h >= mw / mh) {
      if (w >= mw) {
	    img.style.width = mw + "px";
	  }
    } else {
      if (h >= mh) {
        img.style.height = mh + "px";
	  }
    }
  }
};
/**
 * package tom.util
 */
tom.util = {};
tom.util.List = tom.Class.create();
tom.extend(tom.util.List.prototype, {
  initialize: function() {
    this._l = [];
  },
  add: function(o) { this._l.push(o); },
  addAll: function(l) {
  	var a = (l instanceof tom.util.List || l instanceof tom.util.Set) ? l._l : l;
  	for (var i = 0; i < a.length; i++) {
  	  this._l.push(a[i]);
  	}
  },
  clear: function() { this._l.length = 0; },
  contains: function(o) { return this.indexOf(o) != -1; },
  get: function(i) { return this._l[i]; },
  indexOf: function(o) {
    for(var i = 0; i < this._l.length; i++){
      if(this._l[i] === o) {
        return i;
      }
    }
    return -1;
  },
  isEmpty: function() { return this._l.length == 0; },
  remove: function(i) { return this._l.splice(i, 1); },
  removeObject: function(o) { 
    var i = this.indexOf(o);
    if (i != -1) {
      return this._l.splice(i, 1)[0]; 
    } else {
      return null;
    }
  },
  size: function() { return this._l.length; },
  toArray: function() { return [].concat(this._l); },
  dump: function() { return "[" + this._l.join(",") + "]"; },
  sort: function(fn) {
  	if (!this._l || this._l.length < 2) {
  	  return this;
  	}
  	if (fn) {
  	  this._l.sort(fn);
  	} else {
  	  this._l.sort();
  	}
  	return this;
  },
  filter: function(fnExp, fnCond) {
    return tom.util.Arrays.asList(tom.util.Arrays.filter(fnExp, this._l, fnCond));
  },
  each: function(fn) {
  	var l = this._l;
  	for (var i = 0, len = l.length; i < len; i++) {
  	  fn(l[i]);
  	}
  }
});
tom.util.Set = tom.Class.create();
tom.extend(tom.util.Set.prototype, tom.util.List.prototype, {
  initialize: function() {
    this._l = [];
  },
  add: function(o) {
    if (this.indexOf(o) == -1) {
      this._l.push(o);
    }
  },
  addAll: function(s) {
  	var a = (s instanceof tom.util.List || s instanceof tom.util.Set) ? s._l : s;
    for (var i = 0; i < a.length; i++) {
      this.add(a[i]);
    }
  },
  filter: function(fnExp, fnCond) {
    return tom.util.Arrays.asSet(tom.util.Arrays.filter(fnExp, this._l, fnCond));
  }
});
tom.util.Map = tom.Class.create();
tom.extend(tom.util.Map.prototype, {
  initialize: function() {
    this._m = {};
  },
  clear: function() { this._m = {}; },
  containsKey: function(k) { return this._m.hasOwnProperty("_" + k); },
  containsValue: function(v) {
    for (var k in this._m) {
      if (this._m["_" + k] === v) {
        return true;
      }
    }
    return false;
  },
  get: function(k) { return this._m["_" + k]; },
  isEmpty: function() {
    for (var k in this._m) {
      return false;
    }
    return true;
  },
  keySet: function() {
  	var set = new tom.util.Set();
    var m = this._m;
    for (var i in m) {
      set.add(i);
    }
    return set;
  },
  values: function() {
  	var a = [];
    var m = this._m;
    for (var i in m) {
      a.push(m[i]);
    }
    return tom.util.Arrays.asList(a);
  },
  put: function(k, v) { return this._m["_" + k] = v; },
  remove: function(k) {
    var v = this._m["_" + k];
    delete(this._m["_" + k]);
    return v;
  },
  size: function() {
    var c = 0;
    for (var i in this._m) {
      c++;
    }
    return c;
  },
  filter: function(fnExp, fnCond) {
    switch (typeof(fnExp)) {
      case "undefined":
        fnExp = function(k, v) { return {k: k, v: v} };
        break;
      case "function": 
        break;
      case "string":
        fnExp = new Function("k", "v", "return " + fnExp + ";");
        break;
    }
    switch (typeof(fnCond)) {
      case "undefined":
        fnCond = tom.fnTrue;
        break;
      case "function": 
        break;
      case "string":
        fnCond = new Function("k", "v", "return (" + fnCond + ");");
        break;
    }
    
	var rst = new tom.util.Map();
	var m = this._m;
	var v = null;
    var t = null;
    for (var k in m) {
      v = m[k];
      k = k.substring(1, k.length);
      if (fnCond(k, v)) {
      	t = fnExp(k, v);
        rst.put(t.k, t.v);
      }
    }
    return rst;
  },
  each: function(fn) {
	var m = this._m;
	var v = null;
    for (var k in m) {
      v = m[k];
      k = k.substring(1, k.length);
      fn(k, v);
    }
  }
});
tom.util.Queue = tom.Class.create();
tom.extend(tom.util.Queue.prototype, {
  initialize: function() {
    this._q = [];
  },
  enqueue: function(o) {
    this._q.push(o);
  },
  dequeue: function() {
    return this._q.shift();
  },
  peek: function() {
    return this._q[0];
  },
  size: function() {
    return this._q.length;
  }
});

tom.util.ActiveObject = tom.Class.create();
tom.extend(tom.util.ActiveObject.prototype, {
  initialize: function(period) {
  	this.period = period ? period : 100;
  	this._timer = null;
  	this.taskQueue = new tom.util.Queue();
  },
  start: function() {
  	var _this = this;
  	this._timer = setInterval(
  	  function() {
  	  	_this.execute();
  	  },
  	  this.period
  	)
  },
  stop: function() {
  	clearInterval(this._timer);
  },
  run: tom.fnEmpty,
  addTask: function(t) {
  	this.taskQueue.enqueue(t);
  }
});

tom.util.Arrays = {
  asList: function(a) {
    var l = new tom.util.List();
    l._l = [].concat(a);
    return l;
  },
  asSet: function(a) {
    var s = new tom.util.Set();
    for (var i = 0, len = a.length; i < len; i++) {
      s.add(a[i]);
    }
    return s;
  },
  asMap: function(a, asType) {
  	asType = asType ? asType : 0;
  	var m = new tom.util.Map();
  	var tmp = null;
  	for (var i = 0, len = a.length, v = null; i < len; i++) {
  	  v = a[i];
      switch (asType) {
        case 0:
          m.put(v[0], v[1]);
          break;
        case 1:
          m.put(v, a[++i]);
          break;
        case 2:
          m.put(v.k, v.v);
          break;
        default:
          v = asType(v);
          m.put(v.k, v.v);
          break;
      }
  	}
  	return m;
  },
  filter: function(fnExp, arr, fnCond) {
    switch (typeof(fnExp)) {
      case "undefined":
        fnExp = function(o) { return o; };
        break;
      case "function": 
        break;
      case "string":
        fnExp = new Function("o", "return " + fnExp + ";");
        break;
    }
    switch (typeof(fnCond)) {
      case "undefined":
        fnCond = tom.fnTrue;
        break;
      case "function": 
        break;
      case "string":
        fnCond = new Function("o", "return (" + fnCond + ");");
        break;
    }
    var rst = [];
    var o = null;
    for (var i = 0, l = arr.length; i < l; i++) {
      o = arr[i];
      if (fnCond(o)) {
        rst.push(fnExp(o));
      }
    }
    return rst;
  }, 
  dump: function(a) {
    return a.join(",");
  }
};

/** XHConn - Simple XMLHTTP Interface - bfults@gmail.com - 2005-04-08        **
 ** Code licensed under Creative Commons Attribution-ShareAlike License      **
 ** http://creativecommons.org/licenses/by-sa/2.0/                           **/
/**
 * Modified at 2007-05-18 By woodless
 * Email: woodlessr@hotmail.com
 */
tom.XHConn = tom.Class.create();
tom.extend(tom.XHConn.prototype, {
  initialize: function() {
    this.xmlhttp = false;
    this.isComplete = false;
    try { this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
    catch (e) { try { this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
    catch (e) { try { this.xmlhttp = new XMLHttpRequest(); }
    catch (e) { this.xmlhttp = false; }}}
  },
  connectAsync: function(url, method, vars, callback) {
    if (!this.xmlhttp) return false;
    this.isComplete = false;
    try {
      if (method.toUpperCase() == "GET") {
        this.xmlhttp.open(method, url + "?" + vars, true);
        vars = "";
      } else {
        this.xmlhttp.open(method, url, true);
        this.xmlhttp.setRequestHeader("Method", "POST " + url + " HTTP/1.1");
        this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      }
      var _this = this;
      this.xmlhttp.onreadystatechange = function() {
        if (_this.xmlhttp.readyState == 4 && !_this.isComplete) {
          _this.isComplete = true;
          callback(_this.xmlhttp);
        }
      };
      this.xmlhttp.send(vars);
    } catch(z) {
    	alert(z.message);
    	return false;
    }
    return true;
  },
  connectSync: function(url, method, vars, options) {
    if (!this.xmlhttp) return false;
    options = options ? options : {text: true, xml: false, json: false};
    this.isComplete = false;
    method = method.toUpperCase();
    try {
      if (method == "GET") {
        this.xmlhttp.open(method, url + "?" + vars, false);
        vars = "";
      } else {
        this.xmlhttp.open(method, url, false);
        this.xmlhttp.setRequestHeader("Method", "POST " + url + " HTTP/1.1");
        this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      }
      this.xmlhttp.send(vars);
    } catch(e) {
    	alert(e.message);
    	return false;
    }
    var o = {};
    if (options.text) {
      o["text"] = this.xmlhttp.responseText;
    }
    if (options.xml) {
      o["xml"] = this.xmlhttp.responseXML;
    }
     if (options.json) {
      o["json"] = eval("(" + this.xmlhttp.responseText + ")");
    }
    return o;
  }
});
tom.XHConn.Parameter = tom.Class.create();
tom.extend(tom.XHConn.Parameter.prototype, tom.util.Map.prototype, {
  initialize: function(m) {
  	m = m ? m : {};
  	tom.util.Map.prototype.initialize.apply(this, []);
  	tom.extend(this, m);
  },
  append: function(k, v) {
  	this.put(k, v);
  	return this;
  },
  stringValue: function() {
  	var m = this._m;
	var s = "";
  	var i = 0;
  	var v = null;
  	for (var k in m) {
  	  if (i++ > 0) {
  	  	s += "&";
  	  }
  	  v = m[k];
  	  k = k.substring(1, k.length);
  	  s += k + "=" + encodeURIComponent(v);
  	}
  	return s;
  }
});
tom.XHConn.parseResult = function(xhq, options) {
  var opt = {};
  tom.extend(
    opt,
    { text: true, xml: false, json: false},
    options || {}
  );
  var o = {};
  if (opt.text) {
    o["text"] = xhq.responseText;
  }
  if (opt.xml) {
    o["xml"] = xhq.responseXML;
  }
  if (opt.json) {
    o["json"] = eval("(" + xhq.responseText + ")");
  }
  return o;
}
tom.XHConn.quickFillGet = function(fillId, url, vars) {
  var xhc = new XHConn();
  xhc.connectAsync(
    url, 
    "get", 
    vars ? vars : "", 
    function(xhq) {
      $(fillId).innerHTML = xhq.responseText;
    });
}

/*
 * 提示框（类似alert）
 * msg: 提示信息
 * ico：图标，OK/ERROR/INFO
 * fn: 关闭提示框后执行的回调函数。（可选）
 * autoHide: 自动关闭的时间，如不添则不自动隐藏。（可选）
 */
tom.alert = function(msg, ico, fn, autoHide) {
  tom.config.alert.getCallBack()(msg, ico, fn, autoHide);
}

/*
 * 确认框（类似alert）
 * msg: 提示信息
 * fnOk: 点击ok按钮的回调函数。
 * fnCancel: 点击cancel的回调函数。
 * title: 标题（可选）
 */
tom.confirm = function(msg, fnOk, fnCancel, title) {
  tom.config.confirm.getCallBack()(msg, fnOk, fnCancel, title);
}

/*
 * 提示框（只是一个div）
 * msg: 提示信息
 * autoHide: 自动关闭的时间，如不添则不自动隐藏。
 * fn: 关闭提示框后执行的回调函数。（可选）
 */
tom.information = function(msg, autoHide, fn) {
  tom.config.information.getCallBack()(msg, autoHide, fn);
}


/*
 * 登录框（div）
 * todo
 */
tom.login = function(backUrl) {
  tom.config.login.getCallBack()(backUrl);
}

////////// tom.dnd.js //////////
if (typeof(tom) == "undefined") {
  throw new Error("tom.dnd Require tom.core");
}

tom.dnd = {};

tom.dnd.Draggables = {
  //当前拖拽的对象
  draggable: null,

  winMoveDragStart: function(e, draggable) {
    e = e ? e : window.event;
    if (!tom.Event.isLeftClick(e)) {
      return;
    }
    this.removeDragEvents();
    if (this.draggable && !this.draggable.hasDrop) {
      tom.dnd.Droppables.hideDropTmpDiv();
      this.draggable.endDrag(e);
      this.removeDragEvents();
      return;
    }
    this.draggable = draggable;
    //call droppables callback
    if (draggable.canDrop) {
      tom.dnd.Droppables.detectDragStart(e);
    }
    //开始拖拽
    draggable.startDrag(e);
    this.addDragEvents();
  },
  
  winMoveDragGo: function(e) {
    e = e ? e : window.event;
    var draggable = tom.dnd.Draggables.draggable;
    if (!draggable.isDrag) {
      return;
    }
    //call droppable callback
    if (draggable.canDrop) {
      tom.dnd.Droppables.detectHover(e);
    }
    //call onDrag callback
    draggable.onDrag(e);
  },
  
  winMoveDragStop: function(e) {
  	e = e ? e : window.event;
    if (!tom.Event.isLeftClick(e)) {
      return;
    }
  	var draggable = tom.dnd.Draggables.draggable;
  	if (draggable.canDrop) {
      //drop callback
      tom.dnd.Droppables.detectDrop(e);
  	}
    //drag callback
    draggable.endDrag(e);
    //
    tom.dnd.Draggables.removeDragEvents();
  },
  escKeyPress: function(e) {
    e = e ? e : window.event;
    if (e.keyCode == 27) {
      tom.dnd.Droppables.hideDropTmpDiv();
      tom.dnd.Draggables.draggable.endDrag(e);
      tom.dnd.Draggables.removeDragEvents();
    }
  },
  addDragEvents: function() {
    tom.Event.addEvent(document, "mousemove", this.winMoveDragGo, true);
    tom.Event.addEvent(document, "mouseup", this.winMoveDragStop, false);
    tom.Event.addEvent(document, "keypress", this.escKeyPress, false);
  },
  removeDragEvents: function() {
    tom.Event.removeEvent(document, "mousemove", tom.dnd.Draggables.winMoveDragGo, false);
    tom.Event.removeEvent(document, "mouseup", tom.dnd.Draggables.winMoveDragStop, false);
    tom.Event.removeEvent(document, "keypress", tom.dnd.Draggables.escKeyPress, false);
  }
};

/**
 * class Draggable
 */
tom.dnd.Draggable = tom.Class.create();
tom.extend(tom.dnd.Draggable.prototype, {
  element: null,
  droppable: null,
  revert: false,
  scroll: false,
  offset: { left: 0, top: 0 },
  size: { width: 0, height: 0 },
  bound: {x: 0, y: 0, w: 0, h: 0},
  moveToEnd: false,
  hasDrop: true,
  resetBound: function() {
  	this.bound = tom.Position.bound(this.element);
  },
  isMoveToEnd: function() {
  	return this.moveToEnd;
  },
  endPoint: {
    parent: null,
    sibling: null
  },
  isDrag: false,
  hasMoveElem: false,
  
  initialize: function(elem, args) {
  	var options = {
      handle: elem,
      canDrop: false,
      opacity: true
  	};
    tom.extend(this, options, args);
    this.element = typeof(elem) == "string" ? $(elem) : elem;
    this.handle = typeof(this.handle) == "string" ? $(this.handle) : this.handle;
    this.handle.style.cursor = "move";
    var draggable = this;
    tom.Event.addEvent(this.handle, "mousedown", 
      function(e) {
        e = e ? e : window.event;
        tom.dnd.Draggables.winMoveDragStart(e, draggable);
      }, 
      false);
  },
  startDrag: function(e) {
  	this.hasDrop = false;
    var elem = this.element;
    //透明
    if (this.isOpacity()) {
      tom.Effect.setOpacity(elem, 0.8);
    }
    //记录ffset
    var p = tom.Event.pointer(e);
    var pos = tom.Position.cumulativeOffset(elem);
    this.offset = { left: p.x - pos.left, top: p.y - pos.top };
    this.size = { width: elem.offsetWidth, height: elem.offsetHeight };
    //创建记录点，用于revert的时候，插入element
    var sibling = null;
    if (sibling = this._findAvailNextSibling(elem)) {
      this.endPoint = {sibling: sibling, parent: elem.parentNode};
    } else if (elem.parentNode != document.body) {
      this.endPoint = {sibling: null, parent: elem.parentNode};
    }
    //从当前节点parentNode删除，并且添加到body上
    elem.parentNode.removeChild(elem);
    elem.style.position = "absolute";
    elem.style.left = pos.left + "px";
    elem.style.top = pos.top + "px";
    
//    elem.style.width = this.size.width + "px";
    document.body.appendChild(elem);
    
    this.isDrag = true;
    this.hasMoveElem = true;
    //callback
    this.onDragStart(e);
  },
  onDrag: function(e) {
    var elem = this.element;
    if (this.hasMoveElem == false) {
      this.hasMoveElem = true;
    }
    //
    if (this.scroll) {
        if (tom.Position.pointerY(e) < 32) {
          tom.dnd.Roller.rollUp();
        } else if (tom.Position.pointerY(e) >= tom.Position.getWindowClientHeight() - 32) {
          tom.dnd.Roller.rollDown();
        } else {
          tom.dnd.Roller.stop();
        }
    }
    elem.style.top = tom.Event.pointerY(e) - this.offset.top + "px";
    elem.style.left = tom.Event.pointerX(e) - this.offset.left + "px";
    //callback
    this.onDragging(e);
  }, 
  endDrag: function(e) {
  	this.hasDrop = true;
    this.isDrag = false;
    if (!this.hasMoveElem) {
      return;
    }
    if (this.isOpacity()) {
      tom.Effect.setOpacity(this.element, 1);
    }
    if (this.isRevert() || this.isMoveToEnd()) {
      this.moveToEndPoint();
    }
    if (this.scroll) {
      tom.dnd.Roller.stop();
    }
    //callback
    this.onDragEnd(e);
  },
  moveToEndPoint: function(e) {
    document.body.removeChild(this.element);
    if (this.endPoint.sibling) {
      this.endPoint.parent.insertBefore(this.element, this.endPoint.sibling);
    } else {
      this.endPoint.parent.appendChild(this.element);    
    }
    if (this.isRevert()) {
      this.element.style.position = "relative";
      this.element.style.left = "0";
      this.element.style.top = "0";
    }
  },
  onDragStart: tom.fnEmpty,
  onDragging: tom.fnEmpty,
  onDragEnd: tom.fnEmpty,
  isRevert: function() {
    return this.revert;
  },
  isOpacity: function() {
  	return this.opacity;
  },
  _findAvailNextSibling: function(elem) {
    var sibling = elem;
    while (sibling = sibling.nextSibling) {
      if (sibling.nodeType != 3) {
        return sibling;
      }
    }
    return null;
  }
});


tom.dnd.Droppable = tom.Class.create();
tom.extend(tom.dnd.Droppable.prototype, {
  initialize: function(elem, args) {
  	args = args ? args : {};
  	var fields = {
      draggables: new tom.util.Set(),
      currentMoveIndex: 65535
  	}
  	tom.extend(this, fields, args);
  	this.element = typeof(elem) == "string" ? $(elem) : elem;
  },
  addDraggable: function(d) {
    if (!this.draggables.contains(d)) {
      d.droppable = this;
      this.draggables.add(d);
      this.element.appendChild(d.element);
    }
  },
  addDraggableFirst: function(d) {
    if (!this.draggables.contains(d)) {
      d.droppable = this;
      this.draggables.add(d);
      if (this.element.firstChild) {
      	this.element.insertBefore(d.element, this.element.firstChild);
      } else {
      	this.element.appendChild(d.element);
      }
    }
  },
  
  removeDraggable: function(d) {
    if (this.draggables.contains(d)) {
      d.droppable = null;
      this.draggables.removeObject(d);
      this.element.removeChild(d.element);
    }
  },
  hasDraggable: function(d) {
    return this.draggables.contains(d);
  },
  onDragStart: tom.fnEmpty,
  onDrag: tom.fnEmpty,
  onDrop: tom.fnEmpty
});


tom.dnd.Droppables = {
  drops: [],
  dropTmpDiv: false,
  getDropTmpDiv: function() {
  	if (!this.dropTmpDiv) {
  	  var elem = document.createElement("DIV");
  	  elem.style.margin = "0 0 15px 0";
  	  elem.style.border = "2px dashed #999";
  	  elem.style.display = "none";
  	  document.body.appendChild(elem);
  	  
      this.dropTmpDiv = elem;
  	}
  	return this.dropTmpDiv;
  },
  hideDropTmpDiv: function() {
  	var dtd = this.getDropTmpDiv();
  	dtd.style.display = "none";
  	if (dtd.parentNode) {
  	  dtd.parentNode.removeChild(dtd);
  	}
  	document.body.appendChild(dtd);
  },
  add: function(dp) {
    this.drops.push(dp);
  },
  addDraggable: function(dg, dp) {
  	dp.addDraggable(dg);
  },
  removeDraggable: function(dg) {
  	for (var i = 0; i < this.drops.length; i++) {
	  this.drops[i].removeDraggable(dg);
  	}
  },
  detectDragStart: function(e) {
    tom.Position.prepare();
    var p = tom.Event.pointer(e);
    var droppable;
    var dgs;
    for (var i = 0; i < this.drops.length; i++) {
      droppable = this.drops[i];
      if (tom.Position.withinVertical(droppable.element, p.x, p.y)) {
        droppable.onDragStart(e);
//        droppable.draggables.removeObject(tom.dnd.Draggables.draggable);
        break;
      }
    }
    for (var i = 0; i < this.drops.length; i++) {
      droppable = this.drops[i];
//      droppable.currentMoveIndex = 65535;
      dgs = droppable.draggables;
      for (var j = 0; j < dgs.size(); j++) {
      	dgs.get(j).resetBound();
      }
      dgs.sort(function(a, b) { return a.bound.y - b.bound.y; });
    }
  },
  detectHover: function(e) {
    tom.Position.prepare();
    var p = tom.Event.pointer(e);
    var droppable;
    for (var i = 0; i < this.drops.length; i++) {
      droppable = this.drops[i];
      //检查指针在哪个droppable内
      if (tom.Position.withinVertical(droppable.element, p.x, p.y)) {
      	for (var j = 0; j < this.drops.length; j++) {
      	  if (this.drops[j] != droppable) {
      	  	this.drops[j].currentMoveIndex = 65535;
      	  }
      	}
      	var dgs = droppable.draggables;
      	var draggable = tom.dnd.Draggables.draggable;
      	//如果droppable内无draggable或者只有正在拖动的draggable
      	var index = -1;
		
		var dg = null;
		var bd = {x: 0, y: 0, w: 0, h: 0};
		var isSelf = false;
		if (dgs.size() == 0) {
		  index = -2048;
		} else if (dgs.size() == 1) {
		  dg = dgs.get(0);
		  if (dg == draggable) {
		  	index = 1024;
		  } else {
		  	if (droppable.currentMoveIndex == 1023) {
		  	  tom.extend(bd, dg.bound, {y: dg.bound.y + this.getDropTmpDiv().offsetHeight + 8});
		  	} else if (droppable.currentMoveIndex == 1025) {
		  	  tom.extend(bd, dg.bound);
		  	} else {
		  	  tom.extend(bd, dg.bound);
		  	}
		  	if (this.withinUpH(bd, p.y) || bd.y >= p.y) {
		  	  index = 1023;
		  	} else if (this.withinDownH(bd, p.y) || bd.y + bd.h <= p.y) {
		  	  index = 1025;
		  	}
		  }
		} else {
		  var prevDg, nextDg;
		  var offsetH = this.getDropTmpDiv().offsetHeight + 8;
          var selfIndex = dgs.indexOf(draggable);
		  for (var j = 0; j < dgs.size(); j++) {
		  	dg = dgs.get(j);
		  	
		  	prevDg = j == 0 ? null : dgs.get(j - 1);
		  	nextDg = j == dgs.size() - 1 ? null : dgs.get(j + 1);
		  	nextNextDg = j == dgs.size() - 2 ? null : dgs.get(j + 2);
		    if (j >= droppable.currentMoveIndex) {
		      if (selfIndex != -1 && j >= selfIndex) {
		      	tom.extend(bd, dg.bound, {y: dg.bound.y + offsetH - draggable.bound.h});
		      } else {
		      	tom.extend(bd, dg.bound, {y: dg.bound.y + offsetH});
		      }
		    } else {
		      if (selfIndex != -1 && j >= selfIndex) {
		      	tom.extend(bd, dg.bound - draggable.bound.h);
		      } else {
		        tom.extend(bd, dg.bound);
		      }
		    }
		    if (this.withinUpH(bd, p.y)) {
		      if (dg == draggable) {
		      	if (nextDg) {
		      	  index = j;
		      	  isSelf = true;
		      	} else {
		      	  index = dgs.size();
		      	}
		      } else {
		  	    index = j;
		      }
		      break;
		  	} else if (this.withinDownH(bd, p.y)) {
              if (nextDg && nextDg == draggable) {
              	if (nextNextDg) {
              	  index = j + 2;
              	} else {
              	  index = dgs.size();
              	}
              } else {
                index = j + 1;
              }
		  	  break;
		  	} else if (p.y <= bd.y) {
		  	  if (prevDg) {
		  	  	 if (p.y >= prevDg.bound.y) {
			      if (dg == draggable) {
			      	index = j;
			      	isSelf = true;
			      } else {
			  	    index = j;
			      }
		  	  	 }
		  	  } else {
			      if (dg == draggable) {
			      	index = j;
			      	isSelf = true;
			      } else {
			  	    index = j;
			      }
		  	  }
		      break;
		  	} else if (p.y >= bd.y + bd.h) {
		  	  if (nextDg) {
		  	    if (p.y <= nextDg.bound.y) {
			      if (dg == draggable) {
			      	index = j + 1;
			      } else {
			        if (nextDg == draggable) {
			          if (nextNextDg) {
			          	index = j + 2;
			          } else {
			          	index = dgs.size();
			          }
			        } else {
			          index = j + 1;
			        }
			      }
			      break;
		  	    }
		  	  } else {
		  	    index = j + 1;
		  	    break;
		  	  }
		  	}
		  }
		}
		
//		window.status = dgs.size() + "_" + index + "_" + droppable.currentMoveIndex;
		if (index != droppable.currentMoveIndex) {
		  droppable.currentMoveIndex = index;
		  this.getDropTmpDiv().style.display = "block";
		  this.getDropTmpDiv().style.height = draggable.bound.h + "px";
		  this.getDropTmpDiv().parentNode.removeChild(this.getDropTmpDiv());
		  if (index == -2048) {
		  	droppable.element.appendChild(this.getDropTmpDiv());
		  } else if (index == 1024) {
		  	droppable.element.appendChild(this.getDropTmpDiv());
		  } else if (index == 1023) {
		  	droppable.element.insertBefore(this.getDropTmpDiv(), droppable.draggables.get(0).element);
		  } else if (index == 1025) {
		  	droppable.element.appendChild(this.getDropTmpDiv());
		  } else if (index == dgs.size()) {
		  	droppable.element.appendChild(this.getDropTmpDiv());
		  } else {
		  	if (isSelf) {
		  	  droppable.element.insertBefore(this.getDropTmpDiv(), droppable.draggables.get(index + 1).element);  
		  	} else {
		  	  droppable.element.insertBefore(this.getDropTmpDiv(), droppable.draggables.get(index).element);
		  	}
		  }
//		  document.title = new Date().getTime();
		}
		
        //all back
        droppable.onDrag(e);
        break;
      }
    }
  },
  detectDrop: function(e) {
    var draggable = tom.dnd.Draggables.draggable;
    
    if (draggable.hasMoveElem) {
      tom.Position.prepare();
      var p = tom.Event.pointer(e);
      var droppable;
    
	  draggable.element.style.position = "relative";
	  draggable.element.style.left = "0";
	  draggable.element.style.top = "0";
	    
	  for (var i = 0; i < this.drops.length; i++) {
	    droppable = this.drops[i];
	    if (tom.Position.withinVertical(droppable.element, p.x, p.y)) {
	      droppable.onDrop(e);
	      
	      var index = droppable.currentMoveIndex;
	      if (index == 65535) {
	      	;
	      } else if (index == -2048) {
		  	draggable.endPoint = { sibling: null, parent: droppable.element };
		  } else if (index == 1024) {
		  	draggable.endPoint = { sibling: null, parent: droppable.element };
		  } else if (index == 1023) {
		  	draggable.endPoint = { sibling: droppable.draggables.get(0).element, parent: droppable.element };
		  } else if (index == 1025) {
		  	draggable.endPoint = { sibling: null, parent: droppable.element };
		  } else if (index == droppable.draggables.size()) {
		  	draggable.endPoint = { sibling: null, parent: droppable.element };
		  } else {
			draggable.endPoint = { sibling: droppable.draggables.get(index).element, parent: droppable.element };
		  }          
          draggable.element.style.width = "";
          
          for (var i = 0; i < this.drops.length; i++) {
	        this.drops[i].draggables.removeObject(draggable);
	        this.drops[i].currentMoveIndex = 65535;
	      }
          droppable.draggables.add(draggable);
          draggable.droppable = droppable;
	      break;
	    }
	  }
	  this.hideDropTmpDiv();
    }
  },
  within: function(bound, x, y) {
  	return x > bound.x
  	    && x < bound.x + bound.w
  	    && y > bound.y
  	    && y < bound.y + bound.h;
  },
  withinUpH: function(bound, y) {
  	return y > bound.y && y <= bound.y + bound.h / 2;
  },
  withinDownH: function(bound, y) {
  	return y > bound.y + bound.h / 2 && y < bound.y + bound.h;
  }
};

tom.dnd.Roller = {
  _roller: null,
  _rollType: 0,  //0:up/1:down
  _period: 33,
  _scrollHeight: 24,
  rollUp: function() {
    if (!this._roller || (this._roller && this._rollType != 0)) {
      this._roller = setInterval(function() {
          window.scrollBy(0, -1 * tom.dnd.Roller._scrollHeight);
        }, tom.dnd.Roller._period);
      this._rollType = 0;
    }
  },
  rollDown: function() {
    if (!this._roller || (this._roller && this._rollType != 1)) {
      this._roller = setInterval(function() {
          window.scrollBy(0, tom.dnd.Roller._scrollHeight);
        }, tom.dnd.Roller._period);
      this._rollType = 1;
    }
  },
  stop: function() {
    if (this._roller) {
      clearInterval(this._roller);
      this._roller = null;
    }
  }
};
////////// tom.widget.js //////////
//package tom.widget
tom.widget = {};

/**
 * class Component
 */
tom.widget.Component = tom.Class.create();
tom.extend(tom.widget.Component.prototype, {
  initialize: function(id, params) {
  	params = params ? params : {};
    //All "Container"'s properties here.
    var options = {
      visible: true,
      id: id,
      element: null,
      styleClass: "",
      zIndex: 0,
      fnCreateElement: null
    };
    tom.extend(this, options, params);
    //If function "createElement" exists, call it for creating element.
    if (this.fnCreateElement) {
      this.fnCreateElement();
    }
    this.element = typeof(id) == "string" ? $(id) : id;
    this._lastDisplay = tom.Element.getStyle(this.element, "display");
  },
  getId: function() {
  	return this.id;
  },
  getElement: function() {
  	return this.element;
  },
  isVisible: function() {
  	return this.visible;
  },
  setVisible: function(v) {
  	this.visible = v;
  	this.element.style.display = v ? "block" : "none";
  },
  setWidth: function(w) {
  	this.getElement().style.width = w + "px";
  },
  setHeight: function(h) {
  	this.getElement().style.height = h + "px";
  },
  setLeft: function(l) {
  	this.getElement().style.left = l + "px";
  },
  setTop: function(t) {
  	this.getElement().style.top = t + "px";
  },
  getWidth: function() {
  	return this.getElement().offsetWidth;
  },
  getHeight: function() {
  	return this.getElement().offsetHeight;
  },
  setStyleClass: function(c) {
  	this.styleClass = c;
  	this.element.className = c;
  },
  setZIndex: function(zIndex) {
  	this.zIndex = zIndex;
  	this.getElement().style.zIndex = zIndex;
  },
  getZIndex: function() {
  	return this.zIndex;
  }
});

/**
 * class Window
 * extends tom.widget.Component
 */
tom.widget.Window = tom.Class.create();
tom.extend(tom.widget.Window.prototype, tom.widget.Component.prototype, {
  initialize: function(id, param) {
    tom.widget.Component.prototype.initialize.apply(this, [id, param]);
    //All "Window"'s properties here.
    var options = {
      handle: id,
      title: null,
      btnClose: null,
      zIndex: 1,
      isModal: false,
      canDrag: true
    };
    tom.extend(this, options, param);
    
    this.setZIndex(this.zIndex);
    this.title = $(this.title);
    
    var _w = this;
    //Add window close event.
    if (this.btnClose) {
      this.btnClose = $(this.btnClose);
      this.btnClose.onmousedown = function(e) {
        tom.Event.stop(e || window.event);
      }
      this.btnClose.onclick = function(e) {
        e = e || window.event;
        if (_w.onClose(e)) {
          _w.hide();
        }
        tom.Event.stop(e);
      }
    }
    if (this.canDrag) {
      this.handle = $(this.handle);
      new tom.dnd.Draggable(this.getId(), this);
    }
    
    //模态遮罩
    this.maskWindow = new tom.widget.MaskWindow(this.id + "_moduleframe", 
      {fnCreateElement: function() {
        var elem = document.createElement("DIV");
        elem.id = _w.id + "_moduleframe";
        tom.extend(elem.style, {
      	  display: "none",
		  position: "absolute",
		  backgroundColor: "#eee",
		  zIndex: _w.zIndex - 1,
		  opacity: "0.50",
		  filter: "Alpha(Opacity=50)"
        });
        document.body.appendChild(elem);
      }}
    );
  },
  setTitle: function(t) {
    this.title.innerHTML = t;
  },
  getTitle: function() {
  	return this.title.innerHTML;
  },
  show: function() {
  	if (this.isModal) {
  	  this.maskWindow.setVisible(true);
      this.maskWindow.show();
  	}
  	this.setVisible(true);
  },
  hide: function() {
  	if (this.isModal) {
  	  this.maskWindow.setVisible(false);
  	}
  	this.setVisible(false);
  },
  isShow: function() {
  	return this.getVisible();
  },
  setCenter: function() {
    this.setLeft(tom.Position.getWindowScrollLeft() + (tom.Position.getWindowClientWidth() - this.getWidth()) / 2);
    this.setTop(tom.Position.getWindowScrollTop() + (tom.Position.getWindowClientHeight() - this.getHeight()) / 2);
  },
  onClose: tom.fnTrue
});

/**
 * 
 */
tom.widget.MaskWindow = tom.Class.create();
tom.extend(tom.widget.MaskWindow.prototype, tom.widget.Component.prototype, {
  initialize: function(id, params) {
  	tom.widget.Component.prototype.initialize.apply(this, [id, params]);
  },
  show: function() {
  	this.setVisible(true);
    this.setLeft(0);
    this.setTop(0);
    this.setWidth(tom.Position.getWindowScrollWidth());
    this.setHeight(tom.Position.getWindowScrollHeight());
  },
  hide: function() {
  	this.setVisible(false);
  }
});

