(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,
        isWindowAttached:false,
        onScrollAnimate:false,
        scrollHasChanges:false,
        windowObject: null,
        documentObject:null,
        userData:{},
        __initialize:function(parentObject, options){
            this.options = this.__mergeOptions(options);
            this.windowObject = $(window);
            this.isWindowAttached = $(parentObject).size() == 0;
            this.parentObject = this.isWindowAttached?this.parentObject = $('body'):$(parentObject).css('position','relative');
            this.containerDimmesion = {'width':null,'height':null};
            this.__createMessageObject();
        },
        __createMessageObject:function(){
            if(this.__isObject(this.options.overlay)){
                this.overlayObject = $('<div></div>').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).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(!this.__isUndefined(this.options.title)) this.setTitle(this.options.title);
            if(!this.__isUndefined(this.options.body)) this.setBody(this.options.body);
            if(this.options.position.scrollX || this.options.position.scrollY){
                $(window).scroll((function(){this.__scrolling();}).bind(this));
            }
            this.windowObject.resize((function(){this.__resize();}).bind(this));
            if(this.__isObject(this.options.actions)){
                for(action in this.options.actions){
                    this.messageObject.find(action).data('messageBox.instance.event.enabled',true).bind('click',(function(event){
                        if(!$(event.target).data('messageBox.instance.event.enabled')) 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(this.__isNumber(timeout) && timeout > 0){
                this.messageTimeout = timeout;
                if(this.isVisible) this.__callThreads();
            } else {
                if(!this.__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(!this.__isNull(this.userData[key])) return this.userData[key]; else return null;
        },
        unsetData:function(key){
            if(!this.__isNull(this.userData[key])) this.userData[key]= null;
            return this;
        },
        getOverlayObject:function(){
            return this.overlayObject;
        },
        getMessageHtml:function(){
            return this.options.body;
        },
        getMessageBodyObejct:function(){
            return this.bodyObject;
        },
        enableAction:function(enabled, actionSelector){
            for(action in this.options.actions){
                if((!this.__isNull(actionSelector) && action == actionSelector) || this.__isNull(actionSelector)){
                    if(enabled){
                        this.messageObject.find(action).data('messageBox.instance.event.enabled',true).removeClass('disabled');
                    }else{
                        this.messageObject.find(action).data('messageBox.instance.event.enabled',false).addClass('disabled');
                    }
                }
            }
            return this;
        },
        showMessage:function(titleHtml, bodyHtml){
            if(!this.__isUndefined(titleHtml)) this.setTitle(titleHtml);
            if(!this.__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{
                     this.options.beforeHideMessageFn(this, this.isAutoCloseCaller);
                     this.isAutoCloseCaller = false;
                }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(!this.__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 parentSize = this.__getMessageParentSize();
            var overlaySize = this.isWindowAttached?[$(document).width(),$(document).height()]:parentSize;
            $(this.overlayObject).css({'width':overlaySize[0],'height':overlaySize[1],'display':'block'});
            var coords = this.__getMessageCoordinates(parentSize);
            this.messageObject.css({'left':coords[0]+'px','top':coords[1]+'px'});
            if($.isFunction(this.options.beforeShowMessageFn)){
                try{this.options.beforeShowMessageFn(this);}catch(e){}
            }
            if(this.options.animations.onShow){
                this.messageObject.fadeIn((function(){this.__resize();this.isVisible = true;this.__callThreads();}).bind(this));
            } else {
                this.__resize();
                this.messageObject.show();
                this.isVisible = true;
                this.__callThreads();
            }
        },
        __callThreads:function(){
            if(this.__isNumber(this.messageTimeout)){
                this.messageThread = setTimeout((function(){this.isAutoCloseCaller = true;this.hideMessage();}).bind(this),this.messageTimeout);
            }
        },
        __scrolling:function(){
             if(this.isVisible){
                var parentSize = this.__getMessageParentSize();
                var overlaySize = this.isWindowAttached?[$(document).width(),$(document).height()]:parentSize;
                $(this.overlayObject).css({'width':overlaySize[0],'height':overlaySize[1],'display':'block'});
                var coords = this.__getMessageCoordinates(parentSize);
                if(!this.options.animations.onScrolling){
                    this.messageObject.css({'left':coords[0]+'px','top':coords[1]+'px'});
                    if($.isFunction(this.options.affterChangeMessagePosition)){
                        try{this.options.affterChangeMessagePosition(this, coords);}catch(e){}
                    }
                } else if(this.options.scrollAnimation.standart){
                    this.messageObject.animate({'left':coords[0]+'px','top':coords[1]+'px'},50);
                }else {
                    if(!this.onScrollAnimate){
                        this.onScrollAnimate = true; this.scrollHasChanges = false;
                        this.messageObject.fadeOut(this.options.scrollAnimation.fadeOut,(function(){
                            var coords = this.self.__getMessageCoordinates(this.parentSize);
                            this.self.messageObject.css({'left':coords[0]+'px','top':coords[1]+'px'});
                            if(!this.onScrollAnimate){
                                this.self.messageObject.fadeIn(this.self.options.scrollAnimation.fadeIn,(function(){
                                    this.messageObject.css('opacity',1);
                                    if(this.scrollHasChanges){
                                        var coords = this.__getMessageCoordinates();
                                        if(coords[0] !=  parseFloat(this.messageObject.css('left')) || coords[1] !=  parseFloat(this.messageObject.css('top'))){
                                            this.messageObject.fadeOut(this.options.scrollAnimation.fadeOut,(function(){
                                                var coords = this.__getMessageCoordinates();
                                                this.messageObject.css({'left':coords[0]+'px','top':coords[1]+'px'}).fadeIn(this.options.scrollAnimation.fadeIn,(function(){
                                                    this.messageObject.css('opacity',1);
                                                }).bind(this));
                                            }).bind(this));
                                        }
                                    }
                                    this.onScrollAnimate = false;
                                }).bind(this.self));
                            }
                            if($.isFunction(this.self.options.affterChangeMessagePosition)){
                                try{this.self.options.affterChangeMessagePosition(this.self, coords);}catch(e){console.debug(e);}
                            }
                        }).bind({'self':this, 'parentSize':parentSize}));
                    } else if(this.options.scrollAnimation.triging) {
                        this.messageObject.css({'left':coords[0]+'px','top':coords[1]+'px'});
                    } else {
                        this.scrollHasChanges = true;
                    }
                }
             }
        },
        __resize:function(){
             if(this.isVisible){
                $(this.overlayObject).hide();$(this.messageObject).hide();
                var parentSize = this.__getMessageParentSize();
                var overlaySize = this.isWindowAttached?[$(document).width(),$(document).height()]:parentSize;
                $(this.overlayObject).css({'width':overlaySize[0],'height':overlaySize[1],'display':'block'}).show();
                var coords = this.__getMessageCoordinates(parentSize);
                this.messageObject.css({'left':coords[0]+'px','top':coords[1]+'px'}).show();
                if($.isFunction(this.options.affterChangeMessagePosition)){
                    try{this.options.affterChangeMessagePosition(this, coords);}catch(e){}
                }
             }
        },
        __getMessageCoordinates:function(parentObjectSize, messageObjectSize){
             parentObjectSize = this.__isNull(parentObjectSize)?this.__getMessageParentSize():parentObjectSize;
             messageObjectSize = this.__isNull(messageObjectSize)?this.__getMessageSize():messageObjectSize;
             var messageCoords = [(this.__isNumber(this.options.position.x)?this.options.position.x:(parentObjectSize[0]-messageObjectSize[0])/2)+(this.options.position.scrollX?this.windowObject.scrollLeft():0),(this.__isNumber(this.options.position.y)?this.options.position.y:(parentObjectSize[1]-messageObjectSize[1])/2)+(this.options.position.scrollY?this.windowObject.scrollTop():0)];
             if(this.isWindowAttached) return messageCoords;
             messageCoords = [Math.max(Math.min(messageCoords[0], parentObjectSize[0]-messageObjectSize[0]),0),Math.max(Math.min(messageCoords[1], parentObjectSize[1]-messageObjectSize[1]),0)];
             var position = $(this.parentObject).position();
             if(!this.__isNumber(this.options.position.x) && this.options.position.scrollX)
                messageCoords[0] =  Math.max(Math.min((Math.min(this.windowObject.width()-position.left,parentObjectSize[0])-messageObjectSize[0]) / 2 + this.windowObject.scrollLeft(), parentObjectSize[0]-messageObjectSize[0]),0);
            if(!this.__isNumber(this.options.position.y) && this.options.position.scrollY)
                messageCoords[1] = Math.max(Math.min((Math.min(this.windowObject.height()-position.top,parentObjectSize[1])-messageObjectSize[1]) / 2 + this.windowObject.scrollTop(), parentObjectSize[1]-messageObjectSize[1]),0);
             return messageCoords;
        },
        __getMessageParentSize:function(){
            return [this.isWindowAttached?this.windowObject.width():this.parentObject.width(),this.isWindowAttached?this.windowObject.height():this.parentObject.height()];
        },
        __getMessageSize:function(){
            this.messageObject.width(this.containerDimmesion.width);this.messageObject.height(this.containerDimmesion.height);
            return [this.containerDimmesion.width, this.containerDimmesion.height];
        },
        __silentlyMeasMessage:function(){
            if(this.__isNumber(this.options.width) && this.options.width > 0 && this.__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 = (!this.__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 = (!this.__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 = {messageBoxHtml:null, titleSelector:null, bodySelector:null, title:null, body:null, width:null, height:null, zIndex:10, beforeShowMessageFn:null, beforeHideMessageFn:null, affterChangeMessagePosition:null, waitForReady:true, position:{x:null, y:null, scrollX:true, scrollY:true} ,animations:{onShow:true, onClose:true, onAutoClose:true, onScrolling:true},scrollAnimation:{standart:false,fadeOut:300,fadeId:200, triging: false}, overlay:{opacity:1, color:null}, actions:{}};
            if(this.__isObject(options.overlay)) options.overlay = jQuery.extend(defaults.overlay,options.overlay);
            if(this.__isObject(options.actions)) options.actions = jQuery.extend(defaults.actions,options.actions);
            if(this.__isObject(options.position)) options.position = jQuery.extend(defaults.position,options.position);
            if(this.__isObject(options.animations)) options.animations = jQuery.extend(defaults.animations,options.animations);
            if(this.__isObject(options.scrollAnimation)) options.scrollAnimation = jQuery.extend(defaults.scrollAnimation,options.scrollAnimation);
            return jQuery.extend(defaults,options);
        },
        __isNull:function(object){
            return object == null || object == undefined;
        },
        __isUndefined:function(object){
            return object == undefined;
        },
        __isObject:function(object){
            return !this.__isNull(object) && object.constructor.toString().indexOf("Object") != -1;
        },
        __isNumber:function(object){
           return !this.__isNull(object) && (/^-{0,1}\d*\.{0,1}\d+$/.test(object.toString()))
        }
  });
})(jQuery);
