goog.provide('FlappMovieClip');
goog.require('FlappObject');
goog.require('FlappDisplay');
goog.require('FlappShape');
goog.require('FlappAction');
goog.require('FlappCanvas');

goog.scope(function() {

/**
 * @constructor
 */
FlappMovieClip = function(parentMovieClip, matrix, colorTransform) {
    this.OBJECT_TYPE = 2; // 1:Shape, 2:MovieClip
    this.parentMovieClip = parentMovieClip?parentMovieClip:null;
    this.rootMovieClip = parentMovieClip?parentMovieClip.rootMovieClip:this;
    this.name = null;
    this.setMatrix(matrix);
    this.colorTransform = colorTransform;
    this.childMovieClips = {}; // name => movieClip
    this.instanceSeqno = 1; // for name object (movieClip, etc...)
    this.clearControlTags();
    //
    this.prevShowFramePos = 0;
    //
    var canvas = document.createElement('canvas');
    canvas.width = 240; // XXX
    canvas.height = 240; // XXX
    this.canvas = new FlappCanvas(canvas);
    this.canvasDirty = false; // dirtyFlag
    //
    this.displayList = new FlappDisplay();
    this.displayObjectLifeSpan = {}; // for gotoFrame
    //
    this.totalframes = 0;
    this.currentFrame = 0;
    this.playing = true;
    this.loop = true;
//    this.loop = false;
    this.actionVarriableTable = {};
    this.actionVarriablOrigKeys = {};
};

FlappMovieClip.prototype = {
    setMatrix: function(matrix) {
        this.matrix = matrix;
        this.absoluteMatrix = this.parentMovieClip?(matrix?FlappSWFMatrix.multiply(this.parentMovieClip.absoluteMatrix, matrix):this.parentMovieClip.absoluteMatrix):matrix;
    },
    clearControlTags: function() {
        this.controlTagsList = [[]]; //
        this.actionTagsList = [[]];
        this.labelMap = {}; // label => frameNum
        this.framesLoaded = 0;
    },
    appendControlTag: function(controlTag) {
        // console.debug("FlappMovieClip::appendControlTag");
        if (controlTag.code === 12) { // DoAction
            this.actionTagsList[this.framesLoaded].push(controlTag);
            return ;
        }
        this.controlTagsList[this.framesLoaded].push(controlTag);
        if (controlTag.code === 1) { // ShowFrame
            this.controlTagsList.push([]);
            this.actionTagsList.push([]);
            this.framesLoaded++;
        } else if (controlTag.code === 43) { // FrameLabel
            this.labelMap[controlTag.name] = this.framesLoaded;
        }
    },
    setControlTags: function(controlTags) {
        this.clearControlTags();
        for (var i = 0, l = controlTags.length ; i < l ; i++) {
            this.appendControlTag(controlTags[i]);
        }
    },
    addChildMovieClip: function(name, movieClip) {
        this.childMovieClips[name] = movieClip;
    },
    deleteChildMovieClip: function(name) {
        delete this.childMovieClips[name];
    },
    control: function(dict) {
        if (this.totalframes === 0) { // imcomplete
            return false;
        }
//        console.debug("FlappMovieClip::control: name:"+this.name+" playing:"+this.playing);
        if (this.framesLoaded < this.totalframes) { // imcomplete
            if (this.currentFrame < this.framesLoaded) {
                console.debug("control:imcomplete (currentFrame:"+this.currentFrame+" < framesLoaded:"+this.framesLoaded+")");
                return false; // idle
            }
        }
        for (var mc in this.childMovieClips) {
            this.childMovieClips[mc].control(dict);
        }
        if (this.playing) {
            this.controlThis(dict);
        }
        return true;
    },
    controlThis: function(dict) {
//        console.debug("FlappMovieClip::controlThis: name:"+this.name);
        var tag, i, l;
        var defineTag;
        if ((this.currentFrame < 0 ) || (this.totalframes <= this.currentFrame)) {
            this.currentFrame = 0;
        }
        var controlTags = this.controlTagsList[this.currentFrame];

        for (i = 0, l = controlTags.length ; i < l ; i++) {
            tag = controlTags[i];
            switch (tag.code) {
            case 1: // ShowFrame
                break;
            case 4:  // PlaceObject
            case 26: // PlaceObject2
                // set display List;
                var obj = null;
                if (tag.move && (tag.id === null)) {
                    this.displayList.move(tag.depth, tag);
                } else {
                    if (tag.move) {
                        obj = this.displayList.get(tag.depth);
                        if (obj === null) {
                            console.error("Can't get DisplayObject by depth:"+tag.depth);
                        }
                        if (obj.code === 39) { // DefineSprite
                            this.deleteChildMovieClip(obj.name);
                        }
                        this.displayList.del(tag.depth);
                    }
                    defineTag = dict.get(tag.id);
                    if (defineTag === null) {
                        console.error("defineTag === undefined");
                        return ;
                    }
                    var name = tag.name;
                    if ((name === null) && (defineTag.code === 39)) {
                        name = "instance"+this.instanceSeqno;
                        tag.name = name;
                        this.instanceSeqno++;
                    }
                    obj = FlappObject.factory(this, name, defineTag, tag,
                                              dict);
//                    console.debug(obj);
                     if (defineTag.code === 39) { // DefineSprite
                        obj.totalframes = defineTag.count;
                        obj.control(dict);
                        this.addChildMovieClip(name, obj);
                    }
                    this.displayList.set(tag.depth, obj, tag);
                    break;
                }
                break;
            case 5:  // RemoveObject XXX
            case 28: // RemoveObject2
                this.displayList.del(tag.depth);
                break;
            }
        }
    },
    action: function() {
        for (var mc in this.childMovieClips) {
            this.childMovieClips[mc].action();
        }
        if (this.playing) {
            this.actionThis();
        }

    },
    actionThis: function() {
        var actionTags = this.actionTagsList[this.currentFrame];
        var l = actionTags.length;
//        console.debug("FlappMovieClip::actionThis: actionTags.length:"+l);
        for (var i = 0 ; i < l ; i++) {
            var tag = actionTags[i];
            var movieClip = this;
            FlappAction.exec(tag, movieClip, this.rootMovieClip);
        }
    },
    increment: function() {
        for (var mc in this.childMovieClips) {
            this.childMovieClips[mc].increment();
        }
        if (this.playing) {
            this.incrementThis();
        }
    },
    incrementThis: function() {
//        console.debug("FlappMovieClip::incrementThis: "+this.currentFrame);
        this.currentFrame++;
        if (this.totalframes <= this.currentFrame) {
            if (this.loop) {
                this.currentFrame = 0; // play
            } else {
                this.playing = false;
            }
        }
        if (this.totalframes === 1) {
            this.playing = false;
        }
    },
    render: function(canvas, dict) {
//        console.debug("FlappMovieClip::render: name:"+this.name);
        var depthList = this.displayList.ascSortedDepth();
        for (var i = 0, l = depthList.length  ; i < l ; i++) {
            var depth = depthList[i];
            var obj = this.displayList.get(depth);
//            console.debug(obj);
            obj.render(canvas, dict);
        }
    },
    setVariable: function(key, value) {
        var lcKey = key.toLowerCase();
        this.actionVarriableTable[lcKey] = value;
        this.actionVarriablOrigKeys[lcKey] = key;
    },
    getVariable: function(key) {
        var lcKey = key.toLowerCase();
        if (lcKey in this.actionVarriableTable) {
            return this.actionVarriableTable[lcKey];
        }
        return null;
    },
    gotoFrame: function(frameNum) {
        console.debug("FlappMovieClip::gotoFrame"+frameNum);
        this.currentFrame = frameNum;
    },
    gotoLabel: function(frameLabel) {
        var frameNum = this.labelMap[frameLabel];
        console.debug("FlappMovieClip::gotoFrame"+frameLabel+"=>"+frameNum);
        this.currentFrame = frameNum;
    },
    play: function() {
        this.playing = true;
    },
    stop: function() {
        this.playing = false;
    },
    destroy: function() { // destructor
        for (var name in this.childMovieClips) {
            this.childMovieClips[name].destroy();
        }
        this.parentMovieClip = null;
        this.rootMovieClip = null;
        this.controlTagsList = null;
        this.actionTagsList = null;
        this.labelMap = null;
        this.canvas = null;
        this.displayList = null;
    }
};

});
