;(function(){

/**
 * @class Flash渲染器。将可视对象以flash方式渲染出来。
 * @augments Renderer
 * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。
 * @module hilo/flash/FlashRenderer
 * @requires hilo/core/Class
 * @requires hilo/core/Hilo
 * @requires hilo/renderer/Renderer
 */
var FlashRenderer = (function(){

var _stageStateList = ["x", "y", "scaleX", "scaleY", "rotation", "visible", "alpha"];
var _stateList = _stageStateList.concat(["pivotX", "pivotY", "width", "height", "depth"]);
var _textStateList = _stateList.concat(["text", "color", "textAlign", "outline", "lineSpacing", "font"]);
var n = 0;

var state = {
    View: _stateList,
    Stage: _stageStateList,
    Graphics: _stateList,
    Text: _textStateList
};

function createFid(target){
    return target.id + (n++);
}

return Hilo.Class.create(/** @lends FlashRenderer.prototype */{
    Extends: Hilo.Renderer,
    constructor: function(properties){
        FlashRenderer.superclass.constructor.call(this, properties);

        this.stage._ADD_TO_FLASH = true;
        this.stage.fid = createFid(this.stage);
        this.stage.flashType = "Stage";

        this.commands = properties.commands || [];
        this.commands.push("create", this.stage.fid, "Stage");
        this.commands.push("stageAddChild", this.stage.fid);
    },

    /**
     * @private
     * @see Renderer#startDraw
     */
    startDraw: function(target){
        if(target == this.stage){
            return true;
        }

        target._lastState = target._lastState || {};
        //create
        if(!target._ADD_TO_FLASH){
            target._ADD_TO_FLASH = true;
            target.fid = createFid(target);

            if(target._drawTextLine){
                target.flashType = "Text";
            }
            else if(target.beginLinearGradientFill){
                target.flashType = "Graphics";
            }
            else if(target == this.stage){
                target.flashType = "Stage";
            }
            else{
                target.flashType = "View";
            }
            this.commands.push("create", target.fid, target.flashType);
        }

        return true;
    },

    /**
     * @private
     * @see Renderer#draw
     */
    draw: function(target){
        if(target == this.stage){
            return;
        }

        target._lastState = target._lastState || {};

        var lastParent = target._lastState.parent;
        var parent = target.parent;

        if(parent){
            if(!lastParent || parent.fid != lastParent.fid){
                this.commands.push("addChild", parent.fid, target.fid, target.depth);
            }
        }
       
        target._lastState.parent = target.parent;

        switch(target.flashType){
            case "Graphics":
                if(target.isDirty && target.flashGraphicsCommands && target.flashGraphicsCommands.length > 0){
                    this.commands.push("graphicsDraw", target.fid, target.flashGraphicsCommands.join(";"));
                    target.isDirty = false;
                }
                break;
            case "Text":
                break;
        }
    },

    /**
     * @private
     * @see Renderer#transform
     */
    transform: function(target){
        var stateList = state[target.flashType];
        var lastState = target._lastState = target._lastState||{};
        
        if(stateList){
            for(var i = 0,l = stateList.length;i < l;i ++){
                var prop = stateList[i];
                var lastValue = lastState[prop];
                var value = target[prop];
                
                lastState[prop] = value;

                if(lastValue != value){
                    this.commands.push("setProp", target.fid, prop, value);
                }
            }

            //画图
            if(target.drawable && target.drawable.image){
                var image = target.drawable.image;
                var rect = target.drawable.rect;

                var lastRect = lastState.rect||[];
                var lastImage = lastState.image||{};

                if(rect && rect.join(",")!= lastRect.join(",")){
                    this.commands.push("setProp", target.fid, "rect", rect.join(","));
                }

                if(image && (image.src != lastImage.src)) {
                    this.commands.push("setImage", target.fid, image.src);
                }

                lastState.rect = rect;
                lastState.image = image;
            }
        }
    },

    /**
     * @private
     * @see Renderer#remove
     */
    remove: function(target){
        var parent = target.parent;
        if(parent){
            this.commands.push("removeChild", target.parent.fid, target.fid);
            if(target._lastState){
                target._lastState.parent = null;
            }
        }
    }
});

})();

/**
 * @class FlashAdaptor
 * @module hilo/flash/FlashAdaptor
 * @requires hilo/core/Hilo
 * @requires hilo/view/Text
 * @requires hilo/view/Graphics
 * @requires hilo/media/WebAudio
 * @requires hilo/media/WebSound
 * @requires hilo/view/Stage
 * @requires hilo/flash/FlashRenderer
*/
var FlashAdaptor = (function(){

var scripts = document.scripts;
var selfScript = scripts[scripts.length - 1];
var scriptDir = selfScript.src.substring(0, selfScript.src.lastIndexOf('/') + 1);
var defaultSwf = scriptDir + 'hilo.swf';

var defaultOption = {
    url: defaultSwf,
    id: "hiloFlash",
    width: "100%",
    height: "100%",
    color: "#ffffff",
    fps: 60
};

var imageCallBacks = {};
var isFlashReady = false;
var flashCommands = []; 

var Adaptor = {
    /**
     * 初始化flash
     * @public
     * @method init
     * @param {Object} option 参数option定义
     *      option.url flash网址
     *      option.fps  flash fps, 默认60
     *      option.forceFlash 强制falsh模式
     *      option.id  flash id,默认 hiloFlash    
     */
    init:function(option){
        option = option || {};
        var that = this;

        if(!Hilo.browser.supportCanvas || option.forceFlash || location.search.indexOf("forceFlash") > -1){
            Hilo.isFlash = true;
            this._addFlashCallback();
            this._flashShim(option);
        }
        else{
            Hilo.View.prototype.release = function(){
                this.removeFromParent();
            };
        }
    },
    setFps:function(fps){
        if(this._fps != fps){
            this._fps = fps;
            flashCommands.push("setFps", fps);
        }
    },
    _flashShim:function(option){
        var that = this;
        option = Hilo.copy(defaultOption, option||{});

        Array.prototype.indexOf = Array.prototype.indexOf||function(a){
            for(var i = 0, l = this.length;i > l;i ++){
                if(this[i] === a){
                    return i;
                }
            }
            return -1;
        };

        Hilo.Stage.prototype._initRenderer = function(properties){
            var canvas = this.canvas;
            if(typeof canvas === 'string') canvas = Hilo.getElement(canvas);

            var container = properties.container;
            if(typeof container === 'string') container = Hilo.getElement(container);
            if(!container) container = document.body;
            
            if(canvas && canvas.parentNode){
                container = container||canvas.parentNode;
                canvas.parentNode.removeChild(canvas);
            }

            this.canvas = container;
            var width = this.width, height = this.height, 
            viewport = this.updateViewport();
            if(!properties.width) width = (viewport && viewport.width) || 320;
            if(!properties.height) height = (viewport && viewport.height) || 480;

            that._insertSwf(Hilo.copy(option, {
                container:container,
                width:width * (this.scaleX||1),
                height:height * (this.scaleY||1)
            }));

            var props = {canvas:container, stage:this, commands:flashCommands};
            this.renderer = new FlashRenderer(props);
        };

        Hilo.Stage.prototype.addTo = function(domElement){
            var swf = this._swf;
            if(swf && swf.parentNode !== domElement){
                domElement.appendChild(swf);
            }
            return this;
        };

        var enableDOMEvent = Hilo.Stage.prototype.enableDOMEvent;
        Hilo.Stage.prototype.enableDOMEvent = function(type, enabled){
            var canvas = this.canvas;
            if(!canvas.addEventListener){
                canvas.addEventListener = function(type, handler){
                    canvas.attachEvent('on' + type, handler);
                };
                canvas.removeEventListener = function(type, handler){
                    canvas.detachEvent('on' + type, handler);
                };
            }

            return enableDOMEvent.call(this, type, enabled);
        };

        var onDOMEvent = Hilo.Stage.prototype._onDOMEvent;
        Hilo.Stage.prototype._onDOMEvent = function(e){
            onDOMEvent.call(this, e || fixEvent());
        };

        Hilo.View.prototype.release = function(){
            this.removeFromParent();
            if(this.fid){
                flashCommands.push("release", this.fid);
            }
        };

        Hilo.Text.prototype.render = function(renderer){
            renderer.draw(this);
        };

        Hilo.Graphics.prototype.render = function(renderer){
            renderer.draw(this);
        };

        var graphicsFuncs = [
            "lineStyle", "beginFill", "endFill",
            "beginBitmapFill", "beginPath", "closePath", "moveTo", "lineTo", "quadraticCurveTo", "bezierCurveTo",
            "drawRect", "drawRoundRectComplex", "drawRoundRect", "drawCircle", "drawEllipse", "cache", "uncache", "clear"
        ];

        //flashGraphicsCommands  command由";"分割 参数由","分割 参数中数组由":"分割
        for(var i = 0;i < graphicsFuncs.length;i ++){
            var funcName = graphicsFuncs[i];
            Hilo.Graphics.prototype[funcName] = function(funcName){
                return function(){
                    var args = Array.prototype.slice.call(arguments);
                    var arr = [funcName].concat(args).join(",");

                    this.flashGraphicsCommands = this.flashGraphicsCommands||[];
                    this.flashGraphicsCommands.push(arr);
                    this.isDirty = true;
                    return this;
                }
            }(funcName);
        }

        Hilo.Graphics.prototype.beginRadialGradientFill = function(x0, y0, r0, x1, y1, r1, colors, ratios){
            var cmd = ["beginRadialGradientFill", x0, y0, r0, x1, y1, r1, colors.join(":"), ratios.join(":")].join(",");
            this.flashGraphicsCommands = this.flashGraphicsCommands||[];
            this.flashGraphicsCommands.push(cmd);
            this.isDirty = true;
            return this;
        };

        Hilo.Graphics.prototype.beginLinearGradientFill = function(x0, y0, x1, y1, colors, ratios){
            var cmd = ["beginLinearGradientFill", x0, y0, x1, y1, colors.join(":"), ratios.join(":")].join(",");
            this.flashGraphicsCommands = this.flashGraphicsCommands||[];
            this.flashGraphicsCommands.push(cmd);
            this.isDirty = true;
            return this;
        };

        Hilo.Graphics.prototype.drawSVGPath = function(pathData){
            var me = this, addAction = me._addAction,
                path = pathData.split(/,| (?=[a-zA-Z])/);
            
            me.beginPath();
            for(var i = 0, len = path.length; i < len; i++){
                var str = path[i], cmd = str.charAt(0).toUpperCase(), p = str.substring(1).split(/,| /);
                if(p[0].length == 0) p.shift();

                switch(cmd){
                    case 'M':
                        me.moveTo(p[0], p[1]);
                        break;
                    case 'L':
                        me.lineTo(p[0], p[1]);
                        break;
                    case 'C':
                        me.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]);
                        break;
                    case 'Z':
                        me.closePath();
                        break;
                }
            }
            return me;
        };

        Hilo.WebSound.removeAudio = function(source){
            var src = typeof source === 'string' ? source : source.src;
            var audio = this._audios[src];
            if(audio){
                audio.stop();
                audio.off();
                audio.release();
                this._audios[src] = null;
                delete this._audios[src];
            }
        };

        Hilo.WebAudio.isSupported = true;
        Hilo.WebAudio.enabled = true;
        Hilo.WebAudio.enable = function(){};

        Hilo.WebAudio.prototype._init = function(){
            this.fid = Hilo.getUid("audio");
            flashCommands.push("audio", "create", this.fid, this.src);
            if(this.autoPlay){
                this.play();
            }
        };

        Hilo.WebAudio.prototype.load = function(){
            flashCommands.push("audio", "load", this.fid);
            return this;
        };

        Hilo.WebAudio.prototype.play = function(){
            flashCommands.push("audio", "play", this.fid, this.loop?1:0);
            return this;
        };

        Hilo.WebAudio.prototype.pause = function(){
            flashCommands.push("audio", "pause", this.fid);
            return this;
        };

        Hilo.WebAudio.prototype.resume = function(){
            flashCommands.push("audio", "resume", this.fid);
            return this;
        };

        Hilo.WebAudio.prototype.stop = function(){
            flashCommands.push("audio", "stop", this.fid);
            return this;
        };
        
        Hilo.WebAudio.prototype.setVolume = function(volume){
            flashCommands.push("audio", "setVolume", this.fid, volume);
            return this;
        };

        Hilo.WebAudio.prototype.setMute = function(muted){
            flashCommands.push("audio", "setMute", this.fid, muted?1:0);
            return this;
        };

        Hilo.WebAudio.prototype.release = function(){
            flashCommands.push("audio", "release", this.fid);
            return this;
        };
    },
    _insertSwf:function(option){
        var that = this;
        var swf;
        var src = option.url;
        var id = option.id;
        var color = option.color||null;
        var fps = option.fps;
        var container = option.container;
        var width = option.width;
        var height = option.height;
        
        this.setFps(fps);

        if(window.attachEvent){
            var hasHTML = container.innerHTML;
            container.innerHTML = 
            '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"' +
            ' codebase="' + location.protocol + '//fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0">' +
            '<param name="allowScriptAccess" value="always">' +
            '<param name="flashvars" value="id=' + id + '">' +
            '<param name="wmode" value="transparent">' +
            '<param name="bgcolor" value="' + color + '">' +
            '</object>' + hasHTML;
            var swf = container.getElementsByTagName("object")[0];
            swf["movie"] = src;
        }
        else{
            swf = document.createElement("embed");
            swf.setAttribute("src",src);
            swf.setAttribute("type","application/x-shockwave-flash");
            swf.setAttribute("allowScriptAccess","always");
            swf.setAttribute("allowFullScreen","true");
            swf.setAttribute("bgcolor",color);
            swf.setAttribute("pluginspage","http://www.adobe.com/go/getflashplayer_cn");
            swf.setAttribute("wmode", "transparent");
            swf.setAttribute("FlashVars", "debug=0");
            container.appendChild(swf);
        }
        swf.name = id;
        swf.width = width;
        swf.height = height;
        swf.id = id;
            
        this._swf = swf;
        setInterval(function(){
            that.tick();
        }, 1000/fps)
        return swf;
    },
    tick:function(){
        if(isFlashReady && flashCommands.length > 0){
            this._swf.CallFunction(
                '<invoke name="executeCommand" returntype="javascript"><arguments><string>'
                + flashCommands.join("√") + '</string></arguments></invoke>'
            );
            // console.log("executeCommand", flashCommands.join(","));
            flashCommands.length = 0;
        }
    },
    _addFlashCallback:function(){
        /*
         * 加载flash图片
         * @method loadFlashImage
        */
        Hilo.loadFlashImage = function(src, successHandler, errorHandler){
            imageCallBacks[src] = imageCallBacks[src]||[];
            imageCallBacks[src].push([successHandler, errorHandler||successHandler]);
            flashCommands.push("loadImage", src);
        };

        /*
         *flash 可以调接口时回调函数
        */
        Hilo.unlock = function(){
            isFlashReady = true;
        };

        /*
         * falsh图片加载完回调函数
         * @argument src:图片地址
         * @argument errorCode: 0:图片加载成功, 1:图片加载失败
         * @argument width:图片宽
         * argument height:图片高
        */
        Hilo.imageCallBack = function(src, errorCode, width, height){
            // console.log("imageCallBack", src, errorCode);
            var arr = imageCallBacks[src];
            if(arr && arr.length > 0){
                for(var i = 0, l = arr.length;i < l;i ++){
                    arr[i][errorCode]({
                        target:{
                            src:src, 
                            width:width, 
                            height:height,
                            isFlash:true
                        },
                        errorCode:errorCode
                    });
                }
                arr.length = 0;
            }
        }
    }
};

function fixEvent(){
    var event = window.event; 
    var e = {
        rawEvent:event,
        type:event.type,
        target:event.srcElememt,
        preventDefault:function(){
            event.returnValue = false;
        },
        stopPropagation:function(){
            event.cancelBubble = true;
        }
    };
    
    if(event.type.indexOf("mouse") != -1){
        e.clientX = event.clientX;
        e.clientY = event.clientY;
        if(event.type == "mouseover") 
            e.relatedTarget = event.fromElement; 
        else if(event.type == "mouseout") 
            e.relatedTarget = event.toElement; 
    }
    else if(event.type.indexOf("key") != -1){
        e.charCode = e.keyCode = event.keyCode; 
    }
    return e; 
}

if(selfScript.getAttribute('data-auto') === 'true') Adaptor.init();
return Hilo.FlashAdaptor = Adaptor;

})();

})();