/**
 * 계획된 여러 애니메이션을 다룰 수 있는 Queue
 * 
 * [튜토리얼 보기](../tutorial/timer_queue.html)
 * 
 * @see collie.Timer
 * @class
 * @extends collie.Animation
 * @param {Object} [htOption]
 * @param {Object} [htOption.loop=1] 큐 반복 횟수, 0일 경우 무한 반복 한다
 * @example
 * collie.Timer.queue({ loop : 1 }).
 *              delay(function () {}, 1000).
 *              transition(function () {}, 1000, { from : 1, to : 1 });
 */
collie.AnimationQueue = collie.Class(/** @lends collie.AnimationQueue.prototype */{
    $init : function (htOption) {
        this.option("loop", 1);
        this.option(htOption || {});
        this.setOptionEvent(htOption);
        this._aAnimations = [];
        this._fOnCompleteAnimation = this._onCompleteAnimation.bind(this);
        this.reset();
    },
    
    /**
     * queue에 delay 애니메이션을 추가한다
     * @see collie.AnimationDelay
     * @return {collie.AnimationQueue} 메서드 체이닝 사용 가능
     */
    delay : function (fCallback, nDuration, htOption) {
        this._add(new collie.AnimationDelay(fCallback, nDuration, htOption));
        return this;
    },
    
    /**
     * queue에 repeat 애니메이션을 추가한다
     * @see collie.AnimationRepeat
     * @return {collie.AnimationQueue} 메서드 체이닝 사용 가능
     */
    repeat : function (fCallback, nDuration, htOption) {
        this._add(new collie.AnimationRepeat(fCallback, nDuration, htOption));
        return this;
    },
    
    /**
     * queue에 transition 애니메이션을 추가한다
     * @see collie.AnimationTransition
     * @return {collie.AnimationQueue} 메서드 체이닝 사용 가능
     */
    transition : function (fCallback, nDuration, htOption) {
        this._add(new collie.AnimationTransition(fCallback, nDuration, htOption));
        return this;
    },
    
    /**
     * queue에 cycle 애니메이션을 추가한다
     * @see collie.AnimationCycle
     * @return {collie.AnimationQueue} 메서드 체이닝 사용 가능
     */
    cycle : function (fCallback, nDuration, htOption) {
        this._add(new collie.AnimationCycle(fCallback, nDuration, htOption));
        return this;
    },
    
    /**
     * 등록된 애니메이션 인스턴스를 반환한다
     * 
     * @param {Number} nIdx 등록 순서 (0~)
     * @return {collie.Animation}
     */
    getAnimation : function (nIdx) {
        return this._aAnimations[nIdx] || false;
    },
    
    /**
     * 애니메이션 인스턴스를 추가
     * 
     * @private
     * @param {collie.Animation} oAnimation 추가될 애니메이션
     */
    _add : function (oAnimation) {
        oAnimation.attach("complete", this._fOnCompleteAnimation);
        this._aAnimations.push(oAnimation);
    },
    
    /**
     * 각 애니메이션이 종료되었을 때 처리하는 이벤트 핸들러
     * @private
     */
    _onCompleteAnimation : function () {
        this.next();
    },

    /**
     * 다음 애니메이션으로 넘긴다
     */
    next : function () {
        if (this._nAnimationIdx === null) {
            this._nAnimationIdx = 0;
        } else {
            this._nAnimationIdx++;
        }
        
        // 종료되면
        if (this._nAnimationIdx >= this._aAnimations.length) {
            this._nCount++;
            
            /**
             * 계획된 모든 애니메이션이 끝날 때 마다 발생, loop 설정과 관계 없이 매번 일어난다
             * @name collie.AnimationQueue#end
             * @event
             * @param {Object} oEvent 기본 컴포넌트 이벤트 객체
             * @param {Object} oEvent.count 현재까지 반복된 횟수
             */
            this.fireEvent("end", {
                count : this._nCount
            });
            
            // loop 설정이 있으면 되돌림
            if (!this._htOption.loop || this._htOption.loop > this._nCount) {
                this._nAnimationIdx = 0;
            } else {
                /**
                 * 계획된 모든 애니메이션과 반복 횟수가 끝나면 발생. loop=0으로 설정하면 발생하지 않는다.
                 * @name collie.AnimationQueue#complete
                 * @event
                 * @param {Object} oEvent 기본 컴포넌트 이벤트 객체
                 */
                this.complete();
                return;
            }
        }
        
        this._aAnimations[this._nAnimationIdx].stop();
        this._aAnimations[this._nAnimationIdx].start();
    },
    
    /**
     * 값을 초기화
     */
    reset : function () {
        this._nFrameAtRunLastest = null;
        this._nAnimationIdx = null;
        this._nCount = 0;
    },
    
    /**
     * 등록된 모든 애니메이션을 제거
     */
    removeAll : function () {
        this._aAnimations = [];
        this.reset();
    },
    
    /**
     * 현재 진행 중인 애니메이션까지 남기고 나머지를 지움
     */
    removeAfter : function () {
        if (this._nAnimationIdx + 1 <= this._aAnimations.length - 1) {
            var count = this._aAnimations.length - (this._nAnimationIdx + 1); 
            this._aAnimations.splice(this._nAnimationIdx + 1, count);
        }
    },
    
    /**
     * 애니메이션을 실행
     * 
     * @param {Number} [nCurrentFrame] 현재 렌더러 프레임, 값이 없으면 자동으로 현재 렌더러 프레임을 가져 온다
     * @param {Number} [nFrameDuration] 진행된 프레임 시간(ms)
     */
    run : function (nCurrentFrame, nFrameDuration) {
        // 등록된 애니메이션이 없는 경우에는 지나감
        if (this._aAnimations.length < 1) {
            return; 
        }
        
        if (nCurrentFrame === undefined) {
            nCurrentFrame = collie.Renderer.getInfo().frame;
        }
        
        // 렌더러가 stop 된 경우
        if (this._nFrameAtRunLastest > nCurrentFrame) {
            this.reset();
            return;
        }
        
        // 시작되지 않았을 때 시작 시점 기록
        if (this._nFrameAtRunLastest === null) {
            this._nFrameAtRunLastest = nCurrentFrame;
        }
        
        if (this._nAnimationIdx === null) {
            this.next();
        }
        
        this._aAnimations[this._nAnimationIdx].run(nCurrentFrame, nFrameDuration);
    }
}, collie.Animation);