/**
 * Created by rockyl on 2018/11/5.
 *
 * 波动组件
 */

import {ScillaComponent, raw, ScillaEvent} from "scilla";

const PI2 = Math.PI * 2;

export enum WaveMethod {
	/**
	 * 公转
	 */
	round = 'round',
	/**
	 * 自转
	 */
	rotate = 'rotate',
	/**
	 * 缩放
	 */
	zoom = 'zoom',
	/**
	 * 透明渐变
	 */
	fade = 'fade',
	/**
	 * 横向波动
	 */
	cosWave = 'cosWave',
	/**
	 * 纵向波动
	 */
	sinWave = 'sinWave',
	/**
	 * 抖动
	 */
	shake = 'shake',
	/**
	 * 呼吸
	 */
	breath = 'breath',
}

export default class Wave extends ScillaComponent {
	duration: number = 1000;
	waveMethod: WaveMethod;
	waveParams: raw;
	loop: number = -1;
	autoPlay: boolean = true;

	onComplete: ScillaEvent = new ScillaEvent();
	onLoopComplete: ScillaEvent = new ScillaEvent();

	private _playing;
	private _waveMethod;
	private _startTime;
	private _oldProps: any = {};
	private _loopCounting;

	onAwake() {
		super.onAwake();

		this._waveMethod = waveLibs[this.waveMethod];
		this._startTime = 0;

		const {transform: {position}} = this;
		this._oldProps.x = position.x;
		this._oldProps.y = position.y;

		if (this.autoPlay) {
			this.play();
		}
	}

	onUpdate(t) {
		super.onUpdate(t);

		if (this._playing) {
			if (!this._startTime) {
				this._startTime = t;
			}

			const {duration, waveParams, _waveMethod, transform, transform: {position, scale}, _oldProps} = this;

			let pass = (t - this._startTime) % duration;
			let r = pass / duration * PI2;

			let loopCounting = Math.floor((t - this._startTime) / duration);
			if(loopCounting != this._loopCounting){
				this._loopCounting = loopCounting;
				if(this.onLoopEnd()){
					r = PI2;
				}
			}

			let params = waveParams || [];
			let props = _waveMethod(...params, r);

			if (props.hasOwnProperty('x')) {
				position.x = (props.x || 0) + _oldProps.x;
			}
			if (props.hasOwnProperty('y')) {
				position.y = (props.y || 0) + _oldProps.y;
			}
			if (props.hasOwnProperty('sx')) {
				scale.x = props.sx;
			}
			if (props.hasOwnProperty('sy')) {
				scale.y = props.sy;
			}
			if (props.hasOwnProperty('r')) {
				transform.rotation = props.r;
			}
		}
	}

	private onLoopEnd(){
		if (this.loop < 0) {
			this.onLoopComplete.invoke();
		} else if (this._loopCounting < this.loop) {
			this.onLoopComplete.invoke();
		} else {
			this._playing = false;
			this.onComplete.invoke();
			return true;
		}
	}

	play() {
		this._loopCounting = 0;
		this._playing = true;
		this._startTime = 0;
	}

	stop() {
		this._playing = false;
	}
}

const {cos, sin, PI} = Math;

const waveLibs = {
	round: function (h: number, t: number): any {
		return {x: cos(t) * h, y: sin(t) * h};
	},

	cosWave: function (h: number, t: number): any {
		return {x: cos(t) * h, y: 0};
	},

	sinWave: function (h: number, t: number): any {
		h = h || 1;
		return {x: 0, y: sin(t) * h};
	},

	rotate: function (t: number): any {
		return {r: 360 * t / PI / 2};
	},

	shake: function (angle: number, count: number, t: number): any {
		return {r: sin(t * count) * angle};
	},

	breath: function (scale: number = 0.1, t: number): any {
		return {sx: sin(t) * scale + 1, sy: -sin(t + PI / 4) * scale + 1};
	},

	zoom: function (scale: number = 0.1, t: number): any {
		return {sx: sin(t) * scale + 1, sy: sin(t) * scale + 1};
	},

	fade: function (base = 1, t: number): any {
		return {alpha: (sin(t) + 1) * 0.5 + base};
	},
};

