define(['scripts/knockout-3.3.0', 'scripts/act', 'scripts/CallWebObject.js', 'scripts/ACTUtils.js', "jqx/jqxtooltip"], function(ko, ACTSocket, InvokeCallback, ACTUtils) {
	function ComponentBaseViewModel(definition, element) {
		var self = this;

		ACTUtils.Log("Load component: "+definition.Name, 3);
		this.element = element;
		this.beforeResizeFunctions = [];
		this.resizeFunctions = [];
		this.lockFunctions = [];
		this.unlockFunctions = [];
		this.lockElementHidded = [];
		this.disposeFunctions = [];
		this.showFunctions = [];
		this.hideFunctions = [];
		this.updateCSSFunctions = [];
		this.$realElement = $(this.element);
		definition.baseModel = this;

		this.lockKeys = {}
		this.definition = ko.observable(definition);
		definition.ready = ko.observable(false);

		$(self.element).addClass("not_ready");
		definition.ready.subscribe(function(newVal) {
			if (newVal) {
				ACTUtils.Log("Ready : " + definition.Name, 2);
				$(self.element).addClass("ready");
				$(self.element).removeClass("not_ready");
			} else {
				ACTUtils.Log("Not Ready : " + definition.Name, 2);
				$(self.element).removeClass("ready");
				$(self.element).addClass("not_ready");
			}

			this.gridPanel.componentReady(this, newVal);
			InvokeCallback("", this.OnReadyStateChange, [newVal]);

			// to be call after the data-bind
			if (newVal) {
				setTimeout(function(definition) {
					updateClassNames(definition);
					if (updateCSS(definition))
						self.timeoutResize();
				}, 0, this);
			}
		}.bind(definition));

		var updateClassNames = function(definition) {
			var $targetElement = self.$realElement.find(".content").first();
			for (var i = 0; i < definition.ClassNames.length; i++) {
				var className = definition.ClassNames[i];
				if (!$targetElement.hasClass(className))
				{
					ACTUtils.Log("add class for " + definition.Name + " : " + className, 2);
					$targetElement.addClass(className);
				}
			}

			for (var i = 0; i < definition.RemovedClassNames.length; i++) {
				var className = definition.RemovedClassNames[i];
				if ($targetElement.hasClass(className))
				{
					ACTUtils.Log("remove class for " + definition.Name + " : " + className, 2);
					$targetElement.removeClass(className);
				}
			}
		}
		updateClassNames(definition);

		// return true if resize needded
		self.previousReceiveCSSValue = {}
		var updateCSS = function(definition) {
			// apply css
			var wantResize = false;
			var cssProperties = definition.CSSProperties;
			if (cssProperties && cssProperties.length > 0) {
				ACTUtils.Log("Update css of " + definition.Name + definition.Id, 2);
				for (var i = 0; i < cssProperties.length; i++) {
					var cssProperty = cssProperties[i];
					var $targetElement = this.$realElement.find(".content").first();
					if (cssProperty.Filter && cssProperty.Filter != "") {
						$targetElement = $targetElement.find(cssProperty.Filter);
					}

					var oldValue = self.previousReceiveCSSValue[cssProperty.Name];
					if (oldValue != cssProperty.Value) {
						ACTUtils.Log("==> " + cssProperty.Name + " (" + cssProperty.Filter + ") " + cssProperty.Value, 2);
						$targetElement.css(cssProperty.Name, cssProperty.Value);
						if (cssProperty.Name.indexOf("border") >= 0 || cssProperty.Name.indexOf("margin") >= 0)
							wantResize = true;

						if (this.updateCSSFunctions.length != 0)
							ACTUtils.CallFunctions(self.updateCSSFunctions, cssProperty);

						self.previousReceiveCSSValue[cssProperty.Name] = cssProperty.Value;
					}
				}

				if (wantResize)
					ACTUtils.Log("UpdateCSS want resize", 2);
			}
			return wantResize;
		}.bind(this)

		this.updateTooltip = function() {
			var tooltip = self.definition().Tooltip;
			if (tooltip != self.previousTooltip && !ACTUtils.StringIsNullOrEmpty(tooltip))
				ACTUtils.CreateTooltip(self.$realElement, tooltip, false);
			self.previousTooltip = tooltip;
		};
		this.updateTooltip();

		this.callShowFunctions = function() {
			if (self.definition().Visible)
				ACTUtils.CallFunctions(self.showFunctions);
		}

		this.callHideFunctions = function() {
			if (self.definition().Visible)
				ACTUtils.CallFunctions(self.hideFunctions);
		}

		this.isVisible = function() {
			if (!self.definition().Visible)
				return false;
			var parent = self.definition().gridPanel;
			if (parent != null && parent.baseModel != null)
				return parent.baseModel.isVisible();
			return true;
		}

		var updateVisibility = function() {
			// we don't want to set the component ready if it wasn't
			var changeReady = definition.ready();
			if (changeReady) definition.ready(false);

			if (this.definition().Visible) {
				$(this.element).show();
				this.callShowFunctions();
			} else {
				$(this.element).hide();
				this.callHideFunctions();
			}

			if (changeReady) definition.ready(true);
		}.bind(this)
		updateVisibility();

		this.timeoutResize = function() {
			// timeout cause we want to let the visibility/css the time to be updated
			setTimeout(function() {
				var $content = $(this.element).find(".content");
				var oldOverflowState = ACTUtils.GetOverflowsAndSetThemTo($content, "hidden");
				this.setDirty();
				this.resize();
				ACTUtils.SetOverflows($content, oldOverflowState);

				// cause our size can be smaller in case of border
				ACTUtils.UpdateOverflow($(self.element).parents());
			}.bind(this), 0);
		}

		var onUpdateBaseComponent = function(obj) {
			ACTUtils.Log("update base component", 2);
			if (!ACTUtils.StringIsNullOrEmpty(obj.DoLock)) {
				this.lock(obj.DoLock);
				return;
			} else if (!ACTUtils.StringIsNullOrEmpty(obj.DoUnlock)) {
				this.unlock(obj.DoUnlock);
				return;
			} else if (obj.SetUnready) {
				ACTUtils.Log("SetUnready: " + definition.Name + definition.Id, 2);
				definition.ready(false);
				return;
			} else if (obj.Pinged) {
				ACTUtils.Log(this.definition().Name + " ping back", 2);
				InvokeCallback("", this.definition().OnPing, []);
				return;
			} else if (obj.TriggerAllClick) {
				$(element).click();
				return;
			} else if (obj.TriggerRightClick) {
				$(element).triggerHandler('contextmenu');
				return;
			}

			this.definition().WidthType = obj.WidthType;
			this.definition().WidthValue = obj.WidthValue;
			this.definition().HeightType = obj.HeightType;
			this.definition().HeightValue = obj.HeightValue;
			this.definition().BottomAttachment = obj.BottomAttachment;
			this.definition().TopAttachment = obj.TopAttachment;
			this.definition().LeftAttachment = obj.LeftAttachment;
			this.definition().RightAttachment = obj.RightAttachment;
			this.definition().ClickHaveACallback = obj.ClickHaveACallback;
			this.definition().RightClickHaveACallback = obj.RightClickHaveACallback;
			this.definition().Tooltip = obj.Tooltip;

			var oldVisibility = this.definition().Visible;
			this.definition().Visible = obj.Visible;

			var wantResize = false;

			definition.CSSProperties = obj.CSSProperties;
			definition.ClassNames = obj.ClassNames;
			definition.RemovedClassNames = obj.RemovedClassNames;
			if (definition.ready()) {
				updateClassNames(definition);
				if (updateCSS(definition))
					wantResize = true;
			}

			this.updateTooltip();

			if (oldVisibility != this.definition().Visible)
			{
				updateVisibility();
				ACTUtils.Log("Visibility of " + definition.Name + definition.Id + " change gonna resize.", 2);
				wantResize = true;
			}

			if (wantResize) {
				this.timeoutResize();
			}
		}.bind(this)

		this.x = ko.observable(0);
		this.y = ko.observable(0);
		this.w = ko.observable(0);
		this.h = ko.observable(0);
		this.width = 0;
		this.height = 0;
		this.handleComponentSize = true;
		this.xdirty = true;
		this.ydirty = true;
		this.wdirty = true;
		this.hdirty = true;
		this.computeDimDirty = true;

		this.computeWidthFunction = null;
		this.setComputeWidthFunction = function(f) {
			this.computeWidthFunction = f;
		}

		this.computeHeightFunction = null;
		this.setComputeHeightFunction = function(f) {
			this.computeHeightFunction = f;
		}

		this.setWidth = function(w) {
			if (this.handleComponentSize) {
				this.w(w);
				if (w == null)
					this.$realElement.find(".content").first().css("width", "");
			}
			this.width = w;
		}

		this.setHeight = function(h) {
			if (this.handleComponentSize) {
				this.h(h);
				if (h == null)
					this.$realElement.find(".content").first().css("height", "");
			}
			this.height = h;
		}

		this.publicCollections = {}
		this.GetCollection = function(name) {
			if (!this.publicCollections[name])
				this.publicCollections[name] = [];
			return this.publicCollections[name];
		}

		this.setDirtyPosition = function() {
			this.xdirty = true;
			this.ydirty = true;
		}.bind(this);

		this.setDirty = function() {
			ACTUtils.Log("SetDirty : " + this.definition().Name, 1);

			this.setDirtyPosition();

			// don't want to keep old value that could be use to compute new size
			this.setWidth(null);
			this.setHeight(null);

			this.wdirty = true;
			this.hdirty = true;
			this.computeDimDirty = true;
		}.bind(this);

		this.getChildrenBorderSize = function() {
			var $children = $(this.element).children();
			return ACTUtils.GetBorderSize($children);
		}

		this.getChildrenPaddingSize = function() {
			var $children = $(this.element).children();
			return ACTUtils.GetPaddingSize($children);
		}

		this.getChildrenOuterSize = function() {
			var $children = $(this.element).children();
			return ACTUtils.GetOuterSize($children);
		}

		this.getParentSize = function() {
			var parent = null;

			var path = this.definition().Path;
			if (path.length > 1) {
				var parentName = path[path.length - 2];
				var parents = $(this.element).parents();
				for (var parentsIndex = 0; parentsIndex < parents.length; parentsIndex++) {
					var parentCandidate = parents[parentsIndex];
					var parentCandidateData = ko.dataFor(parentCandidate);
					if (parentCandidateData != null &&
						parentCandidateData.definition != null && 
						parentCandidateData.definition().Name == parentName)
					{
						parent = parentCandidate;
						break;
					}
				}
			}

			if (parent == null) {
				var panelParents = $(this.element).parents(".panelComponent");
				var contentParents = $(this.element).parents(".content");
				if (panelParents.length != 0) {
					parent = panelParents[0];
				} else if (contentParents.length != 0) {
					parent = contentParents[0];
				} else {
					parent = $(this.element).parent()[0];
				}
			}

			var $parent = $(parent);
			var parentBorderSize = ACTUtils.GetBorderSize($parent);

			return {
				width:  $parent.outerWidth(true)  - parentBorderSize.width,
				height: $parent.outerHeight(true) - parentBorderSize.height,
			};
		}

		this.getComponentWithName = function(name) {
			if (name == null || name == "")
				return null;
			var comp = this.definition().gridPanel.componentModels[name];
			if (comp == null)
				ACTUtils.Error(
					"attachError", name + " is unknown for " + this.definition().Name,
					this.definition().Name, name
				);
			return comp;
		}

		this.getFirstVisibleTopAttachment = function() {
			var attach = this.definition().TopAttachment;
			while (attach != null && attach != "") {
				var attachComp = this.getComponentWithName(attach);
				if (attachComp.definition().Visible) {
					break;
				}
				attach = attachComp.definition().TopAttachment;
			}
			return this.getComponentWithName(attach);
		}

		this.getFirstVisibleBottomAttachment = function() {
			var attach = this.definition().BottomAttachment;
			while (attach != null && attach != "") {
				var attachComp = this.getComponentWithName(attach);
				if (attachComp.definition().Visible) {
					break;
				}
				attach = attachComp.definition().BottomAttachment;
			}
			return this.getComponentWithName(attach);
		}
		
		this.getFirstVisibleLeftAttachment = function() {
			var attach = this.definition().LeftAttachment;
			while (attach != null && attach != "") {
				var attachComp = this.getComponentWithName(attach);
				if (attachComp.definition().Visible) {
					break;
				}
				attach = attachComp.definition().LeftAttachment;
			}
			return this.getComponentWithName(attach);
		}
		
		this.getFirstVisibleRightAttachment = function() {
			var attach = this.definition().RightAttachment;
			while (attach != null && attach != "") {
				var attachComp = this.getComponentWithName(attach);
				if (attachComp.definition().Visible) {
					break;
				}
				attach = attachComp.definition().TopOffset;
			}
			if (attach == null || attach == "")  return null

			return this.getComponentWithName(attach);
		}

		this.getX = function() {
			if (this.xdirty) {
				var prev = this.getFirstVisibleLeftAttachment();
				if (prev == null) {
					this.x(this.definition().LeftOffset);
					this.xdirty = false;
				} else {
					var prevW = prev.getW() + prev.definition().RightOffset;  // LeftOffset already in prev.getX()
					prevW += prev.getChildrenOuterSize().width;

					this.x(prev.getX() + prevW + this.definition().LeftOffset);
					this.xdirty = false;
				}
			}
			ACTUtils.Log(this.definition().Name+": x="+this.x(), 1)
			return this.x();
		}.bind(this);

		this.getY = function() {
			if (this.ydirty) {
				var prev = this.getFirstVisibleTopAttachment();
				if (prev == null) {
					this.y(this.definition().TopOffset);
					this.ydirty = false;
				}
				else {
					var prevH = prev.getH() + prev.definition().BottomOffset;  // TopOffset already in prev.getY()
					prevH += prev.getChildrenOuterSize().height;

					this.y(prev.getY() + prevH + this.definition().TopOffset);
					this.ydirty = false;
				}
			}
			ACTUtils.Log(this.definition().Name+": y="+this.y(), 1);
			return this.y();
		}.bind(this);
		
		this.getW = function() {
			if (this.wdirty) {
				var def = this.definition();
				var widthType = def.WidthType;

				if (!this.definition().Visible) {
					this.setWidth(0);
				} else if (widthType == "Fixed") {
					this.setWidth(def.WidthValue - this.getChildrenOuterSize().width);
				} else if (widthType == "FitToContent") {
					this.setWidth(this.computeWidth());
				} else if (widthType == "Percentage" || widthType == "RangedPercentage") {
					var remainingWidth = this.remainingWidth(widthType != "RangedPercentage");
					var pc = def.WidthValue / 100.0;
					var offsets = def.LeftOffset + def.RightOffset;
					var outerSize = this.getChildrenOuterSize().width;

					var width = Math.floor(remainingWidth*pc) - offsets - outerSize;
					if (widthType == "RangedPercentage")
						width = this.applyMinMaxWidth(width);
					else if (def.MaxWidth > 0 || def.MinWidth > 0)
						console.warn("Use RangedPercentage if you want to use min or max");

					this.setWidth(width);
					ACTUtils.Log(def.Name + " " + pc + " of " + remainingWidth, 1);
				}

				this.wdirty = false;
				ACTUtils.Log(def.Name+": w="+this.width, 1);
			}
			return this.width;
		}
		
		this.getH = function() {
			if (this.hdirty) {
				var def = this.definition();
				var heightType = def.HeightType;

				if (!def.Visible) {
					this.setHeight(0);
				} else if (heightType == "Fixed") {
					this.setHeight(def.HeightValue - this.getChildrenOuterSize().height);
				} else if (heightType == "FitToContent") {
					this.setHeight(this.computeHeight());
				} else if (heightType == "Percentage" || heightType == "RangedPercentage") {
					var remainingHeight = this.remainingHeight(heightType != "RangedPercentage");
					var pc = def.HeightValue / 100.0;
					var offsets = def.TopOffset + def.BottomOffset;
					var outerSize = this.getChildrenOuterSize().height;

					var height = Math.floor(remainingHeight*pc) - offsets - outerSize;
					if (heightType == "RangedPercentage")
						height = this.applyMinMaxHeight(height);
					else if (def.MaxHeight > 0 || def.MinHeight > 0)
						console.warn("Use RangedPercentage if you want to use min or max");

					this.setHeight(height);
					ACTUtils.Log(def.Name + " " + pc + " of " + remainingHeight, 1);
				}

				this.hdirty = false;
				ACTUtils.Log(def.Name+": h="+this.height, 1);
			}
			return this.height;
		}
		
		this.getOuterDim = function() {
			var dim = this.computeDim();
			return {
				width:  dim.width  + this.getChildrenOuterSize().width,
				height: dim.height + this.getChildrenOuterSize().height,
			};
		}

		this.computeDim = function() {
			// to correctly resize the component (check if we're resizing to avoid infinite loop)
			if (!this.resizing && (this.wdirty || this.hdirty))
				this.resize(false);

			if (!this.computeDimDirty)
				return this.computedDim;

			this.computeDimDirty = false;
			var $element = this.$realElement.find(".content").first().children();

			// we try to apply the width / height if it's fixed because a dim can change the other
			if (this.definition().WidthType == "Percentage" || this.definition().WidthType == "Fixed")
				self.getW();
			if (this.definition().HeightType == "Percentage" || this.definition().HeightType == "Fixed")
				self.getH();

			var $childrenContent = $element.find(".content");
			if ($childrenContent.length > 0) {
				// in case of a component simular to a panel (contain others component)
				var result = { width: 0, height: 0 };
				for (var i = 0; i < $childrenContent.length; i++) {
					var $childContent = $($childrenContent[i]);

					// that the change we make in the css when we do Visible = false
					// we can't do $childreContent.is(":visible") cause we are in a hidden element so alway false.
					if ($childContent.parent().css("display") == "none")
						continue;

					var childRight = parseInt($childContent.css("left")) + $childContent.outerWidth(true);
					childRight = isNaN(childRight) ? 0 : childRight;
					result.width = Math.max(result.width, childRight);

					var childBottom = parseInt($childContent.css("top")) + $childContent.outerHeight(true);
					childBottom = isNaN(childBottom) ? 0 : childBottom;
					result.height = Math.max(result.height, childBottom);
				}
			} else {
				var result = {
					width:  $element.outerWidth(true),
					height: $element.outerHeight(true),
				}
			}

			this.computedDim = result;
			return result;
		}

		this.applyMinMaxWidth = function(width) {
			var maxWidth = this.definition().MaxWidth;
			if (maxWidth > 0 && width > maxWidth)
				width = maxWidth;
			var minWidth = this.definition().MinWidth;
			if (minWidth > 0 && width < minWidth)
				width = minWidth;
			return width;
		};

		this.applyMinMaxHeight = function(height) {
			var maxHeight = this.definition().MaxHeight;
			if (maxHeight > 0 && height > maxHeight)
				height = maxHeight;
			var minHeight = this.definition().MinHeight;
			if (minHeight > 0 && height < minHeight)
				height = minHeight;
			return height;
		};

		this.computeHeight = function() {
			var elementHeight = 0;
			if (this.computeHeightFunction) {
				elementHeight = this.computeHeightFunction();
			} else {
				elementHeight = this.computeDim().height;
			}

			return this.applyMinMaxHeight(elementHeight);
		};
		
		this.computeWidth = function() {
			var elementWidth = 0;
			if (this.computeWidthFunction) {
				elementWidth = this.computeWidthFunction();
			} else {
				elementWidth = this.computeDim().width;
			}

			return this.applyMinMaxWidth(elementWidth);
		};

		this.getThWidthOfAttach = function(attachName, rangePcInclude) {
			var w = 0;
			var attach = this.definition()[attachName];
			while (attach && attach!="") {
				var prev = this.getComponentWithName(attach);
				var prevDef = prev.definition();
				attach = prevDef[attachName];

				if (!prevDef.Visible)
					continue;

				var prevWidthType = prev.definition().WidthType;
				if (prevWidthType == "Percentage" || (!rangePcInclude && prevWidthType == "RangedPercentage"))
					continue;

				w += prev.getW();

				w += prevDef.LeftOffset + prevDef.RightOffset; // offset aren't in getDim
				if (prevWidthType == "FitToContent" || prevWidthType == "RangedPercentage")
					w += prev.getChildrenOuterSize().width;   // pading aren't in getDim
			}

			return w;
		}

		this.remainingWidth = function(rangePcInclude) {
			var parentWidth = this.getParentSize().width;
			var w = parentWidth;
			ACTUtils.Log("parent width: "+w, 1)

			w -= this.getThWidthOfAttach("LeftAttachment", rangePcInclude);
			w -= this.getThWidthOfAttach("RightAttachment", rangePcInclude);

			return w;
		}.bind(this);

		this.getThHeightOfAttach = function(attachName, rangePcInclude) {
			var h = 0;
			var attach = this.definition()[attachName];
			while (attach && attach!="") {
				var prev = this.getComponentWithName(attach);
				var prevDef = prev.definition();
				attach = prevDef[attachName];

				if (!prevDef.Visible)
					continue;

				var prevHeightType = prev.definition().HeightType;
				if (prevHeightType == "Percentage" || (!rangePcInclude && prevHeightType == "RangedPercentage"))
					continue;

				h += prev.getH();

				h += prevDef.TopOffset + prevDef.BottomOffset; // offset aren't in getH
				if (prevHeightType == "FitToContent" || prevHeightType == "RangedPercentage")
					h += prev.getChildrenOuterSize().height;   // pading aren't in getH
			}

			return h;
		}

		this.remainingHeight = function(rangePcInclude) {
			var parentHeight = this.getParentSize().height;
			var h = parentHeight;
			ACTUtils.Log("parent height: "+h, 1)

			h -= this.getThHeightOfAttach("TopAttachment", rangePcInclude);
			h -= this.getThHeightOfAttach("BottomAttachment", rangePcInclude);

			return h;
		}.bind(this);

		this.onTriggerAction = function(actionName, args) {
			InvokeCallback("", this.definition().OnTriggerAction, [actionName, args]);
		}

		this.getLockElement = function() {
			return $(element).children(".lockComponent");
		}

		this.doLock = function(noLockPaths) {
			var thisPath = this.definition().Path;
			for (var noLockPathIndex in noLockPaths) {
				// if our path is "A/B/C" and noLockPath contain "A" we dont want do be lock.
				// So we don't lock if our path start with a noLockPath.
				if (thisPath.indexOf(noLockPaths[noLockPathIndex]) == 0)
					return false;
			}
			return true;
		}

		this.lock = function(key, noLockPaths) {
			if (this.doLock(noLockPaths)) {
				ACTUtils.Log("try lock " + definition.Name + " by " + key, 0);
				if (!ACTUtils.AnyElementIn(this.lockKeys)) {

					ACTUtils.CaptureAndKeepClick();

					// setTimeout to have time to get the click event
					setTimeout(function() {
						self.getLockElement().css("display", "block");
					}, 0);

					// don't do that in the setTimeout if you don't want to break the UIAutomation
					// cause the lock state need to be change before changing panel and not after
					InvokeCallback("", self.definition().OnLockStateChange, [true]);
					ACTUtils.Log(definition.Name + " locked", 0);
				}
				this.lockKeys[key] = true;
			}

			ACTUtils.CallFunctions(this.lockFunctions, key, noLockPaths)
		}

		this.setLockMessage = function(message) {
			var $lockElement = this.getLockElement();
			$lockElement.text(message);
		}

		this.unlock = function(key) {
			if (!key in this.lockKeys) return;
			delete this.lockKeys[key];
			ACTUtils.Log("try unlock " + definition.Name + " by " + key, 0);
			if (!ACTUtils.AnyElementIn(this.lockKeys)) {
				var $lockElement = this.getLockElement();
				$lockElement.text("");

				// have to change the cursor cause webkit doesn't update it if we don't move the mouse
				$lockElement.css("cursor", "default");
				// have to use setimeout to update the mouse
				setTimeout(function() {
					$lockElement.css("display", "none");
					$lockElement.css("cursor", "");
					ACTUtils.CallFunctions(self.lockElementHidded);

					ACTUtils.TriggerKeepedClick();
				}, 0);

				InvokeCallback("", this.definition().OnLockStateChange, [false]);
				ACTUtils.Log(definition.Name + " unlocked", 0);
			}

			ACTUtils.CallFunctions(this.unlockFunctions, key);
		}

		this.resizeCache = [0,0,0,0];
		this.resize = function(computePos) {
			if (!this.definition().Visible)
				return;

			var computePos = (computePos == null && true) || computePos;

			var wasResizing = this.resizing;
			this.resizing = true;

			ACTUtils.CallFunctions(this.beforeResizeFunctions);

			/* getX compute and put in cache corresponding values */
			var rc = this.resizeCache
			var x = rc[0]; var y = rc[1];
			if (computePos) {
				x = this.getX();
				y = this.getY();
			}
			var w = this.getW();
			var h = this.getH();

			var sizeChange = rc[0] != x || rc[1] != y || rc[2] != w || rc[3] != h;
			rc[0] = x; rc[1] = y; rc[2] = w; rc[3] = h;

			ACTUtils.CallFunctions(this.resizeFunctions, this.getH(), this.getW(), sizeChange);

			this.resizing = wasResizing;
		}.bind(this);

		$(element).bind("destroyed", function() {
			ACTUtils.CallFunctions(self.disposeFunctions);
		});

		$(element).on("click", function() {
			if (!this.definition().ClickHaveACallback)
				return true;
			this.onTriggerAction("TriggerAllClick", []);
			InvokeCallback("", this.definition().OnClick, []);
			return false;
		}.bind(this));

		$(element).on("contextmenu", function() {
			if (!this.definition().RightClickHaveACallback)
				return true;
			this.onTriggerAction("TriggerRightClick", []);
			InvokeCallback("", this.definition().OnRightClick, []);
			return false;
		}.bind(this));

		definition.gridPanel.registerComponentModel(definition.Name,this);
		ACTSocket.registerService("UpdateBaseComponent" + definition.Name + definition.Id, onUpdateBaseComponent);
    }

	return {
		createViewModel: function(params, componentInfo) {
            return new ComponentBaseViewModel(params, componentInfo.element);
        }
	};

});

