// Create the namespace
if( !window.com ) {
	/**
	 * @ignore
	 **/
	window.com = new Object();
}
if( !com.jitjat ) {
	/**
	 * @ignore
	 **/
	 com.jitjat = new Object();
}
if( !com.jitjat.plugins ) {
	/**
	 * @ignore
	 **/
	com.jitjat.plugins = new Object();
}


/**
 * Extensible Plugin Detection Class
 * @constructor
 * @version 1.0 April 14, 2004
 * @author Gregory Ramsperger <gregory-at-jitjat.com>
 **/
com.jitjat.plugins.PluginDetector = function() {
	// due to an IE/Win bug, this need to be reset here
	// if you don't do this, each implementation adds to the list
	if( this.useWindowsControls ) this.activeXControls = [];
}

/**
 * <em>Abstract</em>This method should be implemented by subclasses and should extract
 * version information from the plugin.description or plugin.name
 * properties.
 *
 * @param plugin <dfn>plugin</dfn> the plugin instance (as in navigator.plugins[0])
 * @return the version number found or <code>null</code> if no version was retrieved.
 * @type Number
 * @abstract
 */
com.jitjat.plugins.PluginDetector.prototype.findVersion = function( plugin ) {}

/**
 * <em>Abstract</em> This method should be implemented by subclasses and should extract
 * version information from the ActiveX control created.
 * <p><strong>Set this in the implementation class</strong></p>
 *
 * @private
 * @param activeXObj <dfn>ActiveXObject</dfn> the ActiveX instance
 * @type Number
 * @return the version number found or <code>null</code> if no version was retrieved.
 */
com.jitjat.plugins.PluginDetector.prototype.findVersionActiveX = function( activeXObj ) {}

/**
 * An array of mime types to use when searching for the proper plugin. (Ignored for IE/Win)
 * <p><strong>Set this in the implementation class</strong></p>
 * @type Array
 */
com.jitjat.plugins.PluginDetector.prototype.mimeTypes = [];

/**
 * An array of plugin names/descriptions to use when searching for the proper plugin. (Ignored for IE/Win)
 * <p><strong>Set this in the implementation class</strong></p>
 * @type Array
 */
com.jitjat.plugins.PluginDetector.prototype.pluginNames = [];

/**
 * An array of file name suffixes to use when searching for the proper plugin. (Ignored for IE/Win)
 * <p><strong>Set this in the implementation class</strong></p>
 * @type Array
 */
com.jitjat.plugins.PluginDetector.prototype.suffixes = [];

/**
 * Adds an ActiveX control id to the list of controls to check
 * 
 * @param name <dfn>String</dfn> the name of the control to instantiate
 * @param pluginVersion <dfn>Number</dfn> the version of the plugin implied by the existance of this control
 * @type Void
 */
com.jitjat.plugins.PluginDetector.prototype.addActiveXControl = function( name, pluginVersion ) {
	if( this.useWindowsControls ) {
		this.activeXControls[this.activeXControls.length] = {name:name, version:pluginVersion, iterative:false};
	}
}

/**
 * Adds an ActiveX control id pattern to the list of controls to check
 *
 * <p>Example: Flash</p>
 * <blockquote><code>pluginDetector.addActiveXControlPattern( "ShockwaveFlash.ShockwaveFlash.", "" );</code></blockquote>
 * <blockquote>When detect() is called, if maxVersionCheck is set to 10, this will try to instantiate
 *   the "ShockwaveFlash.ShockwaveFlash.10" control. When this fails, it will try 
 *   "ShockwaveFlash.ShockwaveFlash.9" and so on. When it gets to 
 *   "ShockwaveFlash.ShockwaveFlash.7" (the current version), it will succeed and return 7.</blockquote>
 *
 * @param namePrefix <dfn>String</dfn> the prefix of the file type supported by the plugin.
 * @param nameSuffix <dfn>String</dfn> the suffix of the file type supported by the plugin.
 * @type Void
 */
com.jitjat.plugins.PluginDetector.prototype.addActiveXControlPattern = function( namePrefix, nameSuffix ) {
	if( this.useWindowsControls ) {
		this.activeXControls[this.activeXControls.length] = { prefix:namePrefix, suffix:nameSuffix, iterative:true };
	}
}

