/**
 * Created by rockyl on 2018/11/8.
 *
 * 缓动函数集合，使用不同的缓动函数使得动画按照对应的方程进行
 */

export enum Ease {
	linear = 'linear',
	quadIn = 'quadIn',
	quadOut = 'quadOut',
	quadInOut = 'quadInOut',
	cubicIn = 'cubicIn',
	cubicOut = 'cubicOut',
	cubicInOut = 'cubicInOut',
	quartIn = 'quartIn',
	quartOut = 'quartOut',
	quartInOut = 'quartInOut',
	quintIn = 'quintIn',
	quintOut = 'quintOut',
	quintInOut = 'quintInOut',
	sineIn = 'sineIn',
	sineOut = 'sineOut',
	sineInOut = 'sineInOut',
	backIn = 'backIn',
	backOut = 'backOut',
	backInOut = 'backInOut',
	circIn = 'circIn',
	circOut = 'circOut',
	circInOut = 'circInOut',
	bounceIn = 'bounceIn',
	bounceOut = 'bounceOut',
	bounceInOut = 'bounceInOut',
	elasticIn = 'elasticIn',
	elasticOut = 'elasticOut',
	elasticInOut = 'elasticInOut',
}

export function linear(t){
	return t;
}

export function get(amount) {
	if (amount < -1) {
		amount = -1;
	}
	if (amount > 1) {
		amount = 1;
	}
	return function (t) {
		if (amount == 0) {
			return t;
		}
		if (amount < 0) {
			return t * (t * -amount + 1 + amount);
		}
		return t * ((2 - t) * amount + (1 - amount));
	}
}

export function getPowIn(pow) {
	return function (t) {
		return Math.pow(t, pow);
	}
}

export function getPowOut(pow) {
	return function (t) {
		return 1 - Math.pow(1 - t, pow);
	}
}

export function getPowInOut(pow) {
	return function (t) {
		if ((t *= 2) < 1) return 0.5 * Math.pow(t, pow);
		return 1 - 0.5 * Math.abs(Math.pow(2 - t, pow));
	}
}

export const quadIn = getPowIn(2);

export const quadOut = getPowOut(2);

export const quadInOut = getPowInOut(2);

export const cubicIn = getPowIn(3);

export const cubicOut = getPowOut(3);

export const cubicInOut = getPowInOut(3);

export const quartIn = getPowIn(4);

export const quartOut = getPowOut(4);

export const quartInOut = getPowInOut(4);

export const quintIn = getPowIn(5);

export const quintOut = getPowOut(5);

export const quintInOut = getPowInOut(5);


export function sineIn(t) {
	return 1 - Math.cos(t * Math.PI / 2);
}

export function sineOut(t) {
	return Math.sin(t * Math.PI / 2);
}

export function sineInOut(t) {
	return -0.5 * (Math.cos(Math.PI * t) - 1)
}


export function getBackIn(amount) {
	return function (t) {
		return t * t * ((amount + 1) * t - amount);
	}
}

export const backIn = getBackIn(1.7);

export function getBackOut(amount) {
	return function (t) {
		return (--t * t * ((amount + 1) * t + amount) + 1);
	}
}

export const backOut = getBackOut(1.7);

export function getBackInOut(amount) {
	amount *= 1.525;
	return function (t) {
		if ((t *= 2) < 1) return 0.5 * (t * t * ((amount + 1) * t - amount));
		return 0.5 * ((t -= 2) * t * ((amount + 1) * t + amount) + 2);
	}
}


export const backInOut = getBackInOut(1.7);


export function circIn(t) {
	return -(Math.sqrt(1 - t * t) - 1);
}


export function circOut(t) {
	return Math.sqrt(1 - (--t) * t);
}


export function circInOut(t) {
	if ((t *= 2) < 1) {
		return -0.5 * (Math.sqrt(1 - t * t) - 1);
	}
	return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
}


export function bounceIn(t) {
	return 1 - bounceOut(1 - t);
}


export function bounceOut(t) {
	if (t < 1 / 2.75) {
		return (7.5625 * t * t);
	} else if (t < 2 / 2.75) {
		return (7.5625 * (t -= 1.5 / 2.75) * t + 0.75);
	} else if (t < 2.5 / 2.75) {
		return (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375);
	} else {
		return (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375);
	}
}


export function bounceInOut(t) {
	if (t < 0.5) return bounceIn(t * 2) * .5;
	return bounceOut(t * 2 - 1) * 0.5 + 0.5;
}

export function getElasticIn(amplitude, period) {
	let pi2 = Math.PI * 2;
	return function (t) {
		if (t == 0 || t == 1) return t;
		let s = period / pi2 * Math.asin(1 / amplitude);
		return -(amplitude * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * pi2 / period));
	}
}

export const elasticIn = getElasticIn(1, 0.3);


export function getElasticOut(amplitude, period) {
	let pi2 = Math.PI * 2;
	return function (t) {
		if (t == 0 || t == 1) return t;
		let s = period / pi2 * Math.asin(1 / amplitude);
		return (amplitude * Math.pow(2, -10 * t) * Math.sin((t - s) * pi2 / period) + 1);
	}
}


export const elasticOut = getElasticOut(1, 0.3);


export function getElasticInOut(amplitude, period) {
	let pi2 = Math.PI * 2;
	return function (t) {
		let s = period / pi2 * Math.asin(1 / amplitude);
		if ((t *= 2) < 1) return -0.5 * (amplitude * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * pi2 / period));
		return amplitude * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * pi2 / period) * 0.5 + 1;
	}
}


export const elasticInOut = getElasticInOut(1, 0.3 * 1.5);
