﻿/**
 * @fileOverview 수치의 중간값을 쉽게 얻을 수 있게 하는 static 컴퍼넌트
 * @author hooriza, modified by senxation
 */
 
/**
 * 새로운 이펙트 생성 함수를 생성한다.
 * @namespace
 * @param {Function} fpFunc	0~1 사이의 숫자를 인자로 받아 정해진 공식에 따라 0~1 사이의 값을 리턴하는 함수
 * @return {Function} 생성된 이펙트 생성 함수
 * @see <a href="http://ajaxui.nhndesign.com/svnview/yorky/hooriza/components/Effect/trunk/Spec/spec.html" target="_blank">JsSpec Page</a>
 */
nhn.Effect = function(fpFunc) {
	
	if (this instanceof arguments.callee)
		throw new Error("You can't create a instance of this");
	
	var regnum = /^(\-?[0-9\.]+)(%|px|pt|em)?$/;
	var regrgb = /^rgb\(([0-9]+)\s?,\s?([0-9]+)\s?,\s?([0-9]+)\)$/i;
	var reghex = /^#([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
	
	var reg3to6 = /^#([0-9A-F])([0-9A-F])([0-9A-F])$/i;
	
	var getValue = function(v) {

		var unit;
		
		if (regnum.test(v)) v = parseFloat(v), unit = RegExp.$2;
		else if (regrgb.test(v)) v = [ parseInt(RegExp.$1), parseInt(RegExp.$2), parseInt(RegExp.$3) ], unit = 'color';
		else if (reghex.test(v = v.replace(reg3to6, '#$1$1$2$2$3$3'))) v = [ parseInt(RegExp.$1, 16), parseInt(RegExp.$2, 16), parseInt(RegExp.$3, 16) ], unit = 'color';
		
		return { value : v, unit : unit };

	};
	
	return function(fixs, fixd) {
		
		var unit;
		
		if (arguments.length > 1) fixs = getValue(fixs), fixd = getValue(fixd), unit = fixd.unit;
		else fixd = getValue(fixs), fixs = null, unit = fixd.unit;
		
		// 두개의 단위가 다르면
		if (fixs && fixd && fixs.unit != fixd.unit) throw new Error('unit error');
		
		fixs = fixs && fixs.value;
		fixd = fixd && fixd.value;
		
		var cacheValue, cacheResult;

		var fp = function(p) {
			
			var s = fixs;
			var d = fixd;
			
			var getResult = function(s, d) { return (d - s) * fpFunc(p) + s + unit; } ;
			
			if (unit == 'color') {
				
				var r = parseInt(getResult(s[0], d[0])) << 16;
				r |= parseInt(getResult(s[1], d[1])) << 8;
				r |= parseInt(getResult(s[2], d[2]));
				
				r = r.toString(16).toUpperCase();
				for (var i = 0; 6 - r.length; i++) r = '0' + r;
					
				return  '#' + r;

			}
			
			return getResult(s, d);
		};
		
		if (fixs === null) {

			fp.setStart = function(s) {
				
				if (isNaN(parseInt(s))) s = 0 + unit;
				s = getValue(s);
				
				if (s.unit != unit) throw new Error('unit eror');
				fixs = s.value;

			};
			
		}
		
		return fp;
		
	};
	
};



/**
 * 일정한 속도로 변화하는 형태의 이펙트 함수를 생성한다.
 * @param {String | Number} nStart 시작 수치값
 * @param {String | Number} nEnd 종료 수치값
 * @remark 시작 수치값과 종료 수치값으로는 다음과 같이 여러가지 단위와 표현을 사용할 수 있다
 * <dl>
 *	<dt>그냥 숫자</dt>
 *	<dd>예) 100</dd>
 *	<dt>px 단위</dt>
 *	<dd>예) '200px'</dd>
 *	<dt>% 단위</dt>
 *	<dd>예) '50%'</dd>
 *	<dt>em 단위</dt>
 *	<dd>예) '2em'</dd>
 *	<dt>색상 단위</dt>
 *	<dd>
 *		<dl>
 *			<dt>rgb 표현</dt>
 *			<dd>예) 'rgb(255, 127, 0)'</dd>
 *			<dt>#RRGGBB 표현</dt>
 *			<dd>예) '#FF7F00'</dd>
 *			<dt>#RGB 표현</dt>
 *			<dd>예) '#FA0'</dd>
 *		</dl>
 *	</dd>
 * </dl>
 * @remark 시작 수치값과 종료 수치값의 단위가 다르면 에러를 발생시킨다.
 * @return {EffectFunction} 생성된 이펙트 함수
 * @example
// 100 과 200 사이를 일정하게 증가하는 중간값을 알려주는 함수를 리턴
var f = nhn.Effect.linear(100, 200);

// 리턴된 함수를 사용하여 중간값을 얻음
console.log( f(0) ); // 결과 100
console.log( f(0.5) ); // 결과 150
console.log( f(1) ); // 결과 200
 */
nhn.Effect.linear = nhn.Effect(function(s) {
	return s;
});

/**
 * 점점 빨라지는 식으로 변화하는 형태의 이펙트 함수를 생성한다.
 * @param {String | Number} nStart 시작 수치값
 * @param {String | Number} nEnd 종료 수치값
 * @return {Function} 생성된 이펙트 함수
 */
nhn.Effect.easeIn = nhn.Effect(function(s) {
	y = Math.sqrt(1 - (s * s));
	return (1 - y);
});

/**
 * 점점 느려지는 식으로 변화하는 형태의 이펙트 함수를 생성한다.
 * @param {String | Number} nStart 시작 수치값
 * @param {String | Number} nEnd 종료 수치값
 * @return {Function} 생성된 이펙트 함수
 */
nhn.Effect.easeOut = nhn.Effect(function(s) {
	y = Math.sqrt((2 - s) * s);
	return y;
});

/**
 * 조금 넘어가는 식으로 변화하는 형태의 이펙트 함수를 생성한다.
 * @param {String | Number} nStart 시작 수치값
 * @param {String | Number} nEnd 종료 수치값
 * @return {Function} 생성된 이펙트 함수
 */
nhn.Effect.overphase = nhn.Effect(function(s) {
	s /= 0.69643223;
	y = Math.sqrt((2 - s) * s) + 0.1;
	return y.toFixed(7);
});

/**
 * 튀기는 효과로 변화하는 형태의 이펙트 함수를 생성한다.
 * @remark Script.aculo.us 의 코드 사용
 * @param {String | Number} nStart 시작 수치값
 * @param {String | Number} nEnd 종료 수치값
 * @return {Function} 생성된 이펙트 함수
 */
nhn.Effect.bounce = nhn.Effect(function(s) {
	if (s < (1 / 2.75)) return (7.5625 * s * s);
	else if (s < (2 / 2.75)) return (7.5625 * (s -= (1.5 / 2.75)) * s + .75);
	else if (s < (2.5 / 2.75)) return (7.5625 * (s -= (2.25 / 2.75)) * s + .9375);
	else return (7.5625 * (s -= (2.625 / 2.75)) * s + .984375);
});

// jindo.$Element.prototype.css 패치
(function() {
	var b = jindo.$Element.prototype.css;
	jindo.$Element.prototype.css = function(k, v) {
		if (k == 'opacity') return typeof v != 'undefined' ? this.opacity(parseFloat(v)) : this.opacity();
		return v != 'undefined' ? b.call(this, k, v) : b.call(this, k);
	};
})();
