var SwfInstance = Class.create({
  id: null,
  swf: null,
  initialized: false,
  loaded: false,
  built: false,
  shown: false,
  flashVars: {},
  params: {allowScriptAccess: 'always'},
  attrs: {allowscriptaccess: 'always', allowfullscreen: 'true'},
  options: {},

  initialize: function(url, targetId, width, height, minVersion, flashVars, params, attrs, options) {
    if (!url || !targetId || !minVersion || !width || !height) return;
    this.flashVars = flashVars || {};
    this.params = params || {};
    this.attrs = attrs || {};
    this.options = options || {};
    this.id = this.attrs['id'] = this.attrs['name'] = this.flashVars['id'] = targetId;
    this.url = url;

    Object.extend(this.attrs, {data: url, width: width, height: height});
    this.params['allowScriptAccess'] = 'always';
    this.params['flashvars'] = $H(this.flashVars).map(function(flashVar) {
      return flashVar[0] + '=' + (flashVar[1] === null ? '' : flashVar[1]);
    }).join('&');

    if (!SwfInstance.hasPlayerVersion(minVersion)) return; //!! should do express install here
    if (!document._loaded) Event.observe(document, 'dom:loaded', this._embed.bind(this));
    else this._embed();

    this.initialized = true;
    this.onInitialized();
  },

  setupObservers: function() {
    // default events
    Event.observe(this.swf, 'flash:onLoaded', function(event) {
      this.loaded = true;
      this.onLoaded(event);
    }.bind(this));
    Event.observe(this.swf, 'flash:onBuilt', function(event) {
      this.built = true;
      this.onBuilt(event);
    }.bind(this));
    Event.observe(this.swf, 'flash:onShown', function(event) {
      this.shown = true;
      this.onShown(event);
    }.bind(this));
    Event.observe(this.swf, 'flash:onHidden', function(event) {
      this.hidden = true;
      this.onHidden(event);
    }.bind(this));

    // default actions
    Event.observe(this.swf, 'flash:show', this.show.bind(this));
    Event.observe(this.swf, 'flash:hide', this.hide.bind(this));
    Event.observe(this.swf, 'flash:resize', function(event) {
      var dimensions = event.memo;
      this.resize(dimensions.width, dimensions.height);
    }.bind(this));
  },

  // default events
  onInitialized: function() { },
  onLoaded: function(event) { },
  onBuilt: function(event) { this.show(); },
  onShown: function(event) { },
  onHidden: function(event) { },

  // default actions
  resize: function(width, height) {
    $(this.id).setStyle({width: width + 'px', height: height + 'px'});
  },

  show: function() {
    try {
      this.swf.show();
    } catch(e) {}
  },

  hide: function() {
    try {
      this.swf.hide();
    } catch(e) {}
  },

  // private methods
  _embed: function() {
    document._loaded = true;

    var element = $(this.id);
    element.setStyle('visibility:hidden');
    if (Prototype.Browser.IE) {
      var attributes = $H(this.attrs).map(function(attr) {
        if (attr[0] == 'data') { this.params['movie'] = attr[1]; return ''; }
        if (attr[0] == 'allowFullScreen') { this.params['allowFullScreen'] = attr[1]; return ''; }
        return (attr[0].toLowerCase() != 'classid') ? attr[0] + '="' + attr[1] + '"' : '';
      }.bind(this)).join(' ');
      var parameters = $H(this.params).map(function(param) {
        return '<param name="' + param[0] + '" value="' + param[1] + '"/>';
      }).join('');
      element.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ' + attributes + '>' + parameters + '</object>';
      this.swf = $(this.id);
      this.swfParent = element.parentNode;
    } else if (window.SwfInstance_webKitVersion && window.SwfInstance_webKitVersion < 312) {
      Object.extend(this.attrs, this.params);
      var embed = new Element('embed', this.attrs);
      element.parentNode.replaceChild(embed, element);
      this.swf = embed;
    } else {
      this.attrs['type'] = 'application/x-shockwave-flash';
      var object = new Element('object', this.attrs);
      $H(this.params).each(function(param) {
        object.appendChild(new Element('param', {name: param[0], value: param[1]}));
      });
      element.parentNode.replaceChild(object, element);
      this.swf = object;
    }
    element.setStyle('visibility:visible');

    this.setupObservers();
  }
});

