/**********************************************************************************************
!!! 1. файл автоматически копируется из Vko.Common.BusinessLogic.js_resources !!!
!!! 2. PreBuildEvent проверяет имя солюшена и копирует этот файл только для солюшена Vko !!!
!!! 3. TFS не почувствует изменения файлов, скопированных на PreBuildEvent в сайты, поэтому 
нужно вручную зачекинить *site\js\dd.js после изменения этого файла !!!
***********************************************************************************************/

(function($){
	
	$.extend($.fn, {
		// drag and drop method
		dd: function(opt){
			return this.each(function(){

				
				if($(this).data('dd')){
					var dd = $(this).data('dd');
					
					
					if(typeof opt == 'string')
						switch(opt){
							case 'disable': dd.disable(); break;
							case 'enable': dd.enable(); break;
							case 'destroy': dd.destroy(); break;
						}
					else $.extend(dd.options, opt);
					
				
				}else $(this).data('dd', new DD(this, opt));
			});
		}
	});



	DD = function(elem, options){
		this.elem = $(elem);
		this.enabled = true;
		
		
		this.settings = $.extend(true, {
			delay: 0,
			proxy: null,
			region: null,
			position: 'relative',
			scroll: {
				sensitivity: 40,
				distance: 100,
				time: 300
			},
			origin: {x: 0, y: 0}
		}, options);
		
		
		this.region = this.settings.region ?
			$.isFunction(this.settings.region) ? this.settings.region.call(this) : $(this.settings.region) :
			undefined;
		
		this.elem.bind('mousedown.ondragstart', this.ondragstart);	
		
		return this;
	};


	$.extend(DD.prototype, {
		ondragstart: function(e){

			e.stopPropagation();
			var	$this = $(this),
				dd = $this.data('dd');
			if(!dd) return false;
			
			dd.e = e;
			dd.delayTimer = setTimeout( (function(dd){
				return function(){

					if(!dd.enabled) return false;
					
					if (dd.delayTimer) {
						clearTimeout(dd.delayTimer);
						dd.delayTimer = null;
					}

					dd.scrollLeft = dd.scrollTop = 0;

					if(!dd.proxy)
						dd.proxy = dd.settings.proxy ?
						$.isFunction(dd.settings.proxy) ? dd.settings.proxy.call(dd) : $(dd.settings.proxy) :
						dd.elem;
						
					dd.proxy.css({left: intCSS(dd.proxy, 'left') + 'px', top: intCSS(dd.proxy, 'top') + 'px'});
					
					if($.focus) $.focus.blur();
					$.focus = dd.proxy.focus();
			
					if(!dd.proxyPos){
						dd.proxyPos = dd.proxy.css('position');
						if(!dd.proxy.data('dd-native-position'))
							dd.proxy.data('dd-native-position', dd.proxy.css('position'));
						dd.proxy.css('position', dd.settings.position);
					}
					dd.elem.trigger('dd-start');
			
					dd.dimensions = dd.__dimensions();
					
					$(document).bind('mousemove.ondrag', function(event){
						dd.ondrag(event);
					});
				}
			})(dd), dd.settings.delay);

			$(document).bind('mouseup.ondragdrop', (function(dd){return function(event){
				dd.ondragdrop(event)
			}})(dd));
			
			if($.browser.opera || $.browser.msie){
				dd.unselect = $(':not([unselectable])').andSelf();
				dd.unselect.attr('unselectable', 'on');
			}
			else return false;
		},
		
		ondrag: function(e){
			this.e = e;
			this.elem.trigger('dd-drag-before');

			this.__updateCoords();

			this.__autoScroll();

			$.extend(true, this.dimensions, this.__dimensions({proxy: { size: false, mouseOffset: false }, region: false, autoScroll: false}));

			this.elem.trigger('dd-drag-after');
		},
		
		ondragdrop: function(e){
			
			if(this.settings.autoScroll)
				if(this.settings.autoScroll.data('scrollTimer'))
					clearTimeout(this.settings.autoScroll.data('scrollTimer'));

			$(document).unbind('mousemove.ondrag');
			$(document).unbind('mouseup.ondragdrop');
			
			if (this.delayTimer) {
				clearTimeout(this.delayTimer);
				this.delayTimer = null;
			}else this.elem.trigger('dd-drop');
			
			if($.isFunction(this.settings.proxy) && this.proxy){
				this.proxy.remove();
				delete this.proxy;
				delete this.proxyPos;
			}
			
			if(this.unselect)
				this.unselect.removeAttr('unselectable');
		},
		
		enable: function(){
			if(!this.enabled){
				this.enabled = true;
				this.elem.trigger('dd-enable');
			}else return false;
		},
		
		disable: function(){
			if(this.enabled){
				this.enabled = false;
				this.elem.trigger('dd-disable');
			}else return false;
		},
		
		destroy: function(){
			this.elem.trigger('dd-destroy');
			this.elem.removeData('dd');
			this.elem.unbind('mousedown', this.ondragstart);
			this.elem.unbind('mousemove', this.ondrag);
			this.elem.unbind('mouseup', this.ondragdrop);
			this.proxy.css('position', this.proxy.data('dd-nativePosition'));
			delete this;
		},
		
		__dimensions: function(options){
			var settings = { proxy: { offset: true, size: true, mouseOffset: true }, region: true, autoScroll: true },
				dd = this;
			$.extend(true, settings, options);
		
			var result = { };
			
			if(settings.proxy.offset){
				var	proxies = $.map(this.proxy, function(n){
						if(dd.proxy.length > 1 || !(dd.dimensions && dd.dimensions.proxy))
							var width = $(n).width(), height = $(n).height();
							else var width = dd.dimensions.proxy.width, height = dd.dimensions.proxy.height;
						return $.extend($(n).offset(), {width: width, height: height});
					});
				result.proxy = {
					left: $.map(proxies, function(n){return n.left;}).min(),
					top: $.map(proxies, function(n){return n.top;}).min(),
					right: $.map(proxies, function(n){return n.left + n.width;}).max(),
					bottom: $.map(proxies, function(n){return n.top + n.height;}).max()
				};
			}
			
			if(settings.proxy.size)
				$.extend(result.proxy, {
					width: result.proxy.right - result.proxy.left,
					height: result.proxy.bottom - result.proxy.top
				});
			
			if(settings.proxy.mouseOffset)
				$.extend(result.proxy, {
					dx: this.e.pageX - result.proxy.left,
					dy: this.e.pageY - result.proxy.top,
					cssDx: this.e.pageX - intCSS(this.proxy, 'left'),
					cssDy: this.e.pageY - intCSS(this.proxy, 'top')
				});
			
			if(settings.region && this.region){
				result.region = {};
				$.extend(result.region, this.region[0] == document ?
					{
						width: this.region.width(),
						height: this.region.height(),
						offset: { left: 0, top: 0 }
					} :	{
						offset: this.region.offset(),
						width: this.region.width(),
						height: this.region.height()
					}
				);
				
				result.region.offset.left += intCSS(this.region, 'border-left-width');
				result.region.offset.top += intCSS(this.region, 'border-top-width');
				
				$.extend(result.region, {
					right: result.region.offset.left + result.region.width,
					bottom: result.region.offset.top + result.region.height
				});
			}
			
			if(settings.autoScroll && this.settings.autoScroll){
				result.autoScroll = [];	
				this.settings.autoScroll.each(function(){
					var	$this = $(this);
						
					if(this != document && ( 
						!/auto|scroll/.test($this.css('overflow')) ||
						!/auto|scroll/.test($this.css('overflow-x')) ||
						!/auto|scroll/.test($this.css('overflow-y'))
					)) return;
					var res = { elem: $this };
					
					if(this == document){
						$.extend(res, {
							offset: {left: 0, top: 0},
							width: $this.width(),
							height: $this.height()
						});
						$.extend(res, {
							right: res.width,
							bottom: res.height
						});
					}else {
						$.extend(res, {
							offset: $this.offset(),
							width: $this.outerWidth() - this.offsetWidth + this.clientWidth,
							height: $this.outerHeight() - this.offsetHeight + this.clientHeight
						});
						$.extend(res, {
							right: res.offset.left + intCSS(this, 'borderLeftWidth') + res.width,
							bottom: res.offset.top + intCSS(this, 'borderTopWidth') + res.height
						});
					}
					
					result.autoScroll.push(res);
				});
			}
			
			return result;
		},
		
		__updateCoords: function(){
			var e = this.e,
				cx = e.pageX - this.dimensions.proxy.dx,
				cy = e.pageY - this.dimensions.proxy.dy;
			
			if(!this.settings.axis || this.settings.axis == 'x'){
				if(this.region && cx + this.scrollLeft < this.dimensions.region.offset.left){
					var x = intCSS(this.proxy, 'left') - (this.dimensions.proxy.left - this.dimensions.region.offset.left);
				}else if(this.region && cx > this.dimensions.region.right - this.dimensions.proxy.width){
					var x = intCSS(this.proxy, 'left') + this.dimensions.region.right - this.dimensions.proxy.right;
				}else var x = e.pageX - this.dimensions.proxy.cssDx + this.scrollLeft;
			}else var x = intCSS(this.proxy, 'left');
			
			
			if(!this.settings.axis || this.settings.axis == 'y'){
				if(this.region && cy + this.scrollTop < this.dimensions.region.offset.top){
					var y = intCSS(this.proxy, 'top') - (this.dimensions.proxy.top - this.dimensions.region.offset.top);
				}else if(this.region && cy > this.dimensions.region.bottom - this.dimensions.proxy.height){
					var y = intCSS(this.proxy, 'top') + this.dimensions.region.bottom - this.dimensions.proxy.bottom;
				}else var y = e.pageY - this.dimensions.proxy.cssDy + this.scrollTop;
			}else var y = intCSS(this.proxy, 'top');
			
			if(this.settings.grid){
				x = x.roundTo(this.settings.grid.x) + this.settings.origin.x - Math.floor(this.settings.origin.x / this.settings.grid.x)*this.settings.grid.x;
				y = y.roundTo(this.settings.grid.y) + this.settings.origin.y - Math.floor(this.settings.origin.y / this.settings.grid.y)*this.settings.grid.y;
			}
			
			this.proxy.css({
				left:	x + 'px',
				top:	y + 'px'
			});
		},
		
		
		__autoScroll: function(){
			
			var dd = this,
				proxy = dd.dimensions.proxy;
				
			if(this.dimensions.autoScroll)
				$.each(this.dimensions.autoScroll, function(i, s){
					if(s.elem.data('scrollTimer')){
						clearTimeout(s.elem.data('scrollTimer'));
					}
					
					if((s.bottom - dd.settings.scroll.sensitivity < dd.e.pageY) || (s.right - dd.settings.scroll.sensitivity < dd.e.pageX) || (s.offset.left + dd.settings.scroll.sensitivity > dd.e.pageX) || (s.offset.top + dd.settings.scroll.sensitivity > dd.e.pageY)){
						s.elem.data('scrollTimer', setInterval(function(){

							var scroll = { left: 0, top: 0 },
								proxyInScroll = s.elem.isAncestorOf(dd.proxy);
								
							if(s.bottom - dd.settings.scroll.sensitivity < dd.e.pageY && (proxyInScroll ? true: (dd.e.pageY < s.bottom && (dd.e.pageX > s.offset.left && dd.e.pageX < s.right))))
								scroll.top += Math.min(s.elem[0].scrollHeight - s.height - s.elem[0].scrollTop, dd.settings.scroll.distance);
							
							if(s.right - dd.settings.scroll.sensitivity < dd.e.pageX && (proxyInScroll ? true: (dd.e.pageX < s.right && (dd.e.pageY > s.offset.top && dd.e.pageY < s.bottom))))
								scroll.left += Math.min(s.elem[0].scrollWidth - s.width - s.elem[0].scrollLeft, dd.settings.scroll.distance);
							
							if(s.offset.left + dd.settings.scroll.sensitivity > dd.e.pageX && (proxyInScroll ? true: (dd.e.pageX > s.offset.left && (dd.e.pageY > s.offset.top && dd.e.pageY < s.bottom))))
								scroll.left += Math.max(-s.elem[0].scrollLeft, -dd.settings.scroll.distance);
							
							if(s.offset.top + dd.settings.scroll.sensitivity > dd.e.pageY && (proxyInScroll ? true: (dd.e.pageY > s.offset.top && (dd.e.pageX > s.offset.left && dd.e.pageX < s.right))))
								scroll.top += Math.max(-s.elem[0].scrollTop, -dd.settings.scroll.distance);
							
													
							dd.proxy.each(function(){
								if($(this).parents().index(s.elem[0]) != -1){
									if(dd.region){
										if(scroll.top >= 0)
											var top = Math.max(0, Math.min(scroll.top, dd.dimensions.region.bottom - dd.dimensions.proxy.bottom));
										else
											var top = Math.min(0, Math.max(scroll.top, dd.dimensions.region.offset.top - dd.dimensions.proxy.top));

										if(scroll.left >= 0)
											var left = Math.max(0, Math.min(scroll.left, dd.dimensions.region.right - dd.dimensions.proxy.right));
										else
											var left = Math.min(0, Math.max(scroll.left, dd.dimensions.region.offset.left - dd.dimensions.proxy.left));

									}else var top = scroll.top, left = scroll.left;
									
									$(this).animate({
										'left': parseInt(this.style.left) + left + 'px',
										'top': parseInt(this.style.top) + top + 'px'
									}, dd.settings.scroll.time);

								}
							}); 
							s.elem.animate({
								'scrollLeft': s.elem[0].scrollLeft + scroll.left,
								'scrollTop': s.elem[0].scrollTop + scroll.top
							}, dd.settings.scroll.time, null, function(){dd.elem.trigger('dd-drag-after')});
							
							if(dd.region && dd.region.parents().index(s.elem[0]) != -1){
								var reg = dd.dimensions.region;
								reg.offset.left -= scroll.left;
								reg.offset.top -= scroll.top;
								reg.right -= scroll.left;
								reg.bottom -= scroll.top;
								
							}
							
							if(proxyInScroll){
								dd.scrollLeft += scroll.left;
								dd.scrollTop += scroll.top;
							}
						}, 500));
					}
				});
		}
	});
	
})(jQuery);

