if (typeof(tm) == "undefined" || typeof(tm.dnd) == "undefined") {
  throw new Error("tm.widget Require tm.dnd");
}
tm.widget = {};

/**
 * class Component
 */
tm.widget.Component = Class.create();
tm.extend(tm.widget.Component.prototype, {
  initialize: function(id, params) {
  	params = params ? params : {};
    //All "Container"'s properties here.
    var options = {
      bounds: {x: 0, y: 0, w: 0, h: 0},
      visible: false,
      id: id,
      element: null,
      styleClass: "",
      fnCreateElement: null,
      _hasInitBound: false
    };
    //Copy properties to this.
    tm.extend(this, options, params);
    //If function "createElement" exists, call it for creating element.
    if (this.fnCreateElement != null) {
      this.fnCreateElement();
    }
    this.element = typeof(id) == "string" ? $(id) : id;
//    this.visible = tm.Element.getStyle(this.element, "display") == "none" ? false : true;
//    if (this.visible) {
//      this._initBound();
//      this._hasInitBound = true;
//    }
  },
  getId: function() {
  	return this.id;
  },
  getElement: function() {
  	return this.element;
  },
  setBounds: function(b) {
  	if (!this._hasInitBound && this.visible) {
      this._initBound();
      this._hasInitBound = true;
    }
  	tm.extend(this.bounds, b);
  	tm.Element.setStyle(this.element, "left", this.bounds.x + "px");
  	tm.Element.setStyle(this.element, "top", this.bounds.y + "px");
  	tm.Element.setStyle(this.element, "width", this.bounds.w + "px");
  	tm.Element.setStyle(this.element, "height", this.bounds.h + "px");
  },
  getBounds: function() {
  	 if (!this._hasInitBound && this.visible) {
      this._initBound();
      this._hasInitBound = true;
    }
    return this.bounds;
  },
  setHeight: function(h) {
  	this.bounds.h = h < 0 ? 0 : h;
  	this.element.style.height = this.bounds.h + "px";
  },
  getHeight: function() {
    if (!this._hasInitBound && this.visible) {
      this._initBound();
      this._hasInitBound = true;
    }
  	return this.bounds.h;
  },
  setWidth: function(w) {
  	this.bounds.w = w < 0 ? 0 : w;
  	this.element.style.width = this.bounds.w + "px";
  },
  getWidth: function() {
  	 if (!this._hasInitBound && this.visible) {
      this._initBound();
      this._hasInitBound = true;
    }
    return this.bounds.w;
  },
  setLeft: function(x) {
  	this.bounds.x = x;
  	this.element.style.left = x + "px";
  },
  getLeft: function() {
  	 if (!this._hasInitBound && this.visible) {
      this._initBound();
      this._hasInitBound = true;
    }
  	return this.bounds.x;
  },
  setTop: function(y) {
  	this.bounds.y = y;
  	this.element.style.top = y + "px";
  },
  getTop: function() {
  	 if (!this._hasInitBound && this.visible) {
      this._initBound();
      this._hasInitBound = true;
    }
    return this.bounds.y;
  },
  isVisible: function() {
  	return this.visible;
  },
  setVisible: function(v) {
  	if (this.visible == v) {
  	  return;
  	}
  	this.visible = v;
  	this.element.style.display = v ? "block" : "none";
  },
  setStyleClass: function(c) {
  	this.styleClass = c;
  	this.element.className = c;
  },
  _initBound: function() {
    //Compute bounds.
    var pos = tm.Position.cumulativeOffset(this.element);
    var size = tm.Position.cumulativeSize(this.element);
    this.bounds.x = pos.left;
    this.bounds.y = pos.top;
    this.bounds.w = size.width;
    this.bounds.h = size.height;
    this._hasInitBound = true;
  }
});

/**
 * class Container
 */
tm.widget.Container = Class.create();
tm.extend(tm.widget.Container.prototype, tm.widget.Component.prototype, {
  initialize: function(id, params) {
  	params = params ? params : {};
  	//Call super.
    tm.widget.Component.prototype.initialize.apply(this, [id, params]);
    //fields
    var fields = {
      components: new tm.util.Set(),
      isAddElemenet: false
    };
    tm.extend(this, fields, params);
  },
  add: function(c, i) {
    this.components.add(c);
    if (this.isAddElemenet) {
      if (typeof(i) != "undefined") {
        this.getElement().insertBefore(c.getElement(), this.components.get(i).getElement());
      } else {
        this.getElement().appendChild(c.getElement());
      }
    }
  },
  remove: function(c) {
    this.components.removeObject(c);
    this.getElement().removeChild(c.getElement());
  }
});

