/**
 * @param string direction (top, right, bottom, left)
 * @param string color
 * @param int height
 * @param int width
 * @param int side1
 * @example
 *	$('#arrow').cssArrow('bottom', '#000', 40, 30);
 *	$('#arrow').cssArrow('right', '#000', 4);
 */
$.fn.cssArrow = function(direction, color, height, width, side1) {
	var map = {
		// order: height, side1, side2, none
		top	: ['bottom', 'left', 'right', 'top'],
		bottom	: ['top', 'left', 'right', 'bottom'],
		left	: ['right', 'top', 'bottom', 'left'],
		right	: ['left', 'top', 'bottom', 'right']
	};
	var arr = map[direction];

	var side2;
	if (width === undefined) {
		side1 = side2 = height;
	} else {
		if (side1 === undefined) {
			side1 = side2 = parseInt(width/2);
		} else {
			side2 = width - side1;
		}
	}

	return this
		.css('border-' + arr[0], height + 'px solid ' + color)
		.css('border-' + arr[1], side1 + 'px dotted transparent')
		.css('border-' + arr[2], side2 + 'px dotted transparent')
		.css('border-' + arr[3], 'none')
		.css({width:0, height:0, overflow:'hidden', display:'block'});
};

/**
 * @param hash opts
 * @param int left (optional)
 * @param int top (optional)
 * @example
 *	$('#xx').addCssArrow({height:12});
 *	$('#xx').addCssArrow({
 *		direction: 'left', //top, right, bottom, left
 *		height: 18,
 *		width: 36,
 *		side: 18,
 *		offset: '50%' // 0, 50%, 100%, 10, -10
 *	}, 200, 300);
 */
$.fn.addCssArrow = function(opts, left, top) {

	var s = $.extend({
		direction: 'bottom',
		height: 9,
		width: opts.height * 2,
		side: opts.height,
		offset: - opts.height * 3 //0 50% 100% 10 -10
	}, opts);

	var height = s.height;
	var width = s.width;
	var side1 = s.side;
	var side2 = s.width - s.side;

	return this.each(function(){
		var $$ = $(this).relative(), bgColor = $$.css('backgroundColor');
		if (bgColor == 'transparent') bgColor = '#fff';

		// if exists, remove it
		$$.find('ins.jcan-cssArrow').remove();

		var borderWidth = $.intval($$.css('border-' + s.direction + '-width'));
		var borderColor = $$.css('border-' + s.direction + '-color');
		var borderStyle = $$.css('border-' + s.direction + '-style');
		if (borderStyle == 'none') {
			borderWidth = 0;
		}

		var arrow = $('<ins class="jcan-cssArrow"\/>').appendTo(this).cssArrow(s.direction, borderStyle == 'none' ? bgColor : borderColor, height, width, side1)
			.css('position', 'absolute')
			.css(s.direction, - height - borderWidth + 'px');

		var lt, rb, wh;
		if (s.direction == 'top' || s.direction == 'bottom') {
			lt = 'left';
			rb = 'right';
			wh = 'outerWidth';
		} else {
			lt = 'top';
			rb = 'bottom';
			wh = 'outerHeight';
		}

		if (s.offset == '50%') {
			arrow.css(lt, ($$[wh]() - width) / 2 - borderWidth);
		} else if (s.offset == '100%') {
			arrow.css(rb, - borderWidth);
		} else if (s.offset < 0) {
			arrow.css(rb, - s.offset - borderWidth);
		} else {
			arrow.css(lt, s.offset - borderWidth);
		}

		// add border
		if (borderStyle != 'none') {

			var rad_a = Math.atan(height/side1);
			var rad_b = Math.atan(height/side2);
			var rad_c = Math.PI - rad_a - rad_b;

			var side3 = borderWidth / Math.sin(rad_c/2);
			var rad_d = Math.PI - rad_a - Math.PI/2 - rad_c/2;
			var _x = Math.round(Math.sin(rad_d) * side3);
			var _y = Math.round(Math.cos(rad_d) * side3);

			var _arrow = $('<ins class="jcan-cssArrow"\/>').appendTo(this).cssArrow(s.direction, bgColor, height, width, side1)
				.css('position', 'absolute')
				.css(s.direction, - height - borderWidth + _y + 'px');

			var lt, rb, wh;
			if (s.direction == 'top' || s.direction == 'bottom') {
				lt = 'left';
				rb = 'right';
				wh = 'outerWidth';
			} else {
				lt = 'top';
				rb = 'bottom';
				wh = 'outerHeight';
			}

			if (s.offset == '50%') {
				_arrow.css(lt, ($$[wh]() - width) / 2 - borderWidth - _x);
			} else if (s.offset == '100%') {
				_arrow.css(rb, - borderWidth + _x);
			} else if (s.offset < 0) {
				_arrow.css(rb, - s.offset - borderWidth + _x);
			} else {
				_arrow.css(lt, s.offset - borderWidth - _x);
			}
		}

		// position
		if (left !== undefined) {
			var co = $$.offset();
			var ao = arrow.offset();

			var ax = ao.left - co.left;
			var ay = ao.top - co.top;

			var x, y;
			switch (s.direction) {
				case 'top':
					x = left - ax - side1;
					y = top - ay;
					break;

				case 'bottom':
					x = left - ax - side1;
					y = top - ay - height;
					break;

				case 'left':
					x = left - ax;
					y = top - ay - side1;
					break;

				case 'right':
					x = left - ax - height;
					y = top - ay - side1;
					break;
			}

			if ($$.css('position') != 'fixed') {
				$$.css('position', 'absolute');
			}
			$$.css({left: x, top: y, margin: 0});
		}
	});
};

$.intval = function(n) {
	return parseInt(n) || 0;
};

$.fn.relative = function() {
	return this.each(function(){
		var $$ = $(this), pos = $$.css('position');
		if (pos == 'static' || (pos == 'fixed' && $.browser.ltie7)) {
			$$.css('position', 'relative');
		}
	});
};

$.fn.getPosOffset = function(pos) {
	var offset = this.offset();
	var w = this.outerWidth(), h = this.outerHeight();

	var x, y;

	if (pos % 3 == 1) {
		x = offset.left;
	} else if (pos % 3 == 0) {
		x = offset.left + w;
	} else {
		x = offset.left + w/2;
	}

	if (pos < 4) {
		y = offset.top;
	} else if (pos > 6) {
		y = offset.top + h;
	} else {
		y = offset.top + h/2;
	}

	return {left: x, top: y};
};