jQuery.fn.InlineImage = function(options) {
	options = jQuery.extend({
		onDrop : null
	}, options || {});

	return this.Draggable({
		ghosting: true,
		revert: true,
		opacity: 0.7,
		onStart: function() {
			var pos = jQuery.iUtil.getPosition(this);
			var sz = jQuery.iUtil.getSize(this);

			this.inlineImage = {
				startX : pos.x,
				startY : pos.y,
				startW : sz.wb,
				startH : sz.hb,
				bestPara : null,
				bestParaOffset : 0
			};
		},

		onStop: function() {
			if(options.onDrop) {
				options.onDrop();
			}
			this.inlineImage = null;
			
			// Get the id of the inline image.
			var id = this.id.match(/\d+$/)[0];

			// Find the index that this child appears in it's parent.
			var inlineImageElement = this;
			var index = jQuery(this).parent().children(). filter(function(index) {
				return !((this != inlineImageElement && this.className == "inline_image") || this.id == 'draghelper');
			}).index(inlineImageElement);
			
			var alignment = 1;
			switch(jQuery(this).css('float')) {
				case 'left':
					alignment = 0;
					break;
				case 'right':
					alignment = 2;
					break;
			}
			
			var image = this;
			
			// Commit the change to the server.
			jQuery(this).Overlay('<img src="/images/loadingAnimation.gif" alt="Loading" width="100" height="100" />', {clickToClose: true});
			jQuery.post('/inline_image/move/'+id, { position: index, alignment: alignment }, function(result) {
				jQuery(image).OverlayDestroy();
			});
		},

		onDrag: function(x, y) {
			var tpos = { x: this.inlineImage.startX + this.inlineImage.startW / 2 + x, y: this.inlineImage.startY + y };
			var para = jQuery.inlineImageUtility.findNearestParagraph(this, tpos.x, tpos.y);

			var paraCentreY = para.rect.y + para.rect.h / 2;
			var paraOffset = (tpos.y < paraCentreY) ? 0 : 1;

			// Move the image to the nearest paragraph.
			if(para.para != this.inlineImage.bestPara || paraOffset != this.inlineImage.bestParaOffset) {
				jQuery(this).remove();
				if(paraOffset == 0) {
					jQuery(para.para).before(this);
				} else {
					jQuery(para.para).after(this);
				}
				this.inlineImage.bestPara = para.para;
				this.inlineImage.bestParaOffset = paraOffset;
			}

			// Determine the area of the paragraph that the image falls into.
			var paraCentreLeft = para.rect.w / 3 + para.rect.x;
			var paraCentreRight = para.rect.w / 3 * 2 + para.rect.x;
			jQuery(this).css('float', (tpos.x < paraCentreLeft) ? 'left' : ((tpos.x > paraCentreRight) ? 'right': 'none'));
		}
	}).css('cursor', 'move');
};

jQuery.inlineImageUtility = {
	findNearestParagraph : function(el, x, y) {
		var closest = null;
		var closestDistVec = {x : 1000, y : 1000};
		var closestDist = 1000000;
		var closestRect = { x: 0, y: 0, w: 0, h: 0 };

		jQuery(el).parent().children().not(el).not("#dragHelper").not(".inline_image").each(function() {
			var pos = jQuery.iUtil.getPositionLite(this);
			var sz = jQuery.iUtil.getSizeLite(this);

			// Find distance from point x, y to paragraph.
			var xd = x < pos.x ? (pos.x - x) : ((x > pos.x + sz.wb) ? (x - pos.x - sz.wb) : 0);
			var yd = y < pos.y ? (pos.y - y) : ((y > pos.y + sz.hb) ? (y - pos.y - sz.hb) : 0);
			var d = (xd * xd) + (yd * yd);

			if(d < closestDist) {
				closestDist = d;
				closest = this;
				closestDistVec = { x: xd, y: yd };
				closestRect = { x : pos.x, y: pos.y, w: sz.wb, h: sz.hb };
			}
		});

		return { para: closest, distVec: closestDistVec, dist: closestDist, rect: closestRect };
	}
};