/**
 * class Window
 * extends tm.widget.Container
 */
tm.widget.Window = Class.create();
tm.extend(tm.widget.Window.prototype, tm.widget.Container.prototype, {
  initialize: function(id, param) {
  	//Call super.
    tm.widget.Container.prototype.initialize.apply(this, [id, param]);
    //All "Window"'s properties here.
    var options = {
      handle: id,
      title: null,
      btnClose: null,
      btnMinimum: null,
      zIndex: 96,
      isModal: false,
      canDrag: true,
      _isMinimum: false,
      _initHeight: 0
    };
    tm.extend(this, options, param);
    
    this.getElement().style.zIndex = this.zIndex;
    
    var _w = this;
    if (this.title) {
      this.title = $(this.title);
    }
    //Add window close event.
    if (this.btnClose) {
      this.btnClose = $(this.btnClose);
      this.btnClose.onmousedown = function(e) {
      	tm.Event.stop(e || window.event);
      }
      this.btnClose.onclick = function(e) {
      	e = e || window.event;
      	if (_w.onClose(e)) {
      	  _w.hide();
      	}
      	tm.Event.stop(e);
      }
    }
    if (this.btnMinimum) {
      this.btnMinimum = $(this.btnMinimum);
      this.btnMinimum.onmousedown = function(e) {
      	if (_w.onMinimum()) {
      	  e = e ? e : window.event;
      	  tm.Event.stop(e);
      	}
      }
      this.btnMinimum.onclick = function(e) {
      	if (_w.onMinimum()) {
      	  e = e ? e : window.event;
      	  if (_w.isMinimum()) {
      	  	_w.reveal();
      	  } else {
      	  	_w.minimum();
      	  }
      	  tm.Event.stop(e);
      	}
      }
    }
    if (this.canDrag) {
      //Add draggable.
      new tm.dnd.Draggable(this.getElement(), 
        { handle: _w.handle, 
          opacity: false,
          onDragEnd: function() {
            //When drag over, recompute position.
            var pos = tm.Position.cumulativeOffset(this.element);
            _w.setLeft(pos.left);
            _w.setTop(pos.top);
          }
        });
    }
    if (this.handle) {
      this.handle = $(this.handle);
    }
    
    //模态遮罩
    this.modalFrame = new tm.widget.Component(this.id + "_moduleframe", 
      {fnCreateElement: function() {
        var elem = document.createElement("DIV");
        elem.id = _w.id + "_moduleframe";
        tm.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.modalFrame.setVisible(true);
  	  var bd = tm.Position.windowScrollBound();
      this.modalFrame.setBounds({x: 0, y: 0, w: bd.w, h: bd.h});
  	}
  	this.setVisible(true);
  	this.reveal();
  },
  hide: function() {
  	if (this.isModal) {
  	  this.modalFrame.setVisible(false);
  	}
  	this.setVisible(false);
  },
  isShow: function() {
  	return this.getVisible();
  },
  isMinimum: function() {
  	return this._isMinimum;
  },
  minimum: function() {
    if (!this.isMinimum()) {
      this._initHeight = this.getHeight();
      this.setHeight(this.handle.offsetHeight);
      this._isMinimum = true;
      
      this.getElement().style.overflow = "hidden";
    }
  },
  reveal: function() {
  	if (this.isMinimum()) {
      this.setHeight(this._initHeight);
      this._isMinimum = false;
  	}
  },
  setCenter: function() {
  	var p = tm.Position.windowScrollPosition();
  	var ws = tm.Position.windowClientSize();
    this.setTop(p.y + (ws.h - this.getHeight()) / 2);
    this.setLeft(p.x + (ws.w - this.getWidth()) / 2);
  },
  onClose: tm.fnTrue,
  onMinimum: tm.fnTrue
});

/**
 * class Menu
 * extends tm.widget.Container
 */
tm.widget.Menu = Class.create();
tm.extend(tm.widget.Menu.prototype, tm.widget.Container.prototype, {
  initialize: function(id, params) {
  	params = params ? params : {};
  	//Call super.
    tm.widget.Container.prototype.initialize.apply(this, [id, params]);
    var fields = {
    };
    tm.extend(this, fields, params);
    var m = this;
    tm.Event.addEvent(document, "click", 
      function() {
      	if (m.isShow()) {
      	  m.hide();
      	}
      }, true);
  },
  addMenuItem: function(mi) {
  	mi.setMenu(this);
  	this.add(mi);
  },
  removeMenuItem: function(mi) {
  	mi.setMenu(null);
  	this.remove(mi);
  },
  show: function() {
  	if (!this.isVisible()) {
      this.setVisible(true);  		
  	}
  },
  hide: function() {
  	if (this.isVisible()) {
  	  this.setVisible(false);
  	}
  },
  isShow: function() {
  	return this.isVisible();
  },
  showOnPointer: function(e) {
  	if (!this.isVisible()) {
  	  var p = tm.Event.pointer(e);
  	  this.setLeft(p.x);
  	  this.setTop(p.y);
  	  this.show();
  	}
  }
});
/**
 * class MenuItem
 */
tm.widget.MenuItem = Class.create();
tm.extend(tm.widget.MenuItem.prototype, tm.widget.Component.prototype, {
  initialize: function(id, params) {
  	params = params ? params : {};
  	//Call super.
    tm.widget.Component.prototype.initialize.apply(this, [id, params]);
	var fields = {
	  menu: null,
      focusStyle: "",
      blurStyle: "",
      onClick: function(e) {}
	};
	tm.extend(this, fields, params);
	var mi = this;
	var elem = mi.getElement();
	elem.style.cursor = "default";
    tm.Event.addEvent(this.getElement(), "mousemove", 
      function(e) {
//        mi.getElement().style.backgroundColor = "#ccc";
      }, true);
    tm.Event.addEvent(this.getElement(), "mouseout", 
      function(e) {
//        mi.getElement().style.backgroundColor = "";
      }, true);
    tm.Event.addEvent(this.getElement(), "click", 
      function(e) {
      	e = e ? e : window.event;
        mi.onClick(e);
        mi.getMenu().hide();
        tm.Event.stop(e);
        return false;
      }, true);
    
  },
  getMenu: function() {
  	return this.menu;
  },
  setMenu: function(m) {
  	this.menu = m;
  }
});


/**
 * Function Alert
 */
tm.widget.Alert = function(msg, ico, fn, autoHide) {
  if (!tm.widget.Alert.singleton) {
  	tm.widget.Alert.singleton = new tm.widget.AlertWindow(tm.widget.Alert.config.wid, {});
  }
  var aw = tm.widget.Alert.singleton;
  switch (true) {
  	case typeof(fn) == "string":
  	  aw.fnCallback = new Function("e", fn);
  	  break;
  	case fn instanceof Function:
  	  aw.fnCallback = fn;
  	  break;
  	default:
  	  aw.fnCallback = tm.fnTrue;
  	  break;
  }
  aw.setIcon(ico || "OK");
  aw.setMessage(msg);
  aw.setAutoHide(typeof(autoHide) == "undefined" ? -1 : autoHide);
  aw.show();
  aw.setCenter();
}
tm.widget.AlertWindow = Class.create();
tm.extend(tm.widget.AlertWindow.prototype, tm.widget.Window.prototype, {
  initialize: function(id, params) {
  	var fields = {
  	  canDrag: false,
  	  modalFrame: null,
  	  autoHide: 0,
  	  timeout: null
  	};
  	tm.extend(fields, tm.widget.Alert.config, params || {});
    //Call super.
    tm.widget.Window.prototype.initialize.apply(this, [id, fields]);
    
    var _w = this;
    this.btnOk = $(this.btnOk);
    this.btnOk.onclick = function(e) {
      _w.hide();
      _w.modalFrame.setVisible(false);
      _w.fnCallback(e || window.event);
  	  if (_w.timeout) {
  	    clearTimeout(_w.timeout);
  	    _w.timeout = null;
  	  }
    }
    this.content = $(this.content);
    this.icon = $(this.icon);
    
    //模态遮罩
    this.modalFrame = new tm.widget.Component(this.modalFrameId, {fnCreateElement: function() {
      var elem = document.createElement("DIV");
      elem.id = _w.modalFrameId;
      tm.extend(elem.style, {
      	  display: "none",
		  position: "absolute",
		  backgroundColor: "#eee",
		  zIndex: _w.zIndex - 1,
		  opacity: "0.50",
		  filter: "Alpha(Opacity=50)"
      });
      document.body.appendChild(elem);
    }});
    
    //设置alert样式
    tm.extend(this.getElement().style, {
      position: "absolute",
      width: "240px",
      backgroundColor: "#fff",
      zIndex: _w.zIndex
    });
  },
  setMessage: function(msg) {
  	this.content.innerHTML = msg.replace(/\r\n/i, "<br />");
  },
  setIcon: function(ico) {
  	switch (ico) {
  	  case "INFO":
  	    this.icon.src = "/images/info.gif";
  	    break;
  	  case "ERROR":
  	    this.icon.src = "/images/error.gif";
  	    break;
  	  case "OK":
  	    this.icon.src = "/images/ok.gif";
  	    break;
  	  default:
  	    break;
  	}
  },
  setAutoHide: function(ah) {
  	this.autoHide = ah;
  },
  onClose: function(e) {
  	this.modalFrame.setVisible(false);
  	this.fnCallback(e || window.event);
  	if (this.timeout) {
  	  clearTimeout(this.timeout);
  	  this.timeout = null;
  	}
  	return true;
  },
  fnCallback: function(e) {
  	return;
  },
  show: function() {
  	this.modalFrame.setVisible(true);
  	var bd = tm.Position.windowScrollBound();
    this.modalFrame.setBounds({x: 0, y: 0, w: bd.w, h: bd.h});
  	this.setVisible(true);
  	var _w = this;
    if (this.autoHide != -1) {
      this.timeout = setTimeout(
        function() {
	      _w.hide();
	      _w.modalFrame.setVisible(false);
	      _w.fnCallback();
	      _w.timeout = null;
        }, 
        this.autoHide
      );
    }
  }
});

tm.widget.Confirm = function(msg, fnOk, fnCancel, title) {
  if (!tm.widget.Confirm.singleton) {
  	tm.widget.Confirm.singleton = new tm.widget.ConfirmWindow(tm.widget.Confirm.config.wid, {});
  }
  var cw = tm.widget.Confirm.singleton;
  cw.fnOk = fnOk ? (fnOk instanceof Function) ? fnOk : (typeof(fnOk) == "string" ? new Function("e", fnOk) : tm.fnTrue) : tm.fnTrue;
  cw.fnCancel = fnCancel ? (fnCancel instanceof Function) ? fnCancel : (typeof(fnCancel) == "string" ? new Function("e", fnCancel) : tm.fnTrue) : tm.fnTrue;;
  cw.setTitle(title || "确认");
  cw.setMessage(msg);
  cw.show();
  cw.setCenter();
}
tm.widget.ConfirmWindow = Class.create();
tm.extend(tm.widget.ConfirmWindow.prototype, tm.widget.Window.prototype, {
  initialize: function(id, params) {
  	var fields = {
  	  canDrag: false,
  	  modalFrame: null
  	};
  	tm.extend(fields, tm.widget.Confirm.config, params || {});
    //Call super.
    tm.widget.Window.prototype.initialize.apply(this, [id, fields]);
    
    var _w = this;
    this.btnOk = $(this.btnOk);
    this.btnOk.onclick = function(e) {
      _w.hide();
      _w.modalFrame.setVisible(false);
      _w.fnOk(e || window.event);
    }
    this.btnCancel = $(this.btnCancel);
    this.btnCancel.onclick = function(e) {
      _w.hide();
      _w.modalFrame.setVisible(false);
      _w.fnCancel(e || window.event);
    }
    
    this.title = $(this.title);
    this.content = $(this.content);
    this.icon = $(this.icon);
    
    //模态遮罩
    this.modalFrame = new tm.widget.Component(this.modalFrameId, {fnCreateElement: function() {
      var elem = document.createElement("DIV");
      elem.id = _w.modalFrameId;
      tm.extend(elem.style, {
      	  display: "none",
		  position: "absolute",
		  backgroundColor: "#eee",
		  zIndex: _w.zIndex - 1,
		  opacity: "0.5",
		  filter: "Alpha(Opacity=50)"
      });
      document.body.appendChild(elem);
    }});
    
    //设置alert样式
    tm.extend(this.getElement().style, {
      position: "absolute",
      width: "240px",
      backgroundColor: "#fff",
      zIndex: _w.zIndex
    });
  },
  setTitle: function(title) {
  	this.title.innerHTML = title;
  },
  setMessage: function(msg) {
  	this.content.innerHTML = msg;
  },
  onClose: function(e) {
  	this.modalFrame.setVisible(false);
  	this.fnCancel(e || window.event);
  	return true;
  },
  fnOk: function(e) {
  	return;
  },
  fnCancel: function(e) {
  	return;
  },
  show: function() {
  	this.modalFrame.setVisible(true);
  	var bd = tm.Position.windowScrollBound();
    this.modalFrame.setBounds({x: 0, y: 0, w: bd.w, h: bd.h});
  	this.setVisible(true);
  }
});

tm.widget.Information = function(msg, autoHide, fn) {
  if (!tm.widget.Information.singleton) {
  	tm.widget.Information.singleton = new tm.widget.InformationDialog(tm.widget.Information.config.wid, {});
  }
  var iw = tm.widget.Information.singleton;
  switch (true) {
  	case typeof(fn) == "string":
  	  iw.fnCallback = new Function("e", fn);
  	  break;
  	case fn instanceof Function:
  	  iw.fnCallback = fn;
  	  break;
  	default:
  	  iw.fnCallback = tm.fnTrue;
  	  break;
  }
  iw.setMessage(msg);
  iw.setAutoHide(autoHide);
  iw.show();
  iw.setCenter();
}
tm.widget.InformationDialog = Class.create();
tm.extend(tm.widget.InformationDialog.prototype, tm.widget.Component.prototype, {
  initialize: function(id, params) {
  	var fields = {
  	  modalFrame: null,
  	  timeout: null
  	};
  	tm.extend(fields, tm.widget.Information.config, params || {});
    //Call super.
    tm.widget.Component.prototype.initialize.apply(this, [id, fields]);
    
    this.content = $(this.content);
    this.icon = $(this.icon);
    
    var _w = this;
    //模态遮罩
    this.modalFrame = new tm.widget.Component(this.modalFrameId, {fnCreateElement: function() {
      var elem = document.createElement("DIV");
      elem.id = _w.modalFrameId;
      tm.extend(elem.style, {
      	  display: "none",
		  position: "absolute",
		  backgroundColor: "#eee",
		  zIndex: _w.zIndex - 1,
		  opacity: "0.50",
		  filter: "Alpha(Opacity=50)"
      });
      document.body.appendChild(elem);
    }});
    
    //设置alert样式
    tm.extend(this.getElement().style, {
      position: "absolute",
      width: "240px",
      border: "1px solid #666",
      backgroundColor: "#fff",
      textAlign: "center",
      padding: "32px 0",
      zIndex: _w.zIndex
    });
  },
  setMessage: function(msg) {
  	this.content.innerHTML = msg.replace(/\r\n/i, "<br />");
  },
  setAutoHide: function(ah) {
  	this.autoHide = ah;
  },
  onClose: function(e) {
  	this.modalFrame.setVisible(false);
  	this.fnCallback(e || window.event);
  	if (this.timeout) {
  	  clearTimeout(this.timeout);
  	  this.timeout = null;
  	}
  	return true;
  },
  fnCallback: function(e) {
  	return;
  },
  show: function() {
  	this.modalFrame.setVisible(true);
  	var bd = tm.Position.windowScrollBound();
    this.modalFrame.setBounds({x: 0, y: 0, w: bd.w, h: bd.h});
  	this.setVisible(true);
  	var _w = this;
    if (this.autoHide != -1) {
      this.timeout = setTimeout(
        function() {
	      _w.setVisible(false);
	      _w.modalFrame.setVisible(false);
	      _w.fnCallback();
	      _w.timeout = null;
        }, 
        this.autoHide
      );
    }
  },
  setCenter: function() {
  	var p = tm.Position.windowScrollPosition();
  	var ws = tm.Position.windowClientSize();
    this.setTop(p.y + (ws.h - this.getHeight()) / 2);
    this.setLeft(p.x + (ws.w - this.getWidth()) / 2);
  }
});

tm.widget.LoginWindow = function(backurl) {
  if (!tm.widget.LoginWindow.singleton) {
  	tm.widget.LoginWindow.singleton = new tm.widget.LoginFrame(tm.widget.LoginWindow.config.wid, {canDrag: false, isModal: true});
  }
  var lw = tm.widget.LoginWindow.singleton;
  lw.setBackurl(document.location);
  lw.show();
  lw.setCenter();
}
tm.widget.LoginFrame = Class.create();
tm.extend(tm.widget.LoginFrame.prototype, tm.widget.Window.prototype, {
  initialize: function(id, params) {
  	var fields = {
  	  backurl: ''
  	};
  	tm.extend(fields, tm.widget.LoginWindow.config, params || {});
    //Call super.
    tm.widget.Window.prototype.initialize.apply(this, [id, fields]);
    
    tm.extend(this.getElement().style,
      {
      	position: "absolute",
      	display: "none"
      });
    this.txtUsername = $(this.txtUsername);
    this.backurl = $(this.backurl);
  },
  setBackurl: function(backurl) {
  	this.backurl.value = backurl;
  },
  show: function() {
  	tm.widget.Window.prototype.show.apply(this);
  	var _this = this;
  	setTimeout(function() {
  		_this.txtUsername.focus();
  	  },
  	  300
  	);
  	
  }
});