// Copyright 2007 Google Inc. All Rights Reserved.

if (typeof Flash == "undefined") {
  var Flash = new Object();
}

Flash.defaultVersion = "7,0,14,0";

Flash.Builder = {

  writeFlash: function(swf, width, height, initializer) {
    this._createFlashTag(swf, width, height, initializer).write();
  },

  writeFlash: function(elementId, swf, width, height, initializer) {
    this._createFlashTag(swf, width, height, initializer).writeToDom(elementId);
  },

  writeJsIntegratedFlash: function(swf, width, height, initializer) {
    var proxy = this.createJsIntegratedFlash(swf, width, height, initializer);
    proxy.write();
    return proxy;
  },

  writeJsIntegratedFlashToDom: function(elementId, swf, width, height, initializer) {
    var proxy = this.createJsIntegratedFlash(swf, width, height, initializer);
    proxy.writeToDom(elementId);
    return proxy;
  },  

  createJsIntegratedFlash: function(swf, width, height, initializer) {
    var tag = this._createFlashTag(swf, width, height, initializer); 
    return new Flash.Proxy(tag);
  },
  
  _createFlashTag: function(swf, width, height, initializer) {
    var tag = new Flash.Tag(swf, width, height);
    if (initializer instanceof Function) {
      initializer.call(this, tag);
    }
    return tag;
  }
}

Flash.Proxy = function(flashTag) {
  this.flashTag = flashTag;
  this.serializer = new Flash.Serializer(false);
  var id = "flashProxy" + (Flash.Proxy._proxyIdCounter++);
  this.flashTag.setId(id);
  this.flashTag.setFlashVar("JavascriptProxyId", id);

  if (navigator.appName.indexOf ("Microsoft") != -1) {
    this.flashTag.setFlashVar("JavascriptProxyQueueInterval", 100);
  }
}
Flash.Proxy._proxyIdCounter = 0;
Flash.Proxy.prototype = {
  
  getId: function() {
    return this.flashTag.getId();
  },

  write: function() {
    this.flashTag.write();
  },

  writeToDom: function(elementId) {
    this.flashTag.writeToDom(elementId);
  },

  sendMessage: function(__arguments__) {
    
    var functionName = arguments[0];
    var functionArgs = [];
    for (var i = 1; i < arguments.length; i++) {
      functionArgs.push(arguments[i]);
    }
    
    var serializedData = this.serializer.serializeAll([functionName, functionArgs]);
    this.flashTag.getSwf().SetVariable("__JavascriptProxy" + this.getId(), serializedData);
  }
};

Flash.Tag = function(swf, width, height, version) {
  this.swf = swf;
  this.width = width;
  this.height = height;
  this.version = version || Flash.defaultVersion;
  this.id = null;
  this.paramsHash = { bgcolor: "#FFFFFF", quality: "high" };
  this.flashVarsHash = {};
}
Flash.Tag.prototype = {

  getId: function() {
    return this.id;
  },

  setId: function(id) {
    this.id = id;
  },

  getSwf: function() {
    return document.getElementById(this.getId());
  },

  setParam: function(name, value) {
    this.paramsHash[name] = value;
  },

  setFlashVar: function(name, value) {
    this.flashVarsHash[name] = value;
  },
  
  toString: function() {
    if (navigator.appName.indexOf ("Microsoft") != -1) {
      return this._toStringForExplorer();
    } else {
      return this._toStringForStandard();
    }
  },
  
  write: function() {
    document.write(this.toString());
  },

  writeToDom: function(elementId) {
    var element = document.getElementById(elementId)
    if (element) {
      element.innerHTML = this.toString();
    }
  },
  
  _toStringForExplorer: function() {
    var str = "<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" ";
    str += "codebase=\"" + location.protocol + "//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=" + this.version + "\" ";
    str += "width=\"" + this.width + "\" ";
    str += "height=\"" + this.height + "\"";
    if (this.id) {
      str += "id=\"" + this.id + "\"";
    }
    str += ">";
    str += "<param name=\"movie\" value=\"" + this.swf + "\" />";
    str += "<param name=\"flashvars\" value=\"" + this._flashVarsString() + "\" />";
    for (var key in this.paramsHash) {
      str += "<param name=\"" + key + "\" value=\"" + this.paramsHash[key] + "\" />";
    }
    str += "</object>";
    return str;
  },
  _toStringForStandard: function() {
    var str = "<embed src=\"" + this.swf + "\" width=\"" + this.width + "\" height=\"" + this.height + "\" salign=\"tl\" scale=\"noScale\" quality=\"high\" ";
    str += "type=\"application/x-shockwave-flash\" ";
    str += "pluginspage=\"http://www.macromedia.com/go/getflashplayer\" ";
    str += "flashvars=\"" + this._flashVarsString() + "\" ";
    if (this.id) {
      str += "id=\"" + this.id + "\"";
    }
    for (var key in this.paramsHash) {
      str += key + "=\"" + this.paramsHash[key] + "\" ";
    }
    str += "</embed>";
    return str;
  },
  _flashVarsString: function() {
    var vars = [];
    for (var key in this.flashVarsHash) {
      vars.push(encodeURIComponent(key) + "=" + encodeURIComponent(this.flashVarsHash[key]));
    }
    return vars.join("&");
  }
};

