/**
 * Ajax upload
 * Project page - http://valums.com/ajax-upload/
 * Copyright (c) 2008 Andris Valums, http://valums.com
 * Licensed under the MIT license (http://valums.com/mit-license/)
 * Version 2.1 (25.02.2009)
 */

(function(){
    
var d = document, w = window;

/**
 * Get element by id
 */    
function $(element){
    if (typeof element == "string")
        element = d.getElementById(element);
    return element;
}

/**
 * Attaches event to a dom element
 */
function addEvent(el, type, fn){
    if (w.addEventListener){
        el.addEventListener(type, fn, false);
    } else if (w.attachEvent){
        var f = function(){
          fn.call(el, w.event);
        };            
        el.attachEvent('on' + type, f)
    }
}


/**
 * Creates and returns element from html chunk
 */
var toElement = function(){
    var div = d.createElement('div');
    return function(html){
        div.innerHTML = html;
        var el = div.childNodes[0];
        div.removeChild(el);
        return el;
    }
}();

function hasClass(ele,cls){
    return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
    if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
    var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
    ele.className=ele.className.replace(reg,' ');
}

function getOffset(el){
    if (w.jQuery){
        return jQuery(el).offset();
    }
            
    var top = 0, left = 0;
    do {
        top += el.offsetTop  || 0;
        left += el.offsetLeft || 0;
    } while (el = el.offsetParent);
                    
    return {
        left : left,
        top : top
    };
}

function getBox(el){
    var left, right, top, bottom;    
    var offset = getOffset(el);
    left = offset.left;
    top = offset.top;
    right = left + el.offsetWidth;
    bottom = top + el.offsetHeight;        
            
    return {
        left: left,
        right: right,
        top: top,
        bottom: bottom
    };
}

/**
 * Crossbrowser mouse coordinates
 */
function getMouseCoords(e){        
    // pageX/Y is not supported in IE
    // http://www.quirksmode.org/dom/w3c_cssom.html            
    if (!e.pageX && e.clientX){
        return {
            x: e.clientX + d.body.scrollLeft + d.documentElement.scrollLeft,
            y: e.clientY + d.body.scrollTop + d.documentElement.scrollTop
        };
    }
    
    return {
        x: e.pageX,
        y: e.pageY
    };        

}
/**
 * Function generates unique id
 */        
var getUID = function(){
    var id = 0;
    return function(){
        return 'ValumsAjaxUpload' + id++;
    }
}();

function fileFromPath(file){
    return file.replace(/.*(\/|\\)/, "");            
}

function getExt(file){
    return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
}    
        

    // Please use AjaxUpload , Ajax_upload will be removed in the next version
    Ajax_upload = AjaxUpload = function(button, options){
        if (button.jquery){
            // jquery object was passed
            button = button[0];
        } else if (typeof button == "string" && /^#.*/.test(button)){                    
            button = button.slice(1);                
        }
        button = $(button);    
        
        this._input = null;
        this._button = button;
        this._disabled = false;
        this._submitting = false;
                
        this._settings = {
            // Location of the server-side upload script
            action: 'upload.php',            
            // File upload name
            name: 'userfile',
            // Additional data to send
            data: {},
            // Submit file as soon as it's selected
            autoSubmit: true,
            // When user selects a file, useful with autoSubmit disabled            
            onChange: function(file, extension){},                    
            // Callback to fire before file is uploaded
            // You can return false to cancel upload
            onSubmit: function(file, extension){},
            // Fired when file upload is completed
            onComplete: function(file, response) {}
        };

        // Merge the users options with our defaults
        for (var i in options) {
            this._settings[i] = options[i];
        }
        
        this._createInput();
        this._rerouteClicks();
    }
        
// assigning methods to our class
AjaxUpload.prototype = {
    setData : function(data){
        this._settings.data = data;
    },
    disable : function(){
        this._disabled = true;
    },
    enable : function(){
        this._disabled = false;
    },
    // use setData instead, set_data will be removed in the next version
    set_data : function(data){
        this.setData(data);
    },
    // removes ajaxupload
    destroy : function(){
        if(this._input){
            if(this._input.parentNode){
                this._input.parentNode.removeChild(this._input);
            }
            this._input = null;
        }
    },                
    /**
     * Creates invisible file input above the button 
     */
    _createInput : function(){
        var self = this;
        
        var input = d.createElement("input");
        input.setAttribute('type', 'file');
        input.setAttribute('name', this._settings.name);
        var styles = {
            'position' : 'absolute'
            ,'margin': '-5px 0 0 -175px'
            ,'padding': 0
            ,'width': '220px'
            ,'height': '10px'                                
            ,'opacity': 0
            ,'cursor': 'pointer'
            ,'display' : 'none'
            ,'zIndex' : 2147483647                            
        };
        for (var i in styles){
            input.style[i] = styles[i];
        }
        
        // Make sure that element opacity exists
        // (IE uses filter instead)
        if ( ! (input.style.opacity === "0")){
            input.style.filter = "alpha(opacity=0)";
        }                    
        d.body.appendChild(input);    
        
        addEvent(input, 'change', function(){
            // get filename from input
            var file = fileFromPath(this.value);    
            if(self._settings.onChange.call(self, file, getExt(file)) == false ){
                return;                
            }                                                        
            // Submit form when value is changed
            if (self._settings.autoSubmit){
                self.submit();                        
            }                        
        });
        
        this._input = input;
    },
    _rerouteClicks : function (){
        var self = this;
    
        // IE displays 'access denied' error when using this method
        // other browsers just ignore click()
        // addEvent(this._button, 'click', function(e){
        //   self._input.click();
        // });                

        var box, over = false;            
        addEvent(self._button, 'mouseover', function(e){
            if (!self._input || over) return;
            over = true;
            box = getBox(self._button);                                
        });
        
        // we can't use mouseout on the button,
        // because invisible input is over it
        addEvent(document, 'mousemove', function(e){
            var input = self._input;
            if (!input || !over) return;
            if (self._disabled){
                removeClass(self._button, 'hover');
                input.style.display = 'none';
                return;
            }    
                                        
            var c = getMouseCoords(e);
                    
            if ((c.x >= box.left) && (c.x <= box.right) && 
            (c.y >= box.top) && (c.y <= box.bottom)){
            
                input.style.top = c.y + 'px';
                input.style.left = c.x + 'px';
                input.style.display = 'block';
                addClass(self._button, 'hover');                
            } else {        
                // mouse left the button
                over = false;
                input.style.display = 'none';
                removeClass(self._button, 'hover');
            }            
        });            
            
    },
    /**
     * Creates iframe with unique name
     */
    _createIframe : function(){
        // unique name
        // We cannot use getTime, because it sometimes return
        // same value in safari :(
        var id = getUID();
        
        // Remove ie6 "This page contains both secure and nonsecure items" prompt 
        // http://tinyurl.com/77w9wh
        var iframe = toElement('<iframe src="javascript:false;" name="' + id + '" />');
        iframe.id = id;
        iframe.style.display = 'none';
        d.body.appendChild(iframe);            
        return iframe;                        
    },
    /**
     * Upload file without refreshing the page
     */
    submit : function(){
        var self = this, settings = this._settings;    
                    
        if (this._input.value === ''){
            // there is no file
            return;
        }
                                        
        // get filename from input
        var file = fileFromPath(this._input.value);            

        // execute user event
        if (! (settings.onSubmit.call(this, file, getExt(file)) == false)) {
            // Create new iframe for this submission
            var iframe = this._createIframe();
            
            // Do not submit if user function returns false                                        
            var form = this._createForm(iframe);
            form.appendChild(this._input);

            form.submit();        

            d.body.removeChild(form);                
            form = null;
            this._input = null;
            
            // create new input
            this._createInput();
            
            var toDeleteFlag = false;
            addEvent(iframe, 'load', function(){
                if (iframe.src == "about:blank"){                        
                    // First time around, do not delete.
                    if( toDeleteFlag ){
                        // Fix busy state in FF3
                        setTimeout( function() {
                            d.body.removeChild(iframe);
                        }, 0);
                    }
                    return;
                }                
                
                var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;
                var response = doc.body.innerHTML;
                                    
                settings.onComplete.call(self, file, response);
                
                // Reload blank page, so that reloading main page
                // does not re-submit the post. Also, remember to
                // delete the frame
                toDeleteFlag = true;                
                iframe.src = "about:blank"; //load event fired                                    
            });
    
        } else {
            // clear input to allow user to select same file
            this._input.value = '';                        
        }
    },        
    /**
     * Creates form, that will be submitted to iframe
     */
    _createForm : function(iframe){
        var settings = this._settings;
        
        // method, enctype must be specified here
        // because changing this attr on the fly is not allowed in IE 6/7        
        var form = toElement('<form method="post" enctype="multipart/form-data"></form>');
        form.style.display = 'none';
        form.action = settings.action;
        form.target = iframe.name;
        d.body.appendChild(form);
        
        // Create hidden input element for each data key
        for (var prop in settings.data){
            var el = d.createElement("input");
            el.type = 'hidden';
            el.name = prop;
            el.value = settings.data[prop];
            form.appendChild(el);
        }            
        return form;
    }    
};



})();