(function($) {
    $.messageBox = function(settings){
        var obj = new $.fn.messageBox(settings);
        obj.__initialize(null,settings);
        return obj;
    }
    $.fn.messageBox = function(settings){
        if($.isFunction(this.each)){
            this.each(function() {
                if($(this).data('messageBox.instance') == undefined){
                    $(this).data('messageBox.instance', new $.fn.messageBox());
                    $(this).data('messageBox.instance').__initialize(this,settings);
                }
            });
        }
        return $(this).data('messageBox.instance');
   }
   $.extend($.fn.messageBox.prototype, {
        options:{},
        messageObject:null,
        titleObject:null,
        bodyObject:null,
        parentObject:null,        
        containerDimmesion:null,
        overlayObject:null,
        isVisible:false,
        messageTimeout:null,
        messageThread:null,
        isAutoCloseCaller:false,
        actionsEnabled:true,
        userData:{},
        __initialize:function(parentObject, options){
            this.options = this.__mergeOptions(options);
            this.actionsEnabled = true;
            if($(parentObject).size() == 1){
                this.parentObject = $(parentObject).css('position','relative');
            } else this.parentObject = $('body');
            this.containerDimmesion = {'width':null,'height':null};
            this.__createMessageObject();
        },
        __createMessageObject:function(){
            if(isObject(this.options.overlay)){
                this.overlayObject = $('<div></div>');
                this.overlayObject.css({'display':'none','position':'absolute','z-index':this.options.zIndex,'left':'0px','top':'0px','opacity':this.options.overlay.opacity,'background-color':this.options.overlay.color});
                this.parentObject.append(this.overlayObject);
            }
            this.messageObject = $(this.options.messageBoxHtml)
            this.messageObject.css({'display':'none','position':'absolute','z-index':this.options.zIndex+1});
            this.parentObject.append(this.messageObject).end();           
            this.titleObject = this.messageObject.find(this.options.titleSelector);
            this.bodyObject = this.messageObject.find(this.options.bodySelector);
            if(!isUndefined(this.options.title)) this.setTitle(this.options.title);
            if(!isUndefined(this.options.body)) this.setBody(this.options.body);            
            if(this.options.window.centerX || this.options.window.centerY){
                $(window).scroll((function(){this.__center();}).bind(this));
            }            
            $(window).resize((function(){this.__resize();}).bind(this));            
            if(isObject(this.options.actions)){
                for(action in this.options.actions){
                    this.messageObject.find(action).bind('click',(function(event){
                        if(!this.self.actionsEnabled) return false;
                        try{return this.self.options.actions[this.action](this.self, event );}catch(e){}
                        return true;
                    }).bind({'self':this,action:action}));
                }
            }
        },
        setTitle:function(title){
            this.options.title = title;
            this.titleObject.html(this.options.title);
            return this;
        },
        setBody:function(body){
            this.options.body = body;
            this.bodyObject.html(this.options.body);
            return this;
        },
        setTimeout:function(timeout){
            if(isNumber(timeout) && timeout > 0){
                this.messageTimeout = timeout;
                if(this.isVisible) this.__callThreads();
            } else {
                if(!isNull(this.messageThread)) clearTimeout(this.messageThread);
                this.messageTimeout = null;
            }
            return this;
        },
        setData:function(key, data){
            this.userData[key] = data;
            return this;
        },
        getData:function(key){
            if(!isNull(this.userData[key])) return this.userData[key]; else return null;
        },
        unsetData:function(key){
            if(!isNull(this.userData[key])) this.userData[key]= null;
            return this;
        },
        getOverlay:function(){
            return this.overlayObject;
        },
        getMessageHtml:function(){
            return this.options.body;
        },
        enableActions:function(enabled){
            this.actionsEnabled = enabled;
            for(action in this.options.actions){
                if(this.actionsEnabled)
                    this.messageObject.find(action).removeClass('disabled');
                else
                    this.messageObject.find(action).addClass('disabled');
            }
            return this;
        },
        actionsIsEnabled:function(){
            return this.actionsEnabled;
        },
        getMessageBodyObejct:function(){
            return this.bodyObject;
        },
        showMessage:function(titleHtml, bodyHtml){
            if(!isUndefined(titleHtml)) this.setTitle(titleHtml);
            if(!isUndefined(bodyHtml)) this.setBody(bodyHtml);
            if(this.options.waitForReady){
                $(document).ready((function(){this.__showMessage();}).bind(this));
            } else this.__showMessage();
            return this;
        },
        hideMessage:function(){
            if(!this.isVisible) return this;
            if($.isFunction(this.options.beforeHideMessageFn)){
                 try{
                     forceVisible = this.options.beforeHideMessageFn(this,this.isAutoCloseCaller);
                     this.isAutoCloseCaller = false;
                     if(!isUndefined(forceVisible) && forceVisible) return this;
                }catch(e){}
            }
            if((this.options.animations.onClose && !this.isAutoCloseCaller) || (this.options.animations.onAutoClose && this.isAutoCloseCaller)){
                $(this.overlayObject).fadeOut();
                this.messageObject.fadeOut((function(){this.__hideMessage();}).bind(this));
            } else {
                this.__hideMessage();
            }
            return this;
        },
        __hideMessage:function(){
            if(!isNull(this.messageThread)) clearTimeout(this.messageThread);
            if(!this.isVisible) return;
            $(this.overlayObject).css('display','none');
            this.messageObject.css('display','none');
            this.isVisible = false;
            this.isAutoCloseCaller = false;
        },
        __showMessage:function(){
            if(this.isVisible) return;
            this.__silentlyMeasMessage();
            var coords = this.__getCoordinates();
            this.messageObject.css({'left':coords[0]+'px','top':coords[1]+'px'});
            $(this.overlayObject).css({'width':this.parentObject.width(),'height':this.parentObject.height(),'display':'block'});
            if($.isFunction(this.options.beforeShowMessageFn)){
                try{this.options.beforeShowMessageFn(this);}catch(e){}
            }
            if(this.options.animations.onShow){
                this.messageObject.fadeIn((function(){this.__resize();this.__messageCoordsTrigger();this.isVisible = true;this.__callThreads();}).bind(this));
            } else {
                this.__resize();
                this.messageObject.show();
                this.__messageCoordsTrigger();
                this.isVisible = true;
                this.__callThreads();
            }
        },
        __callThreads:function(){
            if(isNumber(this.messageTimeout)){
                this.messageThread = setTimeout((function(){this.isAutoCloseCaller = true;this.hideMessage();}).bind(this),this.messageTimeout);
            }
        },
        __center:function(){            
             if(this.isVisible){
                 var objectSize = this. __getSize();
                 var objectCoords = {};
                 var jWindow = $(window);
                 if(this.options.window.centerY) objectCoords['top'] = ((jWindow.height()-objectSize[1])/2+jWindow.scrollTop())+'px';
                 if(this.options.window.centerX) objectCoords['left'] = ((jWindow.width()-objectSize[0])/2+jWindow.scrollLeft())+'px';
                 if($.isFunction(this.options.beforeScrollingFn)){
                    try{this.options.beforeScrollingFn(this);}catch(e){}
                 }      
                 if(isObject(this.options.animations.onChangeCoordinates))
                     this.messageObject.animate(objectCoords, this.options.animations.onChangeCoordinates);
                 else
                      this.messageObject.css(objectCoords);                   
             }
        },
        __resize:function(){            
             if(this.isVisible){
                 var objectSize = this. __getSize();
                 $(this.overlayObject).css({'width':this.parentObject.width(),'height':this.parentObject.height()});
                 var coords = this.__getCoordinates(objectSize);                 
                 if($.isFunction(this.options.beforeResizeMessageFn)){
                    try{coords = this.options.beforeResizeMessageFn(this, coords);}catch(e){}
                 }                 
                 var objectCoords = {'left':coords[0]+'px','top':coords[1]+'px'};                 
                 if(isObject(this.options.animations.onChangeCoordinates))
                     this.messageObject.animate(objectCoords, this.options.animations.onChangeCoordinates);
                 else
                      this.messageObject.css(objectCoords);   
             }
        },
        __messageCoordsTrigger:function(){           
            if(isNumber(this.options.coordsTriggerDalay) && this.options.coordsTriggerDalay > 0){
                this.messageThread = setTimeout((function(){                    
                    var objectSize = this. __getSize();
                    $(this.overlayObject).css({'width':this.parentObject.width(),'height':this.parentObject.height()});
                    var coords = this.__getCoordinates(objectSize);
                    if(isNull(this.containerDimmesion['lastMessageCords']) || (coords[0] != this.containerDimmesion['lastMessageCords'][0] || coords[1] != this.containerDimmesion['lastMessageCords'][1])){
                         if(isObject(this.options.animations.onChangeCoordinates))
                             this.messageObject.animate(coords, this.options.animations.onChangeCoordinates);
                         else
                              this.messageObject.css(coords);
                    }                    
                    this.containerDimmesion['lastMessageCords'] = coords;
                    this.__messageCoordsTrigger();
                }).bind(this),this.options.coordsTriggerDalay);
            }
        },
        __getCoordinates:function(objectSize){
            objectSize = !isObject(objectSize)?this.__getSize():objectSize;
            var jWindow = $(window);
            return [this.options.window.centerX?(jWindow.width()-objectSize[0])/2+jWindow.scrollLeft():(this.parentObject.width()-objectSize[0])/2,this.options.window.centerY?(jWindow.height()-objectSize[1])/2+jWindow.scrollTop():(this.parentObject.height()-objectSize[1])/2,];
        },
        __getSize:function(){
            this.messageObject.width(this.containerDimmesion.width);this.messageObject.height(this.containerDimmesion.height);
            return [this.containerDimmesion.width, this.containerDimmesion.height];
        },
        __silentlyMeasMessage:function(){
            if(isNumber(this.options.width) && this.options.width > 0 && isNumber(this.options.height) && this.options.height > 0){
                this.containerDimmesion = {'width': this.options.width, 'height': this.options.height};return;
            }
            this.messageObject.css({'visibility':'visible','display':'block'})
            this.containerDimmesion.width = (!isNumber(this.options.width) || this.options.width < 0)?this.messageObject.width(): this.options.width;
            var currentContainerWidth = this.messageObject.width();
            this.messageObject.width(this.containerDimmesion.width);
            this.containerDimmesion.height = (!isNumber(this.options.height) || this.options.height < 0)?this.messageObject.height():this.options.height;
            this.messageObject.width(currentContainerWidth);
            this.messageObject.css({'display':'none','visibility':'visible'});
        },
        __mergeOptions:function(options){
            var defaults = jQuery.extend({messageBoxHtml:null, titleSelector:null, bodySelector:null, title:null, body:null, width:null, height:null, coordsTriggerDalay:false, zIndex:10, beforeShowMessageFn:null, beforeHideMessageFn:null, beforeResizeMessageFn:null, beforeScrollingFn:null, waitForReady:true, window:{centerX:true, centerY:true} ,animations:{onShow:true, onClose:true, onAutoClose:true, onChangeCoordinates:null}, overlay:{opacity:1, color:null}, actions:{}},options);
            if(isObject(options.overlay)) defaults.overlay = jQuery.extend(defaults.overlay,options.overlay);
            if(isObject(options.actions)) defaults.actions = jQuery.extend(defaults.actions,options.actions);
            if(isObject(options.window)) defaults.window = jQuery.extend(defaults.window,options.window);
            if(isObject(options.animations)) defaults.animations = jQuery.extend(defaults.animations,options.animations);
            return defaults;
        }
  });
})(jQuery);