Flash.Receiver = {

  register: function(flashProxy, receiver) {
    this.instances[flashProxy.getId()] = receiver;
  },

  execute: function(id, functionName, functionArgs) {

    functionArgs = (functionArgs instanceof Array) ? functionArgs : []
    var instance = Flash.Receiver.instances[id];
    if (instance) {
      var func = instance[functionName];
      if (func) {
        func.apply(instance, functionArgs);
      } else {
        alert("Flash.Receiver.NoMethodError: " + functionName + ", for id: " + id + " (received by: " + instance + ")");
      }
    } else {
      var func = window[functionName];
      if (func) {
        func.apply(window, functionArgs);
      } else {
        alert("Flash.Receiver.NoMethodError: " + functionName);
      }
    }
  },

  instances: {}
}

Flash.Serializer = function(useCdata) {
  this.useCdata = useCdata;
}
Flash.Serializer.prototype = {
  
  serialize: function(value) {
    return this.Builder.serialize(value);
  },

  serializeAll: function(values) {
    var str = "";
    for (var i = 0; i < values.length; i++) {
      str += this.serialize(values[i]);
    }
    return str;
  },
  
  Builder: {
    
    serialize: function(value, name) {
      var type = typeof value;
      if (type == "undefined") {
        return this.encode("undef", value, name);
      } else if (value == null) {
        return this.encode("null", value, name);
      } else {
        switch(type) {
          case "string":  return this.encode("s", value, name);
          case "number":  return this.encode("n", value, name);
          case "boolean": return this.encode("b", value, name);
          case "object":
            for (var i = 0; i < Flash.Serializers.length; i++) {
              var serializer = Flash.Serializers[i];
              if (serializer.serializes(value)) {
                return serializer.serialize(this, value, name);
              }
            }
        }
      }
      alert("Flash.Serializer: unhandled type of object: " + typeof(value));
    },
    
    encode: function(type, value, name) {
      if (typeof(value) == "string") {
        value = this._escapeXmlString(value);
      }
      if (value != undefined && name != undefined ) {
        return "<" + type + " n=\"" + name + "\" v=\"" + encodeURIComponent(value) + "\"/>";
      } else if (value != undefined) {
        return "<" + type + " v=\"" + encodeURIComponent(value) + "\"/>";
      } else {
        return "<" + type + "/>";
      }
    },
  
    wrap: function(type, contentBuilder) {
      var content = contentBuilder();
      if (content.length > 0) {
        return "<" + type + ">" + content + "</" + type + ">";
      } else {
        return "<" + type + "/>";
      }
    },
  
    _escapeXmlString: function(string) {
      if (this.useCdata) {
        return "<![CDATA[" + string +"]]>";
      } else {
        return string.replace(/&/g, "&amp;").replace(/</g, "&lt;");
      }
    }
  }
    
};

Flash.Serializers = [

  { serializes: function(value) {
      return (value instanceof Date);
    },
    serialize: function(builder, date) {
      return builder.encode("d", date.getTime());
    } 
  },

  { serializes: function(value) {
      return (value instanceof Array);
    },
    serialize: function(builder, array) {
      return builder.wrap("a", function() {
        var str = "";
        for (var i = 0; i < array.length; i++) {
          str += builder.serialize(array[i]);
        }
        return str;
      });
    }
  },

  { serializes: function(value) {
      return true;
    },
    serialize: function(builder, object) {
      return builder.wrap("o", function() {
        var str = "";
        for (var key in object) {
          str += builder.serialize(object[key], key);
        }
        return str;
      });
    }  
  }
];

Flash.Serializers.add = function(serializer) {
  this.unshift(serializer);
}
