/**
 * Created by rockyl on 2020-01-09.
 */

import ObjectPool = engine.ObjectPool;

const PoolName: string = 'pack';

ObjectPool.registerPool(PoolName, function () {
	return new RedPack();
}, function (redPack: RedPack, data) {
	redPack.init(data);
});

class RedPack extends engine.Image {
	private data;
	private _pos: engine.Point = new engine.Point();
	private _globalPos: engine.Point = new engine.Point();

	get pos() {
		return this._pos;
	}
	get globalPos() {
		return this._globalPos;
	}

	init(data) {
		this.data = data;

		const {source, initPos} = data;

		this.source = source;

		this.x = this._pos.x = initPos;
		this.y = this._pos.y = -this.height;
	}

	schedule() {
		const {width, height, data: {angleOffset, speed}} = this;

		let radian = (angleOffset + 90) * Math.PI / 180;

		let speedX = Math.cos(radian) * speed;
		let speedY = Math.sin(radian) * speed;

		this.x = this._pos.x += speedX;
		this.y = this._pos.y += speedY;

		this.wrapper.localToGlobal(this._pos, this._globalPos);
		const {_globalPos: {x, y}} = this;
		if (y < -height || y > this.stage.height) {
			return true;
		}
		if (angleOffset > 0) {
			if (x < -width) {
				return true;
			}
		} else if (angleOffset < 0) {
			if (x > this.stage.width) {
				return true;
			}
		}
	}
}

export class RedPackRain extends engine.Container {
	private assets;
	private speedRange;
	private initPosRange;
	private angleOffset = 0;
	private intervalFrames = 10;

	private _status;
	private _intervalCounting;

	constructor() {
		super();

		engine.globalEvent.addEventListener('redpack-rain-reset', this.reset, this);
		engine.globalEvent.addEventListener('redpack-rain-start', this.start, this);
		engine.globalEvent.addEventListener('redpack-rain-pause', this.pause, this);
		engine.globalEvent.addEventListener('redpack-rain-resume', this.start, this);
		engine.globalEvent.addEventListener('redpack-rain-stop', this.stop, this);

		this.addEventListener(engine.Event.ENTER_FRAME, this.onEnterFrame, this);
		this.addEventListener(engine.MouseEvent.CLICK, this.onTap, this);
	}

	reset() {
		this.pause();

		while (this.children.length > 0) {
			this.recycleOne(this.children[0]);
		}
	}

	start(event: engine.Event) {
		if ('redpack-rain-start') {
			engine.injectProp(this, event.data);
		}

		this._status = 1;
		this._intervalCounting = this.intervalFrames;
	}

	pause() {
		this._status = 0;
	}

	stop() {
		this.reset();
	}

	recycleOne(child) {
		this.removeChild(child);
		ObjectPool.recycleObject(PoolName, child);
	}

	dropOne() {
		const {assets, angleOffset, speedRange, initPosRange} = this;

		let r = Math.random();
		let targetAssetIndex;
		for (let i = 0, li = assets.length; i < li; i++) {
			const asset = assets[i];
			r -= asset.ratio;
			if (r <= 0) {
				targetAssetIndex = i;
				break;
			}
		}

		let pack = <RedPack>engine.ObjectPool.getObject(PoolName, {
			type: targetAssetIndex,
			source: assets[targetAssetIndex].source,
			angleOffset,
			speed: Math.random() * (speedRange.max - speedRange.min) + speedRange.min,
			initPos: Math.random() * (initPosRange.max - initPosRange.min) + initPosRange.min,
		});

		this.addChild(pack);
	};

	private onEnterFrame(event) {
		if (this._status === 1) {
			this._intervalCounting--;
			if (this._intervalCounting <= 0) {
				this._intervalCounting = this.intervalFrames;
				this.dropOne();
			}
		}

		for (let i = 0, li = this.children.length; i < li; i++) {
			const child: RedPack = this.children[i];

			if (child.schedule()) {
				i--;
				li--;

				this.recycleOne(child);
			}
		}
	}

	private onTap(event) {
		if (event.currentTarget instanceof RedPack) {
			const {type, pos, globalPos} = event.currentTarget;
			let data = {type, pos, globalPos};

			this.recycleOne(event.currentTarget);
			engine.globalEvent.dispatchEvent('redpack-rain-hit', data);
		}
	}
}