/**
 * SwfInstance static methods
 */
Object.extend(SwfInstance, {
  debugOutput: true,

  fireEvent: function(id, eventName, object) {
    SwfInstance.trace('SwfInstance.fireEvent', arguments);
    if (id == 'mp3player' || id == 'mpthreeplayer') id = false;
    try {
      if (id) document[id].fire(eventName, object);
      else document.fire(eventName, object);
    } catch(e) {}
  },

  trace: function() {
    if (!SwfInstance.debugOutput) return;
    arguments[0] = arguments[0] + ':';
    if (typeof(console) != 'undefined') {
      if (console.firebug) console.debug(arguments);
      else if (console.info) console.info(arguments[0], arguments[1]);
      else if (console.log) console.log(arguments[0], arguments[1].join(','));
    }
  },

  debug: function(message) {
    if (!SwfInstance.debugOutput) return;
    var debugWindow = $('debug');
    if (debugWindow) debugWindow.value = debugWindow.value + message + '\n----------------------------------------------\n';
  },

  hasPlayerVersion: function(version) {
    if (!window.SwfInstance_installedPlayerVersion) SwfInstance._detectPlayerVersion();

    version = version.match(/(\d+)/g).map(function(v) { return parseInt(v) });
    var installed = window.SwfInstance_installedPlayerVersion;
    return (
      (installed[0] > version[0]) ||
      (installed[0] == version[0] && installed[1] > (version[1] || 0)) ||
      (installed[0] == version[0] && installed[1] == (version[1] || 0) && installed[2] >= (version[2] || 0))
    ) ? true : false;
  },

  _detectPlayerVersion: function() {
    if (window.SwfInstance_installedPlayerVersion) return;

    var installedVersion = [0, 0, 0];
    var detected = null;

    if (typeof(navigator.plugins) != 'undefined' && typeof(navigator.plugins['Shockwave Flash']) == 'object') {
      detected = navigator.plugins['Shockwave Flash'].description;
      if (detected && !(typeof(navigator.mimeTypes) != 'undefined' && navigator.mimeTypes['application/x-shockwave-flash'] && !navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin)) {
        detected = detected.replace(/^.*\s+(\S+\s+\S+$)/, '$1');
        installedVersion[0] = parseInt(detected.replace(/^(.*)\..*$/, '$1'), 10);
        installedVersion[1] = parseInt(detected.replace(/^.*\.(.*)\s.*$/, '$1'), 10);
        installedVersion[2] = /r/.test(detected) ? parseInt(detected.replace(/^.*r(.*)$/, '$1'), 10) : 0;
      }
    } else if (typeof(window.ActiveXObject) != 'undefined') {
      var activeX = null;
      var fp6Crash = false;
      try {
        activeX = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.7');
      } catch(e) {
        try {
          activeX = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6');
          installedVersion = [6, 0, 21];
          activeX.AllowScriptAccess = 'always';
        } catch(e) { if (installedVersion[0] == 6) fp6Crash = true; }
        if (!fp6Crash) {
          try { activeX = new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); } catch(e) {}
        }
      }
      if (activeX && !fp6Crash) {
        try {
          detected = activeX.GetVariable('$version');
          if (detected) {
            detected = detected.split(' ')[1].split(',');
            installedVersion = [parseInt(detected[0], 10), parseInt(detected[1], 10), parseInt(detected[2], 10)];
          }
        } catch(e) {}
      }
    }

    var userAgent = navigator.userAgent.toLowerCase();
    window.SwfInstance_webKitVersion = /webkit/.test(userAgent) ? parseFloat(userAgent.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, '$1')) : false;
    window.SwfInstance_installedPlayerVersion = installedVersion;
  }
});

Event.observe(document, 'dom:loaded', function() { document.loaded = true; });
window.trace = SwfInstance.trace;
