
import { TweenEasing } from "./TweenEasing";
const { ccclass, property, executeInEditMode, playOnFocus } = cc._decorator;
/**
 * 缓动数据
 * @author 薛鸿潇
 */
@ccclass("PropsData")
export class PropsData {
    @property({ displayName: "坐标" })
    public position: cc.Vec2 = cc.Vec2.ZERO;
    @property({ displayName: "旋转" })
    public angle: number = 0;
    @property({ displayName: "缩放" })
    public scale: number = 1;
}
/**
 * 缓动数据
 * @author 薛鸿潇
 */
@ccclass("TweenData")
export class TweenData {
    @property({ displayName: "属性数据", type: PropsData })
    public propsData: PropsData = new PropsData();
    @property({ displayName: "持续时间", tooltip: '单位：秒' })
    public duration: number = 0.3;
    @property({ displayName: "延迟时间", tooltip: '单位：秒' })
    public delay: number = 0;
    @property({ displayName: "是否为差值" })
    public isOffset: boolean = false;
    @property({ displayName: '完成回调', tooltip: "缓动完成时触发", type: cc.Component.EventHandler })
    public onComplete: cc.Component.EventHandler = new cc.Component.EventHandler();
    @property({ displayName: '开始回调', tooltip: "缓动启动时触发", type: cc.Component.EventHandler })
    public onStart: cc.Component.EventHandler = new cc.Component.EventHandler();
    @property({ displayName: '过程回调', tooltip: "缓动更新时触发", type: cc.Component.EventHandler })
    public onUpdate: cc.Component.EventHandler = new cc.Component.EventHandler();
}
/**
 * 缓动组件，目前只支持节点的三个基础属性
 * @author 薛鸿潇
 */
@ccclass
@executeInEditMode()
@playOnFocus()
export class UITween extends cc.Component {
    @property({ displayName: "节点初始属性", type: PropsData })
    public fromData: PropsData = new PropsData();
    @property({ displayName: "节点目标属性", type: TweenData })
    public targetData: TweenData[] = [];
    @property({ displayName: '缓动节点', tooltip: "要播放缓动动画的目标，不填则是当前节点", type: cc.Node })
    public target: cc.Node = null;
    @property({ displayName: "缓动效果", type: cc.Enum(TweenEasing) })
    public tweenEasing: TweenEasing = TweenEasing.linear;
    @property({ displayName: '执行次数', tooltip: "为0则一直重复执行" })
    public repeat: number = 1;
    @property({ displayName: "单次完成回调", tooltip: '单次缓动序列执行完毕时触发', type: cc.Component.EventHandler })
    public onOneRepeatComplete: cc.Component.EventHandler = new cc.Component.EventHandler();
    @property({ displayName: "自动播放" }) 
    public playOnLoad: boolean = false;

    private _edit_play: boolean = false;
    @property({ displayName: "编辑器预览" })
    get edit_play(): boolean {
        if (this._edit_play && !this.edit_playing) {
            this.edit_playing = true;
            this.play();
        }
        return this._edit_play;
    }
    set edit_play(v: boolean) {
        this._edit_play = v;
        if (this.target && v) {
            this.target.stopAllActions();
        }
        if (!v) this.edit_playing = false;
    }
    /** 编辑器是否正在播放 */
    private edit_playing = false;

    public start() {
        !this.target && (this.target = this.node);
        this.target = this.target || this.node;
        this.currentRepeat = this.repeat;
        if (CC_EDITOR) {
            this._edit_play && this.play();
        } else {
            this.playOnLoad && this.play();
        }
    }
    private t: cc.Tween<any>;
    /** 剩余播放次数 */
    private currentRepeat: number;
    public play() {
        if (CC_EDITOR && !this.edit_playing) return;
        if (this.repeat == 0) {
            this.t = cc.tween(this.target);
            this.readyPlay();
            this.t = this.t.call(this.play.bind(this));
            this.t.start();
        }
        else if (this.currentRepeat) {
            this.t = cc.tween(this.target);
            this.readyPlay();
            this.t = this.t.call(this.play.bind(this));
            this.currentRepeat--;
            this.t.start();
        }
        else {
            this.t = null;
        }
    }
    public readyPlay() {
        let self = this;
        if (this.fromData) {
            this.node.setPosition(this.fromData.position.clone());
            this.node.scale = this.fromData.scale;
            this.node.angle = this.fromData.angle;
        }
        if (this.targetData.length) {
            for (let i = 0; i < this.targetData.length; i++) {
                const targetData = this.targetData[i];
                if (targetData.delay != 0) {
                    this.t = this.t.delay(targetData.delay);
                }
                let toData = {
                    position: targetData.propsData.position,
                    scale: targetData.propsData.scale,
                    angle: targetData.propsData.angle
                }
                if (targetData.isOffset) {
                    toData.position = this.node.getPosition().add(targetData.propsData.position);
                    toData.scale = this.node.scale + targetData.propsData.scale;
                    toData.angle = this.node.angle + targetData.propsData.angle;
                }
                this.t = this.t.to(
                    targetData.duration,
                    toData,
                    {
                        easing: TweenEasing[this.tweenEasing] as any,
                        onComplete: (target: cc.Node) => {
                            targetData.onComplete && targetData.onComplete.emit([target]);
                            this.edit_playing = false;
                            this._edit_play = false;
                        },
                        onStart: (target: cc.Node) => { targetData.onStart && targetData.onStart.emit([target]) },
                        onUpdate: (target: cc.Node, ratio: number) => { targetData.onUpdate && targetData.onUpdate.emit([target, ratio]) }
                    }
                );
            }
        }
        if (this.onOneRepeatComplete) {
            this.t = this.t.call(() => {
                self.onOneRepeatComplete.emit([this, this.t])
            });
        }
    }
}