(function() {
var 
// Will speed up references to window, and allows munging its name.
wnd = this,
// Will speed up references to undefined, and allows munging its name.
UNDEF;

var 
// Global entry
$au = wnd.$au = {
    imageUploaderFlash: function(obj) {
        ///	<summary>
        ///		1: imageUploaderFlash(id) - Get created uploader.
        ///		2: imageUploaderFlash(obj) - Create new uploader.            
        ///	</summary>
        ///	<param name="obj" type="Object">
        ///		1: obj - Init object for new uploader.
        ///		2: id - An id of existing uploader.
        ///	</param>
        ///	<returns type="$au.imageUploaderFlash" />
        if (typeof obj === 'string') {
            return ObjectManager.getObjectFromCache(obj);
        } else {
            return ObjectManager.create("imageUploaderFlash", obj);
        }
    }
},

browser = $au.browser = new (function() {
    var a = navigator.userAgent.toLowerCase();
    this.isOpera = (a.indexOf("opera") > -1);
    this.isKonq = (a.indexOf("konqueror") > -1);
    this.isChrome = (a.indexOf("chrome") > -1);
    this.isSafari = (a.indexOf("safari") > -1) && !this.isChrome;
    this.isKhtml = this.isSafari || this.isKonq || this.isChrome;
    this.isIE = (a.indexOf("msie") != -1) && !this.isOpera;
    this.isIE6XPSP2 = this.isIE && (a.indexOf("sv1") > -1);
    this.isIE7 = this.isIE && (a.indexOf("msie 7.0") > -1);
    this.isIE8 = this.isIE && (a.indexOf("msie 8.0") > -1);
    this.isBeforeIE6XPSP2 = this.isIE && !this.isIE6XPSP2 && !this.isIE7 && !this.isIE8;
    this.isWinIE = this.isIE && (a.indexOf('mac') == -1);
    this.isIE64 = this.isIE && (a.indexOf('win64') > -1);
    this.isFF = (a.indexOf('firefox') > -1);
    this.isWindowsOS = (navigator.platform.indexOf("Win") > -1);
})(),

showWarning = function(msg) {
    $au.debug().showWarning(msg);
},

showError = function(msg) {
    $au.debug().showError(msg);
},

trace = function(msg) {
    $au.debug().trace(msg);
},

//encode reserved html symbols
htmlencode = function(text) {
    if (text && typeof text.replace === 'function') {
        var entities = [
            ["\"", "&#34;"],
            ["'", "&#39;"],
            ["&", "&#38;"],
            ["<", "&#60;"],
            [">", "&#62;"]
        ];
        var rg = /\"|\'|&|<|>/g;
        return text.replace(rg, function(c) {
            for (var i = 0, cnt = entities.length; i < cnt; i++) {
                if (c == entities[i][0]) {
                    return entities[i][1];
                }
            }
            return c;
        });
    } else {
        return text;
    }
},

getCurrentUrl = wnd.getCurrentUrl = function() {
    return document.location.href;
},

// get handler name for event
// it will be global function called from uploader control
getGlobalHandlerName = function(uploader, eventName) {
    // pattern: '__uploaderID_eventName'
    return ["__" + uploader.id(), "_", eventName].join("");
},

// get uploader parameters in array of { name: 'name', value: 'value' } objects
getParams = function() {
    ///	<summary>
    ///		For internal use only! Get params array for rendering control.
    ///	</summary>
    var params = [], i, cnt, value;
    //simple properties just copy to array
    if (this._simpleProperties && this._simpleProperties.length > 0) {
        for (i = 0, cnt = this._simpleProperties.length; i < cnt; i++) {
            if (!this._simpleProperties[i].isAttribute) {
                value = this[this._simpleProperties[i].name]() + "";
                if (value != "null" && value != "undefined") {
                    params.push({ name: this._simpleProperties[i].renderName || this._simpleProperties[i].name, value: value });
                }
            }
        }
    }
    // getParams from object properties
    if (this._objectProperties && this._objectProperties.length > 0) {
        for (i = 0, cnt = this._objectProperties.length; i < cnt; i++) {
            value = this[this._objectProperties[i].name]();
            if (typeof value.getParams === "function") {
                params = params.concat(value.getParams());
            }
        }
    }
    return params;
},

propertyMaker = {
    createSimpleProperty: function(obj, property) {
        ///	<summary>
        ///		Create method with the name property.name for object obj.
        ///     Method works like property: if we pass argument it set new value, 
        ///     if we call method without arguments it return stored value.
        ///	</summary>
        ///	<param name="obj" type="Object">
        ///	    The object for which to create a method.
        ///	</param>
        ///	<param name="property" type="Object">
        ///	    The object which contains method name and defaut value.
        ///	</param>
        if (typeof property.name === 'string') {
            var value = property.defaultValue;
            obj[property.name] = function() {
                if (arguments.length > 0) {
                    // Set value if we pass parameter
                    value = arguments[0];
                } else {
                    // Return value if call method without parameter
                    return value;
                }
            };
        }
    },
    createObjectProperty: function(obj, property, uploader) {
        ///	<summary>
        ///		Create method with the name property.name for object obj.
        ///     Method works like property: if we pass argument it set new value, 
        ///     if we call method wothout arguments it return stored value.
        ///	</summary>
        ///	<param name="obj" type="Object">
        ///	    The object for which to create a method.
        ///	</param>
        ///	<param name="property" type="Object">
        ///	    The object which contains method name and defaut value.
        ///	</param>

        // Create new object for this property
        var valueObj = new property.type();

        // Init created object
        // In init usually we create object's simple and object properties
        if (typeof property.type.init === 'function') {
            property.type.init(valueObj, uploader);
        } else {
            var errMsg = "Can not create property '" + property.name + "'. 'init' method is not a function.";
            showError(errMsg);
            throw errMsg;
        }

        obj[property.name] = function() {
            if (arguments.length > 0) {
                var initObj = arguments[0];
                for (var name in initObj) {
                    valueObj[name](initObj[name]);
                }
            } else {
                return valueObj;
            }
        }
    },
    createControlProperty: function(obj, property) {
        ///	<summary>
        ///		Create method with the name property.name for object obj.
        ///     Method works like property: if we pass argument it set new value,
        ///     if we call method wothout arguments it return stored value.
        ///     The value get from or set to the underlying flash, activex or java control.
        ///	</summary>
        ///	<param name="obj" type="Object">
        ///	    The object for which to create a method.
        ///	</param>
        ///	<param name="property" type="Object">
        ///	    The object which contains method name and defaut value.
    ///	</param>
        if (typeof property.name === 'string' && !property.renderOnly) {
            try {
                trace("[js_trace] Creating '" + property.name + "' property.");
                // save current property value
                var oldValue = obj[property.name](),
                    uploader = obj._uploader,
                    element = uploader.getElement();

                var getter = property.getter, setter = property.setter;
                // Check if get method exist in control
                if (getter && (typeof element[getter] === 'undefined')) {
                    showWarning('Function "' + getter + '" undefined');
                    // stub for getter
                    element[getter] = function() {
                        showError("Uploader have not property '" + getter + "'");
                        return null;
                    };
                }
                // Check if set method exist in control
                if (setter && (typeof element[setter] === 'undefined')) {
                    showWarning('Function "' + setter + '" undefined');
                    // stub for setter
                    element[setter] = function() {
                        showError("Uploader have not property '" + setter + "'");
                    };
                }

                obj[property.name] = function() {
                    // set value if we pass parameter
                    if (arguments.length > 0) {
                        return element[setter](arguments[0]);
                    } else {
                        //return value otherwise
                        return element[getter]();
                    }
                };

                // Set value
                if (oldValue !== UNDEF) {
                    obj[property.name](oldValue);
                }

            } catch (err) {
                var msg = "Can't create property '" + property.name + "'.\r\n";
                if (typeof err === "string") {
                    err = msg + err;
                } else {
                    err.message = msg + (err.message || err.description || err);
                }
                throw err;
            }
        }
    },
    createAttributeProperty: function(obj, property) {
        ///	<summary>
        ///		Create method with the name property.name for object obj.
        ///     Method works like property: if we pass argument it set new value,
        ///     if we call method wothout arguments it return stored value.
        ///     The value get from or set to the underlying element <b>attribute</b>.
        ///	</summary>
        ///	<param name="obj" type="Object">
        ///	    The object for which to create a method.
        ///	</param>
        ///	<param name="property" type="Object">
        ///	    The object which contains method name and defaut value.
        ///	</param>
        var uploader = obj._uploader, element = uploader.getElement();
        obj[property.name] = function() {
            // set value if we pass parameter
            if (arguments.length > 0) {
                return element[property.name] = arguments[0];
            } else {
                //return value otherwise
                return element[property.name];
            }
        };
    },
    createMethod: function(obj, method) {
        var uploader = obj._uploader, element = uploader.getElement();
        var controlMethodName = method.controlMethodName || method.name;
        obj[method.name] = function() {
            return element[controlMethodName].apply(element, arguments);
        };
    },
    _typicalInit: function(obj, uploader) {
        ///	<summary>
        ///		DO NOT CALL THIS FUNCTION, use 'init' method for particular type
        ///     Usually 'init' should create simple and object properties for particular type,
        ///     and in this case we can use this function in type's init method.
        ///	</summary>
        ///	<param name="obj" type="Object">
        ///	    The object for which to create a method.
        ///	</param>
        ///	<param name="uploader" type="Object">
        ///	    The parent uploader object.
        ///	</param>

        // Add reference to the parent uploader object
        obj._uploader = uploader;

        // Init simple properties
        if (obj._simpleProperties) {
            for (var i = 0, imax = obj._simpleProperties.length; i < imax; i++) {
                propertyMaker.createSimpleProperty(obj, obj._simpleProperties[i]);
            }
        }

        // Init object properties
        if (obj._objectProperties) {
            for (var i = 0, imax = obj._objectProperties.length; i < imax; i++) {
                propertyMaker.createObjectProperty(obj, obj._objectProperties[i], uploader);
            }
        }
    },
    _typicalReinit: function(obj) {
        // Map uploader properties to the control
        if (obj._simpleProperties) {
            for (var i = 0, imax = obj._simpleProperties.length; i < imax; i++) {
                var property = obj._simpleProperties[i];
                if (!property.isAttribute) {
                    propertyMaker.createControlProperty(obj, property);
                }
            }
        }
        if (obj._objectProperties) {
            for (var i = 0, imax = obj._objectProperties.length; i < imax; i++) {
                var property = obj._objectProperties[i];
                if (property.type && typeof property.type.reinit === 'function') {
                    property.type.reinit(obj[property.name]());
                }
            }
        }
    }
},

ObjectManager = {
    _cache: {},
    _uid: 0,
    create: function(objClass, initObj) {
        if (objClass === "imageUploaderFlash") {
            var uploader = new $au.imageUploaderFlash.fn.init(initObj);
            var id = uploader.id() || ++this._uuid;
            this._cache[id] = uploader;
            uploader.cacheId = id;
            return uploader;
        } else {
            throw Error("\'" + objClass + "\" class is not supported");
        }
    },
    getObjectFromCache: function(id) {
        var c = this._cache;
        if (c[id]) {
            return c[id];
        } else {
            for (var i = 0, imax = c.length; i < imax; i++) {
                if (c[i] && c[i].id() === id) {
                    return c[i];
                }
            }
            return null;
        }
    }
};
// Flash Player version detection script.
var flashDetector = $au.flashDetector = {
    detectVersion: function() {
        ///	<summary>
        ///	    Detect installed flash version. The method returns array of 
        /// three numbers, where first number - major version number, 
        /// second number - minor version number, third number - number of revision. 
        /// For example the latest flash version now is 10.0.45, so method return 
        /// this array [10, 0, 45]. If flash is not installed we return [-1, -1, -1] array.
        ///	</summary>
        ///	<returns type="Array" Array with installed version number. />
        var version = null,
            plugins = navigator.plugins,
            plg;
        if (plugins && typeof ((plg = plugins["Shockwave Flash 2.0"] || plugins["Shockwave Flash"])) !== 'undefined') {
            var flashDescr = plg.description; // Shockwave Flash 10.0 r42
            var matches = /^.+\s+(\d+).(\d+)\s+r(\d+)$/.exec(flashDescr);
            var verMajor = parseInt(matches[1], 10) || 0;
            var verMinor = parseInt(matches[2], 10) || 0;
            var revVer = parseInt(matches[3], 10) || 0;
            version = [verMajor, verMinor, revVer];
        } else if (wnd.ActiveXObject) {
            try {
                // version will be set for 7.X or greater players
                var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
            } catch (e) {
                try {
                    // version will be set for 6.X players only
                    axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");

                    // installed player is some revision of 6.0
                    // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
                    // so we have to be careful. 

                    // default to the first public version
                    version = [6, 0, 21]; // "6,0,21,0";

                    // throws if AllowScripAccess does not exist (introduced in 6.0r47)		
                    axo.AllowScriptAccess = "always";

                } catch (e) { }
            }

            if (axo) {
                try {
                    var versionStr = axo.GetVariable("$version");
                    matches = /^\S+\s+(\d+),(\d+),(\d+)(,\d+)?$/.exec(versionStr);
                    verMajor = parseInt(matches[1], 10) || 0;
                    verMinor = parseInt(matches[2], 10) || 0;
                    revVer = parseInt(matches[3], 10) || 0;
                    version = [verMajor, verMinor, revVer];
                } catch (e) { }
            }
        }

        if (!version) {
            version = [-1, -1, -1]; // Flash player is not installed
        }

        return version;
    }
}
$au.debug = function() {
    ///	<summary>
    ///		Get configure debug object.
    ///	</summary>
    ///	<returns type="$au.debug" />
    if (!this._debug) {
        var f = function() {
            this.constructor = $au.debug;
        };
        f.prototype = $au.debug.prototype;
        this._debug = new f();
    }
    return this._debug;
};

$au.debug.prototype = {

    ///	<field name="debugLevel" type="Number">
    ///		Configure debug level.
    ///     0 - no debug messages,
    ///     1 - errors,
    ///     2 - errors and warnings,
    ///     3 - errors, warnings and trace messages
    ///	</field>
    debugLevel: 0, // disable debug by default

    traceToJS: true,

    traceMode: ['popup', 'console', 'alert'],

    showWarning: function(msg) {
        this.showMessage(msg, 2);
    },

    showError: function(msg) {
        this.showMessage(msg, 1);
    },

    trace: function(msg) {
        if (this.debugLevel >= 3) {
            for (var i in this.traceMode) {
                var mode = this.traceMode[i];
                switch (mode) {
                    case 'console':
                        // check the console available
                        if (typeof wnd.console != 'undefined' && console.log) {
                            console.log(msg);
                            return;
                        }
                        break;
                    case 'popup':
                        if (!this._popupWindow || this._popupWindow.closed) {
                            // open popup window
                            this._popupWindow = wnd.open('', 'traceWindow' + +new Date,
                                'width=300,height=200,menubar=1,status=1,scrollbars=1,resizable=1');

                            // popup has been blocked
                            if (!this._popupWindow)
                                break;

                            // write log window html
                            var html = [];
                            html.push('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n');
                            html.push('<html xmlns="http://www.w3.org/1999/xhtml">\n');
                            html.push('<head>');
                            html.push('<title>Aurigma Image Uploader Flash Log Window</title>');
                            html.push('</head>');
                            html.push('<body>');
                            html.push('<input type="button" value="Clear" onclick=\'document.getElementsByTagName("ol")[0].innerHTML = "";\' />');
                            html.push('<ol>');
                            html.push('</ol>');
                            html.push('</body>');
                            html.push('</html>');
                            this._popupWindow.document.write(html.join(''));
                        }
                        // add log message
                        var el = this._popupWindow.document.createElement("li");
                        el.innerHTML = msg;
                        this._popupWindow.document.getElementsByTagName("ol")[0].appendChild(el);
                        return;
                    case 'alert':
                        alert(msg);
                        return;
                }
            }
        }
    },

    showMessage: function(msg, level) {
        if (this.debugLevel >= level) {
            if (typeof wnd.console != 'undefined' && console.log) {
                // print message to console
                wnd.console.log(msg);
            } else {
                // show alert
                alert(msg);
            }
        }
    }
};
var formHelper = (function() {

    function fieldValue(el) {
        var n = el.name, t = el.type, tag = el.tagName.toLowerCase();

        if (!n || el.disabled ||
            t == 'reset' || t == 'button' || t == 'file' || t == 'submit' || t == 'image' ||
		    (t == 'checkbox' || t == 'radio') && !el.checked ||
		    tag == 'select' && el.selectedIndex == -1) {
            return null;
        }

        if (tag == 'select') {
            var index = el.selectedIndex;
            if (index < 0) return null;
            var a = [], ops = el.options;
            var one = (t == 'select-one');
            var max = (one ? index + 1 : ops.length);
            for (var i = (one ? index : 0); i < max; i++) {
                var op = ops[i];
                if (op.selected) {
                    var v = op.value;
                    if (!v) // for IE...
                        v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
                    if (one) return v;
                    a.push(v);
                }
            }
            return a;
        }
        return el.value;
    }

    function formToArray(form) {
        var a = [];
        var els = form.elements;
        if (!els) return a;
        for (var i = 0, cnt = els.length; i < cnt; i++) {
            var el = els[i];
            var n = el.name;
            if (!n) continue;

            var v = fieldValue(el);
            if (v && v.constructor == Array) {
                for (var j = 0, jmax = v.length; j < jmax; j++)
                    a.push({ name: n, value: v[j], array: true, first: (j === 0) });
            }
            else if (v !== null && typeof v != 'undefined')
                a.push({ name: n, value: v });
        }
        return a;
    }

    return {
        formToArray: formToArray
    };
})();
$au.commonDialog = function() {
    ///	<summary>
    ///		Common dialog window properties.
    ///	</summary>
    ///	<returns type="$au.commonDialog" />
};

$au.commonDialog.prototype = {
    _simpleProperties: [
        { name: "okButton", getter: "getCommonDialogOK", setter: "setCommonDialogOK" },
        { name: "cancelButton", getter: "getCommonDialogCancel", setter: "setCommonDialogCancel" }
    ],
    okButton: function(value) {
        ///	<summary>
        ///		Gets or sets the text of the OK button.
        ///	</summary>
        ///	<param name="value" type="String">
        ///     New button text.
        ///	</param>
    },
    cancelButton: function(value) {
        ///	<summary>
        ///		Gets or sets the text of the Cancel button.
        ///	</summary>
        ///	<param name="value" type="String">
        ///     New button text.
        ///	</param>
    }
};
$au.commonDialog.init = propertyMaker._typicalInit;
$au.commonDialog.reinit = propertyMaker._typicalReinit;
$au.converter = function(json) {
    this.mode("*.*=SourceFile");
	if (json) {
        this.set(json);
    }
    this.constructor = $au.converter.prototype;
};

$au.converter.prototype = {
    thumbnailWidth: function() {
        if (arguments.length > 0) {
            if (arguments[0] >= 0)
                this._thumbnailWidth = arguments[0];
        } else
            return this._thumbnailWidth;
    },
    thumbnailHeight: function() {
        if (arguments.length > 0) {
            if (arguments[0] >= 0)
                this._thumbnailHeight = arguments[0];
        } else
            return this._thumbnailHeight;
    },
    thumbnailFitMode: function() {
        if (arguments.length > 0) {
            if (arguments[0] || arguments[0] === 0)
                this._thumbnailFitMode = arguments[0];
        } else
            return this._thumbnailFitMode;
    },
    thumbnailJpegQuality: function() {
        if (arguments.length > 0) {
            if (arguments[0] >= 0)
                this._thumbnailJpegQuality = arguments[0];
        } else
            return this._thumbnailJpegQuality;
    },
    mode: function() {
        if (arguments.length > 0) {
            if (arguments[0]) {
                this._validateMode(arguments[0]);
                this._mode = arguments[0];
            }
        } else {
            return this._mode;
        }
    },
    thumbnailBgColor: function() {
        if (arguments.length > 0) {
            if (arguments[0] >= 0) {
                this._thumbnailBgColor = arguments[0];
            }
        } else {
            return this._thumbnailBgColor;
        }
    },
    set: function(json) {
        if (json) {
            if (typeof json.toJson == 'function')
                json = json.toJson();
            this.thumbnailWidth(json.thumbnailWidth);
            this.thumbnailHeight(json.thumbnailHeight);
            this.thumbnailFitMode(json.thumbnailFitMode);
            this.thumbnailJpegQuality(json.thumbnailJpegQuality);
            this.thumbnailBgColor(json.thumbnailBgColor);
            this.mode(json.mode);
        }
    },
    toJson: function() {
        return {
            mode: this.mode(),
            thumbnailWidth: this.thumbnailWidth(),
            thumbnailHeight: this.thumbnailHeight(),
            thumbnailFitMode: this.thumbnailFitMode(),
            thumbnailJpegQuality: this.thumbnailJpegQuality(),
            thumbnailBgColor: this.thumbnailBgColor()
        };
    },
    _validateMode: function(modeString) {
        var rg = /^((.*=)?(SourceFile|Thumbnail|Icon|None|Zip);)*(.*=)?(SourceFile|Thumbnail|Icon|None|Zip);?$/;
        if (rg.test(modeString)) {
            return true;
        } else {
            showError("Converter mode string is not valid.\n" + modeString);
            return false;
        }
    }
};

//change prototype to work with rendered control
$au.converter.reinit = function(element, converter) {
    converter.thumbnailWidth = function() {
        if (this._index >= 0) {
            // work with control
            if (arguments.length > 0) {
                if (arguments[0] >= 0) {
                    element.setConverterThumbnailWidth(this._index, arguments[0]);
                }
            } else
                return element.getConverterThumbnailWidth(this._index);
        }
    };
    converter.thumbnailHeight = function() {
        if (arguments.length > 0) {
            if (arguments[0] >= 0) {
                element.setConverterThumbnailHeight(this._index, arguments[0]);
            }
        } else
            return element.getConverterThumbnailHeight(this._index);
    };
    converter.thumbnailFitMode = function() {
        if (arguments.length > 0) {
            if (arguments[0] === 0 || arguments[0]) {
                element.setConverterThumbnailFitMode(this._index, arguments[0]);
            }
        } else
            return element.getConverterThumbnailFitMode(this._index);
    };
    converter.thumbnailJpegQuality = function() {
        if (arguments.length > 0) {
            if (arguments[0] >= 0)
                element.setConverterThumbnailJpegQuality(this._index, arguments[0]);
        } else
            return element.getConverterThumbnailJpegQuality(this._index);
    };
    converter.mode = function() {
        if (arguments.length > 0) {
            if (arguments[0]) {
                this._validateMode(arguments[0]);
                element.setConverterMode(this._index, arguments[0]);
            }
        } else {
            return element.getConverterMode(this._index);
        }
    };
    converter.thumbnailBgColor = function() {
        if (arguments.length > 0) {
            if (arguments[0] >= 0) {
                element.setConverterThumbnailBgColor(this._index, arguments[0]);
            }
        } else {
            return element.getConverterThumbnailBgColor(this._index);
        }
    };
};
$au.converters = function() {
    ///	<summary>
    ///		Get or set upload converters properties
    ///	</summary>
    ///	<returns type="$au.converters" />
}

$au.converters.prototype = {
    add: function() {
        ///	<summary>
        ///		Add converter to uploader
        ///	</summary>
        ///	<returns type="$au.converter" />
        var th;
        if (arguments[0] instanceof $au.converter) {
            th = arguments[0];
        } else {
            th = new $au.converter(arguments[0]);
        }
        this._converters.push(th);
        return th;
    },
    count: function() {
        return this._converters.length;
    },
    get: function(index) {
        ///	<summary>
        ///		Get thumbnail to upload
        ///	</summary>
        ///	<param name="index" type="Number">
        ///     thumbnail index
        ///	</param>
        ///	<returns type="$au.converter" />
        return this._converters[index];
    },
    remove: function(index) {
        ///	<summary>
        ///		Remove thumbnail
        ///	</summary>
        ///	<param name="index" type="Number">
        ///     thumbnail index
        ///	</param>
        this._converters.splice(index, 1);
    },
    removeAll: function() {
        this._converters.length = 0;
        while (this.count() > 0) {
            this.remove(0);
        }
    }
};

$au.converters.init = function(obj, uploader) {
    obj._uploader = uploader;
    obj._converters = [new $au.converter({ mode: "*.*=SourceFile" })];
}

// change prototype to work with rendered control
// for internal use
$au.converters.reinit = function(converters) {
    try {
        trace("[js_trace] Reinit converters.");

        var element = converters._uploader.getElement();

        if ($au.debug().debugLevel >= 3) {
            // check element converter methods existance
            if (typeof element.getConverterCount === UNDEF) {
                showError('getConverterCount method is not defined.');
            }
            if (typeof element.addConverter === UNDEF) {
                showError('addConverter method is not defined.');
            }
            if (typeof element.removeConverter === UNDEF) {
                showError('removeConverter method is not defined.');
            }
        }

        //save converters added before
        var convertersArr = [], i, cnt;
        for (i = 0, cnt = converters.count(); i < cnt; i++) {
            var cv = converters.get(i);
            convertersArr.push(cv.toJson());
        }

        // remove converters from control
        while (element.getConverterCount() > 0) {
            element.removeConverter(0);
        }

        //clear internal converters array
        converters._items = [];

        converters.add = function() {
            ///	<summary>
            ///		Add converter to uploader
            ///	</summary>
            ///	<returns type="$au.converter" added converter />
            var index = element.addConverter("*.*=SourceFile");
            if (index >= 0) {
                if (arguments[0]) {
                    var conv = this.get(index);
                    conv.set(arguments[0]);
                    return conv;
                }
            } else {
                showWarning("Converter hasn't been added.");
                return null;
            }
        };

        converters.count = function() {
            return element.getConverterCount();
        };

        converters.get = function(index) {
            ///	<summary>
            ///		Get converter
            ///	</summary>
            ///	<param name="index" type="Number">
            ///     Converter index
            ///	</param>
            ///	<returns type="$au.converter" />
            if (index < this.count()) {
                if (this._items && this._items[index]) {
                    return this._items[index];
                } else {
                    this._items = this._items || [];
                    //create object to provide methods to work with thumbnail
                    var th = new $au.converter();
                    th._index = index;
                    $au.converter.reinit(element, th);
                    this._items[index] = th;
                    return th;
                }
            } else {
                return null;
            }
        };

        converters.remove = function(index) {
            ///	<summary>
            ///		Remove thumbnail
            ///	</summary>
            ///	<param name="index" type="Number">
            ///     thumbnail index
            ///	</param>
            // remove from control
            element.removeConverter(index);
            //remove from internal array
            this._items.splice(index, 1);
            // re-index items
            for (var i in this._items) {
                this._items[i]._index = i;
            }
        };

        // add saved converters to uploader control
        for (i = 0, cnt = convertersArr.length; i < cnt; i++) {
            converters.add(convertersArr[i]);
        }
    } catch (err) {
        showError('Converters initialization failed.\n' + (err.message || err.description || err));
        throw err;
    }
};
$au.events = function(initObj) {
    ///	<summary>
    ///		Get or set uploader events           
    ///	</summary>
    ///	<param name="initObj" type="Array">
    ///		java control parameters.
    ///	</param>
    ///	<returns type="$au.events" />
    /* will be created while initialization */
};

$au.events.prototype = {
    _eventNames: ["initComplete", "beforeUpload", "afterUpload", "beforePackageUpload", "afterPackageUpload",
        "preRender", "progress"],

    preRender: function() {
        ///	<summary>
        ///		PreRender event. Called just before writeHtml or getHtml methods executed.
        ///	</summary>
        ///	<returns type="$au.event" />
    },
    initComplete: function() {
        ///	<summary>
        ///		InitComplete event            
        ///	</summary>
        ///	<returns type="$au.event" />
    },
    beforeUpload: function() {
        ///	<summary>
        ///		BeforeUpload event            
        ///	</summary>
        ///	<returns type="$au.event" />
    },
    afterUpload: function() {
        ///	<summary>
        ///		AfterUpload event
        ///	</summary>
        ///	<returns type="$au.event" />
    },
    beforePackageUpload: function() {
        ///	<summary>
        ///		BeforePackageUpload event            
        ///	</summary>
        ///	<returns type="$au.event" />
    },
    afterPackageUpload: function() {
        ///	<summary>
        ///		AfterPackageUpload event            
        ///	</summary>
        ///	<returns type="$au.event" />
    },
    progress: function() {
        ///	<summary>
        ///		AfterPackageUpload event            
        ///	</summary>
        ///	<returns type="$au.event" />
    },
    getParams: function() {
        var params = [];
        for (var i = 0, imax = this._eventNames.length; i < imax; i++) {
            var eventName = this._eventNames[i], evt = this[eventName];
            if (typeof evt === 'function' && evt().count() > 0) {
                params.push({ name: eventName.toLowerCase() + "listener",
                    value: getGlobalHandlerName(this._uploader, eventName)
                });
            }
        }
        return params;
    }
};

$au.events.init = function(obj, uploader) {
    obj._uploader = uploader;
    var events = obj._eventNames;
    var f = function() {
        var eventObj = new $au.event();
        return function() {
            if (arguments.length > 0) {
                eventObj.add(arguments[0]);
            }
            return eventObj;
        };
    }
    for (var i = 0, imax = events.length; i < imax; i++) {
        obj[events[i]] = f();
    }
};
$au.file = function(json) {
    if (json) {
        this.set(json);
    }
    this.constructor = $au.file.prototype;
};

$au.file.prototype = {
    name: function() {
    },
    size: function() {
    },
    width: function() {
    },
    height: function() {
    },
    angle: function(angle) {
    },
    description: function(description) {
    },
    selected: function(selected) {
    }
};

//change object to work with rendered control
$au.file.reinit = function(element, obj) {

    obj.name = function() {
        return element.getUploadFileName(this._index);
    };
    obj.size = function() {
        return element.getUploadFileSize(this._index);
    };
    obj.width = function() {
        return element.getUploadFileWidth(this._index);
    };
    obj.height = function() {
        return element.getUploadFileHeight(this._index);
    };
    obj.angle = function(angle) {
        if (angle || angle === 0) {
            element.setUploadFileAngle(this._index, angle);
        } else {
            return element.getUploadFileAngle(this._index);
        }
    };
    obj.description = function(description) {
        if (description !== UNDEF) {
            element.setUploadFileDescription(this._index, description);
        } else {
            return element.getUploadFileDescription(this._index);
        }
    };
    obj.selected = function(selected) {
        if (selected !== UNDEF) {
            element.setUploadFileSelected(this._index, selected);
        } else {
            return element.getUploadFileSelected(this._index);
        }

    };

};
$au.files = function() {
    ///	<summary>
    ///		Get collection of files to upload.
    ///	</summary>
    ///	<returns type="$au.files" />
};

$au.files.prototype = {
    count: function() {
        ///	<summary>
        ///		Get count of files selected to upload.
        ///	</summary>
        ///	<returns type="Number" />

        // can't select files before uploader initialization
        return 0;
    },
    get: function(index) {
        ///	<summary>
        ///		Get file to upload
        ///	</summary>
        ///	<param name="index" type="Number">
        ///     Index of files in the list view
        ///	</param>
        ///	<returns type="$au.file" />

        // can't select files before uploader initialization
        return null;
    }
};

$au.files.init = propertyMaker._typicalInit;

// change object to work with rendered control
// for internal use
$au.files.reinit = function(obj) {
    trace("[js_trace] Reinit files API.");

    var element = obj._uploader.getElement();

    obj.count = function() {
        return element.getUploadFileCount();
    };

    obj.get = function(index) {
        if (index < this.count()) {
            if (this._items && this._items[index]) {
                return this._items[index];
            } else {
                this._items = this._items || [];
                //create object to provide methods to work with file
                var f = new $au.file();
                $au.file.reinit(element, f);
                f._index = index;
                this._items[index] = f;
                return f;
            }
        } else {
            return null;
        }
    };
};
$au.flashControl = function() {
    ///	<summary>
    ///		Get or set flash control parameters            
    ///	</summary>
    ///	<param name="initObj" type="Object">
    ///		flash control parameters.
    ///	</param>
    ///	<returns type="$au.flashControl" />
    /* will be created while initialization */
};
$au.flashControl.prototype = {
    _simpleProperties: [
        { name: "codeBase", defaultValue: "aurigma.imageuploader.swf", isAttribute: true },
        { name: "themeUrl", getter: "getThemeUrl", setter: "setThemeUrl", renderOnly: true },
        { name: "bgColor", isAttribute: true },
        { name: "maxFileToLoadSize", getter: "getMaxFileToLoadSize", setter: "setMaxFileToLoadSize" },
        { name: "version", isAttribute: true }
    ],
    flashVersionRequired: [9, 0, 0],
    codeBase: function(codeBase) {
        ///	<summary>
        ///		Get or set URL to flash file
        ///	</summary>
        ///	<param name="codeBase" type="String">
        ///     URL to file
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    maxFileToLoadSize: function() {
        ///	<summary>
        ///		Configure max file size can be loaded into memory.
        ///     All other converters except sourceFile or None require to load file into memory.
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Ma file size able to be loaded into memory.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    themeUrl: function() {
        ///	<summary>
        ///		Gets or sets url to flash uploader theme.
        ///	</summary>
        ///	<param name="value" type="String">
        ///		URL to theme
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    bgColor: function() {
        ///	<summary>
        ///     Specifies the background color of the movie. Use this attribute to
        ///     override the background color setting specified in the Flash file.
        ///	</summary>
        ///	<param name="value" type="String">
        ///		[ hexadecimal RGB value] in the format #RRGGBB.
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    isFlashSupported: function() {
        // Can we use Flash?
        var v = $au.flashDetector.detectVersion();
        var reqVer = this.flashVersionRequired;
        for (var i = 0, imax = reqVer.length; i < imax; i++) {
            if (v[i] < reqVer[i]) {
                return false;
            }
        }
        return true;
    },
    getParams: getParams
};

$au.flashControl.init = propertyMaker._typicalInit;
$au.flashControl.reinit = propertyMaker._typicalReinit;
$au.imagePreviewWindow = function() {
    ///	<summary>
    ///		Get image preview window.
    ///	</summary>
    ///	<returns type="$au.imagePreviewWindow" />
};

$au.imagePreviewWindow.prototype = {
    _simpleProperties: [
        { name: "closePreviewToolTip", getter: "getClosePreviewToolTip", setter: "setClosePreviewToolTip" }
    ],
    closePreviewToolTip: function(text) {
        ///	<summary>
        ///		Gets or sets the text displayed when the mouse pointer hovers 
        ///     over the image caption on preview window.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New tooltip text of image caption on preview window.
        ///	</param>
    }
};

$au.imagePreviewWindow.init = propertyMaker._typicalInit;
$au.imagePreviewWindow.reinit = propertyMaker._typicalReinit;
$au.listView = function() {
    ///	<summary>
    ///		Get list view
    ///	</summary>
    ///	<returns type="$au.listView" />
};

$au.listView.prototype = {
    _simpleProperties: [
        { name: "removeIconToolTip", getter: "getRemoveIconToolTip", setter: "setRemoveIconToolTip" },
        { name: "rotateIconToolTip", getter: "getRotateIconToolTip", setter: "setRotateIconToolTip" },
        { name: "itemToolTip", getter: "getItemToolTip", setter: "setItemToolTip" },
        { name: "imageToolTip", getter: "getImageToolTip", setter: "setImageToolTip" },
        { name: "descriptionIconToolTip", getter: "getDescriptionIconToolTip", setter: "setDescriptionIconToolTip" },
        { name: "iconSize", getter: "getIconSize", setter: "setIconSize" },
        { name: "tilePreviewSize", getter: "getTilePreviewSize", setter: "setTilePreviewSize" },
        { name: "thumbnailPreviewSize", getter: "getThumbnailPreviewSize", setter: "setThumbnailPreviewSize" },
        { name: "tileItemWidth", getter: "getTileItemWidth", setter: "setTileItemWidth" },
        { name: "iconItemWidth", getter: "getIconItemWidth", setter: "setIconItemWidth" },
        { name: "addFilesButton", getter: "getAddFilesButton", setter: "setAddFilesButton" },
        { name: "view", getter: "getView", setter: "setView" }
    ],

    addFilesButton: function(obj) {
        ///	<summary>
        ///		Get or set 'Add Files Button' button button properties
        ///	</summary>
        ///	<param name="obj" type="String,Object">
        ///     'Add Files Button' button text or image format
        ///	</param>
    },

    removeIconToolTip: function(text) {
        ///	<summary>
        ///		Gets or sets the text displayed when the mouse pointer hovers over the remove icon.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New tooltip text of remove icon.
        ///	</param>
    },
    rotateIconToolTip: function(text) {
        ///	<summary>
        ///		Gets or sets the text displayed when the mouse pointer hovers over the rotate icon.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New tooltip text of rotate icon.
        ///	</param>
    },
    imageToolTip: function(text) {
        ///	<summary>
        ///		Gets or sets the text displayed when the mouse pointer hovers over the image thumbnail.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New tooltip text of image thumbnail.
        ///	</param>
    },
    itemToolTip: function(text) {
        ///	<summary>
        ///		Gets or sets the text displayed when the mouse pointer hovers over the non-image item.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New tooltip text of non-image item.
        ///	</param>
    },
    descriptionIconToolTip: function(text) {
        ///	<summary>
        ///		Gets or sets the text displayed when the mouse pointer hovers over the edit description icon.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New tooltip text of edit description icon.
        ///	</param>
    },

    iconSize: function(value) {
        ///	<summary>
        ///		Gets or sets the file icons size.
        ///	</summary>
        ///	<param name="value" type="Number">
        ///     New file icons size.
        ///	</param>
    },
    tilePreviewSize: function(value) {
        ///	<summary>
        ///		Gets or sets the tiles size.
        ///	</summary>
        ///	<param name="value" type="Number">
        ///     New tiles size.
        ///	</param>
    },
    thumbnailPreviewSize: function(value) {
        ///	<summary>
        ///		Gets or sets the size of thumbnails in list view.
        ///	</summary>
        ///	<param name="value" type="Number">
        ///     New size of thumbnails in list view.
        ///	</param>
    },
    tileItemWidth: function(value) {
        ///	<summary>
        ///		Gets or sets the tile item width.
        ///	</summary>
        ///	<param name="value" type="Number">
        ///     New tile item width.
        ///	</param>
    },
    iconItemWidth: function(value) {
        ///	<summary>
        ///		Gets or sets the icon item width.
        ///	</summary>
        ///	<param name="value" type="Number">
        ///     New icon item width.
        ///	</param>
    },
    view: function(value) {
        ///	<summary>
        ///		Gets or sets the list view.
        ///	</summary>
        ///	<param name="value" type="Number,String">
        ///     New list view value.
        ///	</param>
    }
};

$au.listView.init = propertyMaker._typicalInit;
$au.listView.reinit = propertyMaker._typicalReinit;
$au.messages = function() {
    ///	<summary>
    ///		Get status panel
    ///	</summary>
    ///	<returns type="$au.messages" />
}

$au.messages.prototype = {
    _simpleProperties: [
        { name: "cannotReadFileError", getter: "getCannotReadFileError",
            setter: "setCannotReadFileError"
        },
        { name: "fileTooLargeError", getter: "getFileTooLargeError",
            setter: "setFileTooLargeError"
        },
        { name: "fileTooSmallError", getter: "getFileTooSmallError",
            setter: "setFileTooSmallError"
        },
        { name: "imageWidthTooLargeError", getter: "getImageWidthTooLargeError",
            setter: "setImageWidthTooLargeError"
        },
        { name: "imageHeightTooLargeError", getter: "getImageHeightTooLargeError",
            setter: "setImageHeightTooLargeError"
        },
        { name: "imageWidthTooSmallError", getter: "getImageWidthTooSmallError",
            setter: "setImageWidthTooSmallError"
        },
        { name: "imageHeightTooSmallError", getter: "getImageHeightTooSmallError",
            setter: "setImageHeightTooSmallError"
        },
        { name: "tooFewFilesError", getter: "getTooFewFilesError",
            setter: "setTooFewFilesError"
        },
        { name: "tooManyFilesError", getter: "getTooManyFilesError",
            setter: "setTooManyFilesError"
        },
        { name: "totalFileSizeTooLargeError", getter: "getTotalFileSizeTooLargeError",
            setter: "setTotalFileSizeTooLargeError"
        },
        { name: "notAllFilesWereAddedError", getter: "getNotAllFilesWereAddedError",
            setter: "setNotAllFilesWereAddedError"
        },
        { name: "previewNotAvailableError", getter: "getPreviewNotAvailableError",
            setter: "setPreviewNotAvailableError"
        }
    ],

    cannotReadFileError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when the read file error occurs.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    fileTooLargeError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to add 
        ///     file larger maxFileSize restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    fileTooSmallError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to add 
        ///     file smaller minFileSize restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    imageWidthTooLargeError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to add 
        ///     image with width larger maxImageWidth restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    imageHeightTooLargeError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to add 
        ///     image with height larger maxImageHeight restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    imageWidthTooSmallError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to add 
        ///     image with width smaller minImageWidth restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    imageHeightTooSmallError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to add 
        ///     image with height smaller minImageHeight restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    tooFewFilesError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to upload 
        ///     number of files less than the minFileCount restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    tooManyFilesError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to upload 
        ///     number of files more than the maxFileCount restriction.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    totalFileSizeTooLargeError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to upload files 
        ///     with total size bigger than the maxTotalSize restrictions.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    notAllFilesWereAddedError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when user tries to add files
        ///     and some of them were not added because of restrictions.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    previewNotAvailableError: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when image preview is not available.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    messageUploadCompleteText: function(text) {
        ///	<summary>
        ///		Gets or sets the message displayed when image preview is not available.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    messageUnexpectedErrorText: function(text) {
        ///	<summary>
        ///		Gets or sets the MessageUnexpectedErrorText property
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New error message.
        ///	</param>
    },
    messageMaxFileSizeExceededText: function(text) {
        ///	<summary>
        ///		
        ///	</summary>
        ///	<param name="text" type="String">
        ///     
        ///	</param>
    },
    messageFileSizeIsTooSmallText: function(text) {
        ///	<summary>
        ///		
        ///	</summary>
        ///	<param name="text" type="String">
        ///     
        ///	</param>
    },
    messageDimensionsAreTooLargeText: function(text) {
        ///	<summary>
        ///		
        ///	</summary>
        ///	<param name="text" type="String">
        ///     
        ///	</param>
    },
    messageDimensionsAreTooSmallText: function(text) {
        ///	<summary>
        ///		
        ///	</summary>
        ///	<param name="text" type="String">
        ///     
        ///	</param>
    },
    messageMaxTotalFileSizeExceededText: function(text) {
        ///	<summary>
        ///		
        ///	</summary>
        ///	<param name="text" type="String">
        ///     
        ///	</param>
    },
    messageMaxFileCountExceededText: function(text) {
        ///	<summary>
        ///		
        ///	</summary>
        ///	<param name="text" type="String">
        ///     
        ///	</param>
    }
};

$au.messages.init = propertyMaker._typicalInit;
$au.messages.reinit = propertyMaker._typicalReinit;
$au.metadata = function() {
    ///	<summary>
    ///		Get or set additional upload data
    ///	</summary>
    ///	<returns type="$au.metadata" />
}

$au.metadata.prototype = {
    addField: function(name, value, add) {
        this._fields = this._fields || [];
        if (name) {
            this._fields.push({ name: name, value: value, add: add });
        }
    },
    removeField: function(name) {
        if (name && this._fields && this._fields.length > 0) {
            for (var i = this._fields.length - 1; i >= 0; i--) {
                var f = this._fields[i];
                if (f.name == name) {
                    this._fields = this._fields.splice(i, 1);
                }
            }
        }
    },
    additionalFormName: function(name) {
        if (arguments.length == 0) {
            return this._formName;
        } else {
            if (this._beforeUploadHandler) {
                this._uploader.events().beforeUpload().remove(this._beforeUploadHandler);
                delete this._beforeUploadHandler;
                delete this._formName;
            }
            if (name) {
                this._formName = name;
                this._beforeUploadHandler = function() {
                    var metadata = this.metadata();
                    var form = document.forms[metadata._formName];
                    if (form) {
                        var fields = formHelper.formToArray(form), cnt = fields.length;
                        if (cnt > 0) {
                            for (var i = 0; i < cnt; i++) {
                                var f = fields[i];
                                if (!f.array || f.first) {
                                    metadata.addField(f.name, f.value);
                                } else {
                                    metadata.addField(f.name, f.value, true);
                                }
                            }
                        }
                    }
                };
                this._uploader.events().beforeUpload().add(this._beforeUploadHandler);
            }
        }
    }
};

$au.metadata.init = propertyMaker._typicalInit;

$au.metadata.reinit = function(obj) {
    trace("[js_trace] Reinit metadata.");

    var element = obj._uploader.getElement();
    
    obj.addField = function(name, value, add) {
        element.addField(name, value, add);
    };

    obj.removeField = function(name) {
        element.removeField(name);
    };

    //add fields from internal array to control
    if (obj._fields) {
        for (var i = 0, max = obj._fields.length; i < max; i++) {
            var f = obj._fields[i];
            obj.addField(f.name, f.value, f.add);
        };
    }
}
$au.restrictions = function() {
    ///	<summary>
    ///		Get or set upload restrictions properties
    ///	</summary>
    ///	<param name="restrictions" type="Object">
    ///		An object with restrictions parameters
    ///	</param>
    ///	<returns type="$au.restrictions" />
}

$au.restrictions.prototype = {
    _simpleProperties: [
            { name: "maxFileCount", getter: "getMaxFileCount", setter: "setMaxFileCount" },
            { name: "minFileCount", getter: "getMinFileCount", setter: "setMinFileCount" },
            { name: "maxTotalSize", getter: "getMaxTotalSize", setter: "setMaxTotalSize" },
            { name: "minFileSize", getter: "getMinFileSize", setter: "setMinFileSize" },
            { name: "maxFileSize", getter: "getMaxFileSize", setter: "setMaxFileSize" },
            { name: "minImageWidth", getter: "getMinImageWidth", setter: "setMinImageWidth" },
            { name: "maxImageWidth", getter: "getMaxImageWidth", setter: "setMaxImageWidth" },
            { name: "minImageHeight", getter: "getMinImageHeight", setter: "setMinImageHeight" },
            { name: "maxImageHeight", getter: "getMaxImageHeight", setter: "setMaxImageHeight" },
            { name: "fileFilters", getter: "getFileFilters", setter: "setFileFilters" }
        ],
    maxFileCount: function(value) {
        ///	<summary>
        ///		Maximum number of files allowed for upload per one session           
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Number of files allowed for upload.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    minFileCount: function(value) {
        ///	<summary>
        ///		Minimum number of files allowed for upload per one session           
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Number of files allowed for upload.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    maxTotalSize: function() {
        ///	<summary>
        ///		Maximum total file size allowed for upload.
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Total file size.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    minFileSize: function() {
        ///	<summary>
        ///		Minimum file size allowed for upload.           
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Minimum file size.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    maxFileSize: function() {
        ///	<summary>
        ///		Maximum file size allowed for upload.           
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Maximum file size.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    minImageWidth: function() {
        ///	<summary>
        ///		Minimum image width allowed for upload.            
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Minimum image width. 
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    maxImageWidth: function() {
        ///	<summary>
        ///		Maximum image width allowed for upload.          
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Maximum image width.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    minImageHeight: function() {
        ///	<summary>
        ///		Minimum image height allowed for upload.       
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Minimum image height.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    maxImageHeight: function() {
        ///	<summary>
        ///		Maximum image height allowed for upload.    
        ///	</summary>
        ///	<param name="value" type="Number">
        ///		Maximum image height.
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    fileFilters: function() {
        ///	<summary>
        ///		Get or set files filter in open files dialog.    
        ///	</summary>
        ///	<param name="value" type="String">
        ///		File filters.
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    deniedFileMask: function() {
        ///	<summary>
        ///		Get or set DeniedFileMask property
        ///	</summary>
        ///	<param name="mask" type="String">
        ///		DeniedFileMask
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    fileMask: function () {
        ///	<summary>
        ///		Get or set FileMask property
        ///	</summary>
        ///	<param name="mask" type="String">
        ///		FileMask
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    getParams: getParams
};

$au.restrictions.init = propertyMaker._typicalInit;
$au.restrictions.reinit = propertyMaker._typicalReinit;
$au.statusPanel = function() {
    ///	<summary>
    ///		Get status panel
    ///	</summary>
    ///	<returns type="$au.statusPanel" />
}

$au.statusPanel.prototype = {
    _simpleProperties: [
        { name: "sendButton", getter: "getSendButton", setter: "setSendButton" },
        { name: "stopButton", getter: "getStopButton", setter: "setStopButton" },
        { name: "filesPreparedLabel", getter: "getStatusPanelFilesPreparedLabel",
            setter: "setStatusPanelFilesPreparedLabel"
        },
        { name: "filesUploadedLabel", getter: "getStatusPanelFilesUploadedLabel",
            setter: "setStatusPanelFilesUploadedLabel"
        },
        { name: "dataUploadedLabel", getter: "getStatusPanelDataUploadedLabel",
            setter: "setStatusPanelDataUploadedLabel"
        },
        { name: "preparingLabel", getter: "getStatusPanelPreparingLabel",
            setter: "setStatusPanelPreparingLabel"
        },
        { name: "sendingLabel", getter: "getStatusPanelSendingLabel",
            setter: "setStatusPanelSendingLabel"
        },
        { name: "totalFilesLabel", getter: "getTotalFilesLabel", setter: "setTotalFilesLabel" }
    ],
    sendButton: function(obj) {
        ///	<summary>
        ///		Get or set Send button properties
        ///	</summary>
        ///	<param name="obj" type="String, Object">
        ///     Send button text or image format
        ///	</param>
    },
    stopButton: function(obj) {
        ///	<summary>
        ///		Get or set Stop button properties
        ///	</summary>
        ///	<param name="obj" type="String, Object">
        ///     Stop button text or image format
        ///	</param>
    },
    filesPreparedLabel: function(text) {
        ///	<summary>
        ///		Get or set prepared label text.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New prepared label text value.
        ///	</param>
    },
    filesUploadedLabel: function(text) {
        ///	<summary>
        ///		Get or set files uploaded label text.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New files uploaded label text value.
        ///	</param>
    },
    bytesUploadedLabel: function(text) {
        ///	<summary>
        ///		Get or set bytes uploaded label text.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New data uploaded label text value.
        ///	</param>
    },
    preparingLabel: function(text) {
        ///	<summary>
        ///		Get or set preparing header text.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New preparing header text value.
        ///	</param>
    },
    sendingLabel: function(text) {
        ///	<summary>
        ///		Get or set sending header text.
        ///	</summary>
        ///	<param name="text" type="String">
        ///     New sending header text value.
        ///	</param>
    },
    totalFilesLabel: function(value) {
        ///	<summary>
        ///		Get or set 'Total files' label on status panel.
        ///	</summary>
        ///	<param name="value" type="String">
        ///     'Total files' label text.
        ///	</param>
    }
};

$au.statusPanel.init = propertyMaker._typicalInit;
$au.statusPanel.reinit = propertyMaker._typicalReinit;
$au.topPanel = function() {
    ///	<summary>
    ///		Get top panel
    ///	</summary>
    ///	<returns type="$au.topPanel" />
}

$au.topPanel.prototype = {
    _simpleProperties: [
        { name: "addFilesLink", getter: "getAddFilesLink", setter: "setAddFilesLink" },
        { name: "removeAllFilesLink", getter: "getRemoveAllFilesLink", setter: "setRemoveAllFilesLink" },
        { name: "orLabel", getter: "getOrLabel", setter: "setOrLabel" },
        { name: "viewComboBox", getter: "getViewComboBox", setter: "setViewComboBox" },
        { name: "viewComboBoxLabel", getter: "getViewComboBoxLabel", setter: "setViewComboBoxLabel" },
        { name: "titleLabel", getter: "getTitleLabel", setter: "setTitleLabel" }
    ],
    addFilesLink: function(obj) {
        ///	<summary>
        ///		Get or set 'Add Files' link text.
        ///	</summary>
        ///	<param name="obj" type="String|Object">
        ///     'Add Files' link text
        ///	</param>
    },
    removeAllFilesLink: function(obj) {
        ///	<summary>
        ///		Get or set 'Remove All Files' link text.
        ///	</summary>
        ///	<param name="obj" type="String,Object">
        ///     'Remove All Files' link text
        ///	</param>
    },
    orLabel: function(obj) {
        ///	<summary>
        ///		Get or set 'or' label on top panel.
        ///	</summary>
        ///	<param name="obj" type="String,Object">
        ///     'or' label text
        ///	</param>
    },
    viewComboBox: function(obj) {
        ///	<summary>
        ///		Get or set Change view combobox values text.
        ///	</summary>
        ///	<param name="obj" type="Array">
        ///     'Change view' combobox values text.
        ///	</param>
    },
    viewComboBoxLabel: function(obj) {
        ///	<summary>
        ///		Get or set 'Change view' label on top panel.
        ///	</summary>
        ///	<param name="obj" type="String">
        ///     'Change view' label text.
        ///	</param>
    },
    titleLabel: function(value) {
        ///	<summary>
        ///		Get or set 'Files for upload' label on top panel.
        ///	</summary>
        ///	<param name="value" type="String">
        ///     'Files for upload' label text.
        ///	</param>
    }
};

$au.topPanel.init = propertyMaker._typicalInit;
$au.topPanel.reinit = propertyMaker._typicalReinit;
$au.upload = function() {
    ///	<summary>
    ///		Upload options.
    ///	</summary>
    ///	<returns type="$au.upload" />
}

$au.upload.prototype = {
    _simpleProperties: [
        { name: "_actionInternal", getter: "getActionUrl", setter: "setActionUrl", renderName: "actionUrl", defaultValue: document.location.href }
    ],
    actionUrl: function(url) {
        ///	<summary>
        ///		Get or set URL to upload
        ///	</summary>
        ///	<param name="url" type="String">
        ///     URL to to upload
        ///	</param>
        ///	<returns type="String" />
        if (url) {
            if (url == "." || url == "./") {
                // if default value (".") then use current document url
                url = document.location.href;
            }
            return this._actionInternal(url);
        } else {
            return this._actionInternal();
        }
    },
    redirectUrl: function(url) {
        ///	<summary>
        ///		Get or set URL to redirect after upload
        ///	</summary>
        ///	<param name="codeBase" type="String">
        ///     URL to redirect after upload
        ///	</param>
        ///	<returns type="String" />
        if (arguments.length > 0) {
            this._redirectUrl = arguments[0];
            var uploader = this._uploader;
            if (this._afterUpload) {
                uploader.events().afterUpload().remove(this._afterUpload);
                delete this._afterUpload;
            }
            if (this._redirectUrl) {
                var url = this._redirectUrl;
                this._afterUpload = function() {
                    wnd.location = url;
                }
                uploader.events().afterUpload().add(this._afterUpload);

            }
        } else {
            return this._redirectUrl;
        }
    },
    getParams: getParams
};

$au.upload.init = propertyMaker._typicalInit;
$au.upload.reinit = propertyMaker._typicalReinit;
$au.uploadErrorDialog = function() {
    ///	<summary>
    ///		Upload error dialog window.
    ///	</summary>
    ///	<returns type="$au.uploadErrorDialog" />
};
$au.uploadErrorDialog.prototype = {
    _simpleProperties: [
        { name: "title", getter: "getUploadErrorDialogTitle", setter: "setUploadErrorDialogTitle" },
        { name: "message", getter: "getUploadErrorDialogMessage", setter: "setUploadErrorDialogMessage" },
        { name: "showDetails", getter: "getUploadErrorDialogShowDetails", setter: "setUploadErrorDialogShowDetails" },
        { name: "hideDetails", getter: "getUploadErrorDialogHideDetails", setter: "setUploadErrorDialogHideDetails" }
    ],
    title: function(value) {
        ///	<summary>
        ///		Get or set title of the error dialog window
        ///	</summary>
        ///	<param name="value" type="String">
        ///     Title of the dialog
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    message: function(value) {
        ///	<summary>
        ///		Get or set upload error message
        ///	</summary>
        ///	<param name="value" type="String">
        ///     Error message
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    showDetails: function(value) {
        ///	<summary>
        ///		Get or set "Show details" button text
        ///	</summary>
        ///	<param name="value" type="String">
        ///     Show details button text
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    hideDetails: function(value) {
        ///	<summary>
        ///		Get or set "Hide details" button text
        ///	</summary>
        ///	<param name="value" type="String">
        ///     Hide details button text
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },
    getParams: getParams
};

$au.uploadErrorDialog.init = propertyMaker._typicalInit;
$au.uploadErrorDialog.reinit = propertyMaker._typicalReinit;
$au.imageUploaderFlash.fn = $au.imageUploaderFlash.prototype = {
    _simpleProperties: [
        { name: "id", isAttribute: true },
        { name: "width", isAttribute: true, defaultValue: "600px" },
        { name: "height", isAttribute: true, defaultValue: "400px" },
        { name: "licenseKey", getter: "getLicenseKey", setter: "setLicenseKey", renderOnly: true }
    ],
    _objectProperties: [
        { name: "flashControl", type: $au.flashControl },
        { name: "upload", type: $au.upload },
        { name: "events", type: $au.events },
        { name: "files", type: $au.files },
        { name: "restrictions", type: $au.restrictions },
        { name: "metadata", type: $au.metadata },
        { name: "topPanel", type: $au.topPanel },
        { name: "statusPanel", type: $au.statusPanel },
        { name: "listView", type: $au.listView },
        { name: "messages", type: $au.messages },
        { name: "imagePreviewWindow", type: $au.imagePreviewWindow },
        { name: "uploadErrorDialog", type: $au.uploadErrorDialog },
        { name: "commonDialog", type: $au.commonDialog },
        { name: "converters", type: $au.converters }
    ],
    _methods: [
        { name: "send", controlMethodName: "startUpload" },
        { name: "stop", controlMethodName: "stopUpload" }
    ],
    init: function(initObj) {

        this._uploader = this;

        // Init simple properties
        for (var i = 0, imax = this._simpleProperties.length; i < imax; i++) {
            propertyMaker.createSimpleProperty(this, this._simpleProperties[i]);
        }

        // Init object properties
        for (var i = 0, imax = this._objectProperties.length; i < imax; i++) {
            var property = this._objectProperties[i];
            if (property.type === $au.converters) {
                // special create logic for events and converters
                // Create new object for this property
                var convertersObj = new $au.converters();
                // init default value
                $au.converters.init(convertersObj, this);

                this[property.name] = function() {
                    if (arguments[0] instanceof Array) {
                        // remove old vales from array
                        convertersObj._converters.length = 0;
                        // and remove from actual control
                        while (convertersObj.count() > 0) {
                            convertersObj.remove(0);
                        }
                        //add new converters
                        for (var j = 0, jmax = arguments[0].length; j < jmax; j++)
                        {
                            convertersObj.add(arguments[0][j]);
                        }
                    } else {
                        return convertersObj;
                    }
                }
            } else {
                propertyMaker.createObjectProperty(this, property, this);
            }
        }

        //add InitComplete event to know that control rendered
        this.events().initComplete(function() {
            this.reinit();
        });

        trace('[js_trace] Start apply uploader init object.');
        this.set(initObj);
        trace('[js_trace] Finish apply uploader init object.');

    },
    reinit: function() {
        trace("[js_trace] Start control re-initialization.");
        var element = document.getElementById(this.id()), i, cnt;

        // fix scroll wheel
        var f = function(e) {
            if (typeof e.preventDefault === 'function') {
                e.preventDefault();
            }
            if (typeof e.stopPropagation === 'function') {
                e.stopPropagation();
            }
            e.returnValue = false;
            return false;
        };
        if (typeof element.attachEvent !== 'undefined') {
            element.attachEvent("onmousewheel", f);
        } else if (typeof element.addEventListener !== 'undefined') {
            element.addEventListener('DOMMouseScroll', f, false);
            element.addEventListener('mousewheel', f, false);
        }

        trace("[js_trace] Reinit control properties.");

        // Map uploader properties to the control
        if (this._simpleProperties) {
            for (var i = 0, imax = this._simpleProperties.length; i < imax; i++) {
                var property = this._simpleProperties[i];
                if (!property.isAttribute) {
                    propertyMaker.createControlProperty(this, property);
                } else {
                    propertyMaker.createAttributeProperty(this, property);
                }
            }
        }
        if (this._objectProperties) {
            for (var i = 0, imax = this._objectProperties.length; i < imax; i++) {
                var property = this._objectProperties[i];
                if (property.type && typeof property.type.reinit === 'function') {
                    property.type.reinit(this[property.name]());
                }
            }
        }

        //create methods
        trace("[js_trace] Creating methods.");
        if (this._methods && this._methods.length > 0) {
            for (var i = 0, imax = this._methods.length; i < imax; i++) {
                propertyMaker.createMethod(this, this._methods[i]);
            }
        }

        trace("[js_trace] Control re-initialization completed.");
        this.state(1);
    },
    state: function() {
        if (arguments.length > 0) {
            this._state = arguments[0];
        } else {
            return this._state;
        }
    },
    id: function(id) {
        ///	<summary>
        ///		Get or set control id
        ///	</summary>
        ///	<param name="id" type="String">
        ///		control id
        ///	</param>
        ///	<returns type="String" />

        /* will be created while initialization */
    },
    width: function(width) {
        ///	<summary>
        ///		Get or set control width            
        ///	</summary>
        ///	<param name="width" type="Number">
        ///		control width
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    height: function(height) {
        ///	<summary>
        ///		Get or set control height            
        ///	</summary>
        ///	<param name="height" type="Number">
        ///		control height
        ///	</param>
        ///	<returns type="Number" />
        /* will be created while initialization */
    },
    licenseKey: function(licenseKey) {
        ///	<summary>
        ///		Get or set license key
        ///	</summary>
        ///	<param name="licenseKey" type="String">
        ///		License key
        ///	</param>
        ///	<returns type="String" />
        /* will be created while initialization */
    },

    imagePreviewWindow: $au.imagePreviewWindow,
    listView: $au.listView,
    messages: $au.messages,
    statusPanel: $au.statusPanel,
    topPanel: $au.topPanel,
    flashControl: $au.flashControl,
    upload: $au.upload,
    events: $au.events,
    converters: $au.converters,
    restrictions: $au.restrictions,
    metadata: $au.metadata,
    files: $au.files,
    uploadErrorDialog: $au.uploadErrorDialog,
    commonDialog: $au.commonDialog,

    set: function(obj) {
        ///	<summary>
        ///		Set uploader properties
        ///	</summary>
        ///	<param name="obj" type="Object">
        ///		An object with uploader properties
        ///	</param>
        for (var name in obj) {
            if (typeof this[name] === 'function') {
                this[name](obj[name]);
            }
            else {
                showError('Uploader haven\'t ' + name + ' property.');
            }
        }
    },

    writeHtml: function() {
        wnd.document.write(this.getHtml());
    },

    getHtml: function() {
        var self = this, id = this.id(), events = this.events();

        /* create events function*/
        var createEventHandler = function(event, eventName) {
            return function() {
                var result1 = true;
                for (var f in event._handlers) {
                    try {
                        var handler = event._handlers[f];
                        var result;
                        if (typeof handler === 'function') {
                            result = handler.apply(self, arguments);
                        } else if (typeof wnd[handler] === 'function') {
                            result = wnd[handler].apply(self, arguments);
                        } else {
                            showError(eventName + " error:\n \"" + handler + "\" handler is not defined.");
                        }
                        if (eventName === 'beforeUpload' || eventName === 'afterPackageUpload') {
                            // for beforeUpload and afterPackageUpload events 
                            // we returns false if any event handler returns false or 0 
                            if (!result1) {
                                // already get false in prev handler
                                result = result1;
                            } else if (result !== UNDEF) {
                            // convert to boolean and save to temp var
                                result1 = (result === false || result === 0 ? false : true);
                            }
                        }
                    }
                    catch (err) {
                        showError(eventName + " error:\n" + (err.message || err.description || err));
                        throw err;
                    }
                }
                // return result from last handler
                return result;
            };
        };

        // fire preRender event
        if (events.preRender().count() > 0) {
            (createEventHandler(events.preRender(), 'preRender'))();
        }

        for (var i in events) {
            if (i != 'getParams' && i != 'preRender') {
                var event = events[i];
                if (typeof event === 'function' && event() instanceof $au.event && event().count() > 0) {
                    wnd[getGlobalHandlerName(this, i)] = createEventHandler(event(), i);
                }
            }
        }

        return flashRenderer(this).html();
    },

    getElement: function() {
        return wnd.document.getElementById(this.id());
    },

    getParams: function() {
        var params = getParams.call(this);

        //set debug options
        params.push({ name: 'debugMode', value: ($au.debug().debugLevel >= 3) });
        params.push({ name: 'traceToJS', value: $au.debug().traceToJS });

        return params;
    },

    send: function() {
        ///	<summary>
        ///		Upload selected images to server.
        ///	</summary>
    },

    stop: function() {
        ///	<summary>
        ///		Cancel upload images.
        ///	</summary>
    },

    registerCallback: function(name, callback, context) {
        this._clbs = this._clbs || {};
        this._clbs[name] = this._clbs[name] || [];
        this._clbs[name].push({ 'func': callback, 'ctx': context });
    },

    _invokeCallback: function(name, args) {
        if (!this._clbs || !this._clbs[name]) {
            return;
        }
        var clbs = this._clbs[name]
        for (var i = 0, imax = clbs.length; i < imax; i++) {
            var clb = clbs[i];
            clb.func.apply(clb.ctx, args);
        }
    }
};

// Give the init function the Aurigma.imageUploaderFlash prototype for later instantiation
$au.imageUploaderFlash.fn.init.prototype = $au.imageUploaderFlash.fn;
$au.event = function evt() {
    this._handlers = this._handlers || [];
    this.constructor = evt;
};

$au.event.prototype = {
    add: function(handler) {
        if (handler instanceof Array) {
            for (var i = 0, cnt = handler.length; i < cnt; i++)
                this._handlers.push(handler[i]);
        } else {
            this._handlers.push(handler);
        }
    },
    remove: function(handler) {
        for (var i in this._handlers) {
            if (this._handlers[i] === handler) {
                this._handlers.splice(i, 1);
                return true;
            }
        }
        return false;
    },
    clear: function() {
        this._handlers = [];
    },
    count: function() {
        return this._handlers.length;
    }
};
/*******************
** Flash renderer **
*******************/
var flashRenderer = function(uploader) {

    if (!uploader)
        return;

    //create browser specific flash uploader markup
    var getHtml = function() {

        //build string with uploader params
        function createUploaderParam() {
            var paramsArr = uploader.getParams();
            for (var i = 0, cnt = paramsArr.length; i < cnt; i++) {
                paramsArr[i] = paramsArr[i].name + '=' + paramsArr[i].value;
            }
            return paramsArr.join("&");
        };

        var codeBase = uploader.flashControl().codeBase();
        var v = uploader.flashControl().version();

        if (v) {
            // prevent browser cache swf with different version
            if (codeBase.indexOf('?') > -1) {
                codeBase = codeBase + '&version=' + v;
            } else {
                codeBase += '?version=' + v;
            }
        }

        var html = [], i, tagName, id = uploader.id(),
            flashVersionRequired = uploader.flashControl().flashVersionRequired.join(",");
        var attributes = {
            id: id,
            name: id,
            width: uploader.width(),
            height: uploader.height()
        };
        if (wnd.ActiveXObject) {
            // ActiveX supported, so we use clsid for classid attribute (Internet Explorer).
            attributes.classid = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
            attributes.codebase = "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version="
                + flashVersionRequired;
        } else {
            attributes.data = codeBase;
            attributes.type = "application/x-shockwave-flash";
        }
        var parameters = {
            quality: "high",
            bgcolor: uploader.flashControl().bgColor() || "#869ca7",
            allowScriptAccess: "always",
            flashvars: createUploaderParam() // most uploader params here
        };
        if (wnd.ActiveXObject) {
            parameters.movie = codeBase;
        }

        // invoke flashBeforeOpenTagRender callback
        var flashBeforeOpenTagRenderArgs = [uploader, { resultHtml: ''}], result;
        uploader._invokeCallback('flashBeforeOpenTagRender', flashBeforeOpenTagRenderArgs);
        // add before open tag html if any
        if (result = flashBeforeOpenTagRenderArgs[1].resultHtml) {
            html.push(result);
        }

        /*************************************
        * Use <object> tag for all browsers. *
        *************************************/

        var tagName = 'object';

        html.push('<' + tagName + ' ');

        // invoke flashRenderStyleAttribute callback
        var flashRenderStyleAttributeArgs = [uploader, { resultHtml: ''}], result;
        uploader._invokeCallback('flashRenderStyleAttribute', flashRenderStyleAttributeArgs);
        // add style attributes if any
        if (result = flashRenderStyleAttributeArgs[1].resultHtml) {
            html.push(' style="' + result + '" ');
        }

        for (var i in attributes) {
            if (!attributes.hasOwnProperty || attributes.hasOwnProperty(i)) {
                html.push(i + '="' + htmlencode(attributes[i]) + '" ');
            }
        }

        html.push('>');

        for (var i in parameters) {
            if (!parameters.hasOwnProperty || parameters.hasOwnProperty(i)) {
                html.push('<param name="' + i + '" value="' + htmlencode(parameters[i]) + '" /> ');
            }
        }

        // invoke flashBeforeCloseTagRender callback
        var flashBeforeCloseTagRenderArgs = [uploader, { resultHtml: ''}], result;
        uploader._invokeCallback('flashBeforeCloseTagRender', flashBeforeCloseTagRenderArgs);
        // add before close tag html if any
        if (result = flashBeforeCloseTagRenderArgs[1].resultHtml) {
            html.push(result);
        }

        html.push('</' + tagName + '>');

        // invoke flashAfterCloseTagRender callback
        var flashAfterCloseTagRenderArgs = [uploader, { resultHtml: ''}], result;
        uploader._invokeCallback('flashAfterCloseTagRender', flashAfterCloseTagRenderArgs);
        // add after close tag html if any
        if (result = flashAfterCloseTagRenderArgs[1].resultHtml) {
            html.push(result);
        }

        return html.join("");
    };

    return {
        html: getHtml,
        write: function() {
            ///	<summary>
            ///		write flash uploader markup
            ///	</summary>
            document.write(this.html());
        }
    };
};
})();