/**
 * Use addActiveXControl() and addActiveXControl() to add controls to check.
 * <p>Stores the controls for later checking</p>
 *
 * @private
 * @type Array
 */
com.jitjat.plugins.PluginDetector.prototype.activeXControls = [];

/**
 * The plugin vendor.
 * <p>Media types may be supported by more than one plugin. Use this property to differentiate.</p>
 *
 * @type String
 */
com.jitjat.plugins.PluginDetector.prototype.vendor = null;



/**
 * The detection method.
 *
 * @return <code>true</code> if any version is found
 * @type Boolean
 */
com.jitjat.plugins.PluginDetector.prototype.detect = function() {

	if( this.useWindowsControls ) {
		for( var i=0; i<this.activeXControls.length; i++ ) {
			if( this.activeXControls[i].iterative ) {
				this.versionFound = Math.max( this.versionFound, this.iterativeActiveXDetect( this.activeXControls[i].prefix, this.activeXControls[i].suffix ) );
			} else {
				try {
					var ctl = new ActiveXObject( this.activeXControls[i].name );
					var v = this.findVersionActiveX( ctl );
					if( v != null ) this.versionFound = Math.max( this.versionFound, v );
					else this.versionFound = Math.max( this.versionFound, this.activeXControls[i].version );
				} catch( e ) {
				}
			}
		}

	} else if(navigator.plugins) {
		// continue to the next only if nothing was found
		if( !this.versionFromMimeTypes( this.mimeTypes ) )
			if( !this.versionFromSuffix( this.suffixes ) )
				this.versionFromNames( this.pluginNames );
	}

	return ( this.versionFound > 0 );
}

/**
 * If on MSIE/Windows, plugins must be detected by instantiating a control
 * @private
 * @type Boolean
 */
