/**
 * Created by rockyl on 2018/8/17.
 */

import {props} from "../props";
import {createSvga, playSound} from "./utils";

const svgaAssets = {
	aniReady: {name: '准备立正', dir: 1},
	aniJump: {name: '跳上升', dir: 1},
	aniFall: {name: '跳下落', dir: 1},
	aniLandNormal: {name: '普通着地', dir: 1},
	aniLandSide: {name: '边缘着地', dir: -1},
	aniHit: {name: '被撞开', dir: -1},
	aniParachute: {name: '降落', dir: -1},
};

export default class Player extends engine.Container {
	private jumpPromise;
	private playing;
	private vy;
	private g = props.gravity;
	private baseY;

	private aboveBlock;

	private _aniName;

	private _currentAni: svga.Svga;
	private _prefectLandCounting;

	private aniJump: svga.Svga;
	private aniFall: svga.Svga;
	private aniLandNormal: svga.Svga;
	private aniLandSide: svga.Svga;
	private aniHit: svga.Svga;
	private aniParachute: svga.Svga;

	private prefectEffect: svga.Svga;
	private landEffect: svga.Svga;

	constructor() {
		super();

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

	switchAni(name, dir = 1, play = true, loop = false) {
		return new Promise(resolve => {
			this.scaleX = dir;
			if (this._aniName !== name) {
				this._aniName = name;
				let oldAni = <svga.Svga>this.removeChild(this.getChildByName('body'));
				if (oldAni) {
					oldAni.stop();
				}
				let ani: svga.Svga = this._currentAni = this['ani' + name];
				this.addChild(ani);

				if (play) {
					ani.play(false, loop);
					if (loop) {
						resolve();
					} else {
						ani.once(engine.Event.END_FRAME, resolve);
					}
				} else {
					ani.gotoAndStop(1);
					resolve();
				}
			}
		})
	}

	setup() {
		this.prefectEffect = createSvga('完美着地特效', 'playerLandPrefectAnchor');
		this.landEffect = createSvga('着地特效', 'playerLandEffectAnchor');

		for (let key in svgaAssets) {
			let {name, dir} = svgaAssets[key];
			let body = this[key] = createSvga(name, key.replace('ani', 'player') + 'Anchor');

			body.name = 'body';
			body.scaleX = dir;
		}
	}

	reset(revive) {
		this.x = 0;
		this.rotation = 0;
		this.scaleX = this.scaleY = 1;
		this._prefectLandCounting = 0;

		engine.Tween.removeTweens(this);
		if(revive){
			this.switchAni('Jump', 1, false);
		}
	}

	playReady() {
		return new Promise(resolve => {
			this.switchAni('Ready', 1);
			this._currentAni.once(engine.Event.END_FRAME, function () {
				this.switchAni('Jump', 1, false);
				resolve();
			}, this);
		})
	}

	private onEnterFrame(event) {
		if (!this.playing) {
			return;
		}

		this.vy += this.g;
		this.y += this.vy;

		if (this.vy > 0 && this._aniName !== 'Fall') {
			this.dispatchEvent('jump-on-top');
			this.switchAni('Fall');
		}

		if (this.y > this.baseY) {
			this.y = this.baseY;

			this.playing = false;
			//this.aniDown.play(0);

			this.jumpPromise && this.jumpPromise({
				aboveBlock: this.aboveBlock,
			});
			this.jumpPromise = null;
		}
	}

	changeBaseY(v) {
		if (this.baseY == v) {
			return;
		}

		this.aboveBlock = true;
		this.baseY = v;
	}

	jump() {
		playSound('跳起音效');
		this.switchAni('Jump', 1, false);
		this._currentAni.play(false, false);

		this.aboveBlock = false;
		this.playing = true;

		this.baseY = this.y;
		this.vy = -props.jumpSpeed;

		return new Promise(resolve => {
			this.jumpPromise = resolve;
		})
	}

	async playLand(type, dir) {
		switch (type) {
			case 0:
				this._prefectLandCounting++;
				playSound('完美落地音效' + Math.min(4, this._prefectLandCounting));

				let prefectEffect = this.prefectEffect;
				this.addChildAt(prefectEffect, 0);
				prefectEffect.gotoAndPlay(1);
				prefectEffect.once(engine.Event.END_FRAME, function () {
					this.removeChild(prefectEffect);
				}, this);

				let landEffect = this.landEffect;
				this.addChildAt(landEffect, 0);
				landEffect.gotoAndPlay(1);
				landEffect.once(engine.Event.END_FRAME, function () {
					this.removeChild(landEffect);
				}, this);

				await this.switchAni('LandNormal');
				break;
			case 1:
			case 2:
				this._prefectLandCounting = 0;
				playSound('普通落地音效');
				this.switchAni('LandNormal');
				break;
			case 3:
				this._prefectLandCounting = 0;
				playSound('边缘落地音效');
				this.switchAni('LandSide', dir);
				break;
		}
	}

	async hitAway(dir) {
		this.jumpPromise && this.jumpPromise();
		this.jumpPromise = null;

		playSound('被撞开音效');
		this.switchAni('Hit', dir);

		this.vy = 0;
		await new Promise(resolve => {
			engine.Tween.get(this)
				.to({
					x: -dir * props.hitAwayDistance.x,
				}, props.hitAwayDuration, engine.Ease.quartOut);
			engine.Tween.get(this)
				.to({
					y: this.y + props.hitAwayDistance.y,
				}, props.hitAwayDuration, engine.Ease.cubicOut)
				.call(resolve)
		});
	}

	parachute(dir) {
		this.switchAni('Parachute', dir);

		return new Promise(resolve => {
			engine.Tween.get(this)
				.wait(200)
				.call(function () {
					playSound('降落伞下落音效');
				})
				.wait(300)
				.to({y: this.y + props.parachuteDistance}, props.parachuteDuration)
				.set({anchorOffsetY: 0})
				.call(resolve)
		});
	}
}