com.jitjat.plugins.PluginDetector.prototype.useWindowsControls = (navigator.appVersion.indexOf("MSIE") != -1 && navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; // true if we're on windows


/**
 * The maximum version to check for existence. (Only used in MSIE/Windows.)
 * Setting this to a higher number increases the efficiency of the check on MSIE/Windows
 *
 * @type Number
 */
com.jitjat.plugins.PluginDetector.prototype.minVersionCheck = 1;

/**
 * The maximum version to check for existence. (Only used in MSIE/Windows.)
 * This should be set above the current version of the format for support of future versions without updates.
 *
 * @type Number
 */
com.jitjat.plugins.PluginDetector.prototype.maxVersionCheck = 10;

/**
 * The version of the plugin detected. Use getVersion() to retrieve this value.
 *
 * @private
 * @type Number
 * @see #getVersion
 */
com.jitjat.plugins.PluginDetector.prototype.versionFound = -1;


/**
 * Check to see that the detected version is equal to or greater than the passed number.
 *
 * @param version <dfn>Number</dfn> the number to test against.
 * @return <code>true</code> if the version is greater than the tested value. <code>false</code> if it is less than or the plugin was not found.
 * @type Boolean
 */
com.jitjat.plugins.PluginDetector.prototype.atLeastVersion = function( version ) {
	if( !this.detected ) return false;
	if( typeof version != "number" ) version = parseFloat( version );
	if( isNaN( version ) ) return null;

	return ( this.versionFound >= version );
}

/**
 * Get the detected plugin version
 * @return <dfn>Number</dfn> the plugin version detected
 */
com.jitjat.plugins.PluginDetector.prototype.getVersion = function() {
	return this.versionFound;
}

/**
 * Determine that any version of the plugin (within the tested range) is present
 * @return <code>true</code> if the plugin was detected
 * @type Boolean
 */
com.jitjat.plugins.PluginDetector.prototype.detected = function() {
	return this.versionFound > 0;
}


/**
 * Find the plugin associated with the given mime type.
 *
 * @param type <dfn>Array</dfn> or <dfn>String</dfn> the mime type of the associated plugin. For multiple types, pass more than one argument
 */
com.jitjat.plugins.PluginDetector.prototype.versionFromMimeTypes = function( type ) {
	if( !navigator.mimeTypes ) return;
	if( typeof type == "string" ) type = [type];

	var foundSomething = false;

	for( var i=0; i<type.length; i++ ) {
		if( navigator.mimeTypes[ type[i] ] && navigator.mimeTypes[ type[i] ].enabledPlugin ) {
			var v = this.findVersion( navigator.mimeTypes[ type[i] ].enabledPlugin );
			if( v!=null && !isNaN( v ) ) {
				this.versionFound = Math.max( this.versionFound, v );
				foundSomething = true;
			}
		}
	}

	return foundSomething;
}

/**
 * Find all plugins with name or description properties containing the given string.
 *
 * @param name <dfn>Array</dfn> or <dfn>String</dfn> the string contained within the name or descriptoin of the desired plugin. For multiple names, pass more than one argument
 */
com.jitjat.plugins.PluginDetector.prototype.versionFromNames = function( names ) {
	if( typeof names == "string" ) names = [names];

	var foundSomething = false;

	for( var i=0; i<navigator.plugins.length; i++ ) {
		var plugin = navigator.plugins[i];

		for( var j=0; j<names.length; j++ ) {
			names[j] = names[j].toLowerCase();

			if( plugin.name.toLowerCase().indexOf( names[j] ) != -1 || plugin.description.toLowerCase().indexOf( names[j] ) != -1 ) {
				var v = this.findVersion( plugin );
				if( v!=null && !isNaN( v ) ) {
					this.versionFound = Math.max( this.versionFound, v );
					foundSomething = true;
				}
			}
		}
	}

	return foundSomething;
}

/**
 * Find all plugins supporting the given suffix.
 *
 * @private
 * @param name <dfn>Array</dfn> or <dfn>String</dfn> the suffix of the file type supported by the plugin. For multiple suffixes, pass more than one argument
 */
com.jitjat.plugins.PluginDetector.prototype.versionFromSuffix = function( suffix ) {
	if( typeof suffix == "string" ) suffix = [suffix];

	var foundSomething = false;

	for( var i=0; i<navigator.mimeTypes.length; i++ ) {
		for( var j=0; j<suffix.length; j++ ) {
			if( navigator.mimeTypes[i].suffixes.indexOf( suffix[j].toLowerCase() ) != -1 ) {
				if( navigator.mimeTypes[i].enabledPlugin ) {
					var v = this.findVersion( navigator.mimeTypes[i].enabledPlugin );
					if( v!=null && !isNaN( v ) ) {
						this.versionFound = Math.max( this.versionFound, v );
						foundSomething = true;
					}
				}
			}
		}
	}

	return foundSomething;
}



/**
 * Iteratively instantiate ActiveX controls and return the highest version found. This method depends on values set for maxVersionCheck and minVersionCheck.
 *
 * <p>Example: Flash</p>
 * <blockquote><code>pluginDetector.addActiveXControlPattern( "ShockwaveFlash.ShockwaveFlash.", "" );</code></blockquote>
 * <blockquote>When detect() is called, if maxVersionCheck is set to 10, this will try to instantiate
 *   the "ShockwaveFlash.ShockwaveFlash.10" control. When this fails, it will try 
 *   "ShockwaveFlash.ShockwaveFlash.9" and so on. When it gets to 
 *   "ShockwaveFlash.ShockwaveFlash.7" (the current version), it will succeed and return 7.</blockquote>
 *
 * @private
 * @param namePrefix <dfn>String</dfn> the prefix of the file type supported by the plugin.
 * @param nameSuffix <dfn>String</dfn> the suffix of the file type supported by the plugin.
 * @return the version number found
 * @type Number
 */
com.jitjat.plugins.PluginDetector.prototype.iterativeActiveXDetect = function( controlPrefix, controlSuffix ) {
	if( controlPrefix == null ) controlPrefix = "";
	if( controlSuffix == null ) controlSuffix = "";

	for( var i=this.maxVersionCheck; i>=this.minVersionCheck; i-- ) {
		try {
			var obj = new ActiveXObject( controlPrefix + i + controlSuffix );
			return i;
		} catch( e ) {
		}
	}
	return -1;
}


// test variable. Implementation files should check for this before subclassing com.jitjat.plugins.PluginDetector
var PluginDetectorLoaded = true;

/**
 * Set to true when PluginDetector is loaded.
 * <code>
 * </code>
 *
 * @type Boolean
 **/
com.jitjat.plugins.PluginDetector.PluginDetectorLoaded = true;