/*
 *  
 * jQuery extensions by plentySystems
 * 
 *
 * 
 * HowTo ...
 * 
 * ...definine a custom function:
 * 
 * jQuery.fn.FUNCTIONNAME = function()
 *                          {
 *                              return jQuery(this).each(
 *                                  function()
 *                                  {
 *                                      // "jQuery(this)" is the jquery object
 *                                      jQuery(this).doSomething();
 *                                  });
 *                          };
 * 
 */


/*
 * Lets element(s) blink
 */
jQuery.fn.blink =   function(iBlinkCount)
                    {
                        return jQuery(this).each(
                            function()
                            {
                                // speed in ms
                                var speed = 250;
                                
                                // count of blinks
                                if(iBlinkCount > 0)
                                {
                                    var count = iBlinkCount;
                                }
                                else
                                {
                                    var count = 3;
                                }
                                
                                for(var i=0;i<count;i++)
                                {
                                    this.fadeOut(speed).fadeIn(speed);
                                }
                            });
                    };

/*
 * Move element(s) to center (chainable), centers both on param unset
 */
jQuery.fn.center =  function (from)
                    {
                        return jQuery(this).each(
                            function()
                            {
                                // top pos
                                var top     = (jQuery(window).height() - jQuery(this).height()) / 2 + jQuery(window).scrollTop() + "px";
                                // left pos
                                var left    = (jQuery(window).width() - jQuery(this).width()) / 2 + jQuery(window).scrollLeft() + "px";
                                
                                switch(from)
                                {
                                // adjust top
                                case 'top':
                                    jQuery(this).css("top", top);
                                    break;
                                    // adjust left
                                case 'left':
                                    jQuery(this).css("left", left);
                                    break;
                                    // default adjust both
                                default:
                                    jQuery(this).css("top", top);
                                jQuery(this).css("left", left);
                                break;
                                }
                            });
                    };

/*
 * Applies a for the document unique id to element(s)
 */
jQuery.fn.setUniqueId = function(prefix)
                        {
                            return jQuery(this).each(
                                function()
                                {
                                    var sUniqueId = '';
                                    var sUniqueId = '';
                                    var iMultiplier = 3;
                                    var iRandomNum  = 0;
                                    
                                    var elExists = true;
                                    
                                    // set default id
                                    if(!prefix)
                                    {
                                        prefix = 'id_';
                                    }
                                    
                                    do
                                    {
                                        // get more room for new IDs on repeat
                                        iMultiplier++;
                                        // get random number
                                        iRandomNum = Math.ceil(Math.random() * iMultiplier);
                                        
                                        // build new id
                                        sUniqueId = prefix + iRandomNum;
                                    }
                                    // repeat if id already exists
                                    while(jQuery('#'+sUniqueId).exists());
                                    
                                    // set id to element
                                    this.attr('id', sUniqueId);
                                });
                        };

/**
 * Extending the jQuery namespace by defining a new function jQuery.plentyRequest() for AJAX calls
 * (estafilarakis)
 */
jQuery.extend({
    plentyRequest : plentyAjaxRequest2
});

/**
 * 
 * Custom effect for tabs
 */
jQuery.tools.tabs.addEffect(    "plenty_tabs",
                        function(tabIndex, done)
                        {
                            this.getPanes()
                                // slide up all panes
                                .slideUp("slow")
                                // get the selected tab
                                .eq(tabIndex)
                                // slide down the selected
                                .slideDown("slow");
                            
                            // effect is done
                            done.call();
                        });

/*
 * Custom datepicker
 */
jQuery.fn.plentyDateInput =     function() 
                                {
                                    return this.each(   function()
                                                        {
                                                             jQuery(this).dateinput({
                                                                                format: "dd.mm.yyyy ",
                                                                                selectors: true,                
                                                                                min: -1
                                                                                });
                                                        });
                                };


/**
 * New plugin 'plentyPortlet'.
 * 
 * The HTML structur should be:
 * <div class="PlentyGuiHeaderPane">
 *     <div class="PlentyGuiHeader">...</div>
 *     <div class="PlentyGuiContent">...</div>
 * </div>
 * 
 * The javascript call to build the portlet is:
 * jQuery(".PlentyGuiHeaderPane").plentyPortlet();
 * 
 * The plugin adds a button with the CSS class 'PlentyGuiPortletButton'
 * to open and close the content of the portlet.
 * 
 * @author estafilarakis@plentySystems
 * 
 */
jQuery.fn.plentyPortlet = function(conf) {
    if(typeof(conf) != "object")
    {
        conf = { opened : false };
    }
    return this.each(function(){
        var button = jQuery('<div class="PlentyGuiPortletButton">&nbsp;</div>');
        var portlet = jQuery(this);
        var portletContent = portlet.find('> .PlentyGuiContent');
        if(conf.opened == true || conf.opened == "true")
        {
            portletContent.addClass("PortletFirstOpened");
        }
        portlet.
            addClass('PlentyGuiPortlet').
            find('> .PlentyGuiContent').
                addClass('PlentyGuiPortletContent').
                end().
            find('> .PlentyGuiHeader').
                addClass('PlentyGuiPortletHeader').
                before(button);
        button.toggle(
                function(){
                    jQuery(this).addClass('PlentyGuiPortletOpened');
                    portletContent.slideDown();
                    if(typeof(conf.onOpen) == 'function')
                    {
                        conf.onOpen(portlet.find('> .PlentyGuiPortletContent'));
                    }
                },
                function(){
                    jQuery(this).removeClass('PlentyGuiPortletOpened');
                    portletContent.slideUp();
                    if(typeof(conf.onClose) == 'function')
                    {
                        conf.onClose(portlet.find('> .PlentyGuiPortletContent'));
                    }
                }
        );
        if(conf.opened == true || conf.opened == "true")
        {
            button.click();
        }
    });
}

/**
 * New Plugin 'plentyOverlay'.
 * 
 * This plugin combines the Tools-Plugin 'overlay' with the UI-Plugin 'draggable'.
 * So you get a draggable overlay.
 * 
 * @author estafilarakis@plentySystems
 * 
 */
jQuery.fn.plentyOverlay = function(conf){
    return this.each(function(){
        // Bilde Overlay (über den Trigger)
        jQuery(this).
            overlay({   onLoad : conf.onLoad,
                        onBeforeLoad : conf.onBeforeLoad,
                        oneInstance : (conf.oneInstance ? conf.oneInstance : false),
                        left : conf.left ? conf.left : '20%',
                        top : conf.top ? conf.top : '10%',
                        closeOnClick : (conf.closeOnClick ? true : false)
                    });
        // Mache das Overlay verschiebbar
        jQuery(jQuery(this).attr("rel")).
            draggable({ appendTo : 'body',
                        //containment : 'window',
                        scroll : true,
                        stack : '.plenty_overlay',
                        handle : '> .title_bar'
                    });
    });
}

/**
 * New Plugin 'plentyDateInput'
 * 
 * This Plugin uses the jQuery Tools dateinput-Plugin and fixes
 * the problems with multiple dateinput instances in different
 * AJAX loaded contents (e.g. portlets).
 * 
 * @author estafilarakis@plentySystems
 * 
 */
jQuery.fn.plentyDateInput = function(conf){
    return this.each(function(){
        jQuery(this).
            bind("focus",function(){
                jQuery(this).after(jQuery("#calroot"));
            }).
            dateinput(conf);
    });
}

/**
 * New Plugin 'plentyQFAMS'
 * 
 * @author estafilarakis@plentySystems
 */
jQuery.fn.plentyQFAMS = function(conf)
{
    return this.each(function(){
        var leftSelect = jQuery(this).find(".QFAMSLeftSelect").eq(0);
        var rightSelect = jQuery(this).find(".QFAMSRightSelect").eq(0);
        var addFunction = function()
        {
            var newOptions = leftSelect.find("option:selected");
            /*if(newOptions.length > 0)
            {
                rightSelect.find("option.emptyOption").remove();
            }*/
            rightSelect.append(newOptions);
        }
        var removeFunction = function()
        {
            var newOptions = rightSelect.find("option:selected");//.filter(":not(.emptyOption)");
            leftSelect.append(newOptions);
            /*if(rightSelect.find("option").length == 0)
            {
                rightSelect.append("<option value=\"\" class=\"emptyOption\">&nbsp;</option>");
            }*/
        }
        /*if(rightSelect.find("option").length==0)
        {
            rightSelect.append("<option value=\"\" class=\"emptyOption\">&nbsp;</option>");
        }*/
        leftSelect.dblclick(addFunction);
        rightSelect.dblclick(removeFunction);
        jQuery(this).
            find(".QFAMSAddIcon").
                click(addFunction).
                end().
            find(".QFAMSRemoveIcon").
                click(removeFunction).
                end();
    });
}

/**
 * New Plugin 'plentyFarbtastic'
 * 
 * @author estafilarakis@plentySystems
 * 
 * @uses The jQuery farbtastic plugin 
 */
jQuery.fn.plentyFarbtastic = function()
{
    /*
     * Load the farbtastic script if not allready loaded.
     */
    jQuery.getPlentyScriptOnce("/tpl/global/jquery/farbtastic/farbtastic.js");
    
    /*
     * Split hexstring color to RGB array
     */
    function getRGB(color)
    {
        if(color.length == 7 && color.substring(0,1) == "#")
        {
            return [parseInt('0x'+color.substring(1,3))/255, parseInt('0x'+color.substring(3,5))/255, parseInt('0x'+color.substring(5,7))/255];
        }
        else if(color.length == 4 && color.substring(0,1) == "#")
        {
            return [parseInt('0x'+color.substring(1,2))/15, parseInt('0x'+color.substring(2,3))/15, parseInt('0x'+color.substring(3,4))/15];
        }
        return [255,255,255];
    }
    
    /*
     * Returns the foreground color for the given background color.
     */
    function getFgColor(bgColor)
    {
        var r = bgColor[0], g = bgColor[1], b = bgColor[2];
        var min = Math.min(r, Math.min(g, b));
        var max = Math.max(r, Math.max(g, b));
        return (min+max)/2 > 0.5 ? '#000' : '#fff';
    }
    
    return this.each(function(){
        var picker = jQuery("<div class=\"plentyFarbtastic\" id=\""+jQuery(this).attr("id")+"_farbtastic\"></div>");
        
        jQuery(this).
            after(picker.hide()).
            focusin(function(){
                picker.farbtastic(this).show();
            }).
            focusout(function(){
                picker.farbtastic(this).hide();
            }).
            css({
                backgroundColor: jQuery(this).val(),
                color: getFgColor(getRGB(jQuery(this).val()))
            });
    });
}

/**
 * Loads a Javascript file with the given URL syncron.
 */
jQuery.getPlentyScript = function(url){
    jQuery.ajax({
          url: url,
          dataType: 'script',
          async : false
        });
}

/*jQuery.fn.scrollTo =  function()
                        {
                            var x = $(this).offset().top - 100;
                            $("html,body").animate({scrollTop: x}, 500);
                            return jQuery(this);
                        }*/

jQuery.fn.removeClassByPrefix = function(sPrefix)
{
    return this.each(function(){
        
        var regx = new RegExp('\\b' + sPrefix + '.*?\\b', 'g');
        this.className = this.className.replace(regx, '');
        //return this;
        
    });
}
    

/**
 * Removes a tab added with jQuery.addNewTab() and reinitializes the tabs object.
 */
jQuery.removeTab = function()
{
    var tabTitle = $(this).closest("li").find("a.PlentyGuiTabTitle");
    var tabId = tabTitle.attr("id");
    var paneId = tabTitle.attr("href").substr(1,tabTitle.attr("href").length);
    
    var tabsSelectorId = tabTitle.closest("div.PlentyGuiTabs").attr("id");
    var tabsObj = $("#"+tabsSelectorId+" > .tabs");
    var options = tabsObj.data("options");
    
    $("#"+tabsSelectorId).find("div#"+paneId).remove();
    $(this).closest("li").remove();
    
    options.initialIndex = 0;
    tabsObj.tabs("> .pane",options);
    tabsObj.find("a.current").click();
}

/**
 * Adds a new tab in an existing tabs object and reinitializes it.
 * 
 * @param string    selector    The ID of the tabs object (PlentyGuiTabs->getID()).
 * @param string    id          The ID of the new tab title. This value will be submited to the AJAX class called with 'ajaxUrl'.
 * @param string    ajaxUrl     The URL to be called. This call should return the tab title and the tab pane for the new tab.
 * @param boolean   click       A flag indicating whether to imediatly open the new tab or not.
 * 
 * @return void
 */
jQuery.addNewTab = function(selector,id,ajaxUrl,click)
{
    var tab = $(selector);
    var selectorId = selector;
    var liId = id+"_liElement";
    var liElem = $("#"+liId);
    var ulElem = $("#"+selector+" > .tabs");
    
    if(typeof click != "boolean")
    {
        click = false;
    }
    
    /*
     * Only if the tab does not already exist.
     */
    if(liElem.length == 0)
    {
        var closeBtn = $("<img/>");
        liElem = $("<li></li>");
        
        /*
         * The new close button.
         */
        closeBtn.
            css({'position':'absolute', 'top':'10px', 'right':'5px'}).
            addClass("link").
            addClass("PlentyGuiIcon").
            addClass("TabCloseButton").
            attr("title","Close Tab").
            attr("id",liId+"_closeButton").
            attr("src","/images/icons/silk/tab_close.gif").
            bind("click",$.removeTab);
        
        /*
         * The new tab title of the tabs object.
         */
        liElem.
            css("position","relative").
            attr("id",liId);
        ulElem.append(liElem);
        
        /*
         * The callback function, which adds the new tab and reinitializes the tabs object.
         */
        var addCloseBtn = function()
        {
            var options = $("#"+selector+" > .tabs").data("options");
            options.initialIndex = ulElem.find('li').index(liElem);
            
            /*
             * Add the close button
             */
            liElem.append(closeBtn);
            
            /*
             * Reinitialize the tabs object.
             */
            ulElem.tabs("> .pane",options);
            
            /*
             * Open the new tab, if requested.
             */
            if(click)
            {
                ulElem.find("a.current").click();
            }
        }
        
        /*
         * The AJAX call.
         */
        ajaxUrl = ajaxUrl + '&Params[result_id][0]=' + liId + '&Params[result_id][1]=' + selectorId + '&Params[add_result_id][1]=1'+'&TabTitleId='+id;
        plentyAjaxRequest2(ajaxUrl,addCloseBtn);
    }
    else
    {
        /*
         * The requested tab already exists, so only open it.
         */
        $("#"+selector+" > .tabs").data("tabs").click(ulElem.find('li').index(liElem));
    }
}


jQuery.fn.iconselect = function(conf){
    return this.each(function(){
            $(this).change(function(){
                var option = $(this).find("option:selected");
                var url = option.css("background-image");
                if( url )
                {
                    $(this).css("background-image",url);
                }
                else
                {
                    $(this).css("background-image","none");
                }
            });
            $(this).css("background-repeat","no-repeat").
                    css("height","19px").
                    css("padding-left","25px");
            $(this).change();
        });
}

function PlentyElementCache()
{
    // Element sets are registered here
    this.oRegistry = new Object();
    // Singleton
    PlentyElementCache.oInstance = null;
}

/**
 * 
 * @returns {PlentyElementCache}
 * @todo if this class is in heavy use, we could think about a cache limit
 */
PlentyElementCache.getInstance = function()
{
    if(PlentyElementCache.oInstance == null)
    {
        PlentyElementCache.oInstance = new PlentyElementCache();
    }
    
    return PlentyElementCache.oInstance;
};

/**
 * 
 * @returns {void}
 */
PlentyElementCache.destroy = function()
{
    PlentyElementCache.oInstance = null;
};

/**
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 * @returns {Object} jQuery element match
 */
PlentyElementCache.prototype.get = function(sJQuerySelector, sCacheNamespace)
{
    if(     sJQuerySelector.length > 0
        &&  this.exists(    sJQuerySelector,
                            sCacheNamespace) == false)
    {
        // Allocate element set to the selector
        this.set(   sJQuerySelector,
                    sCacheNamespace);
    }
    
    if(     $.isset(sCacheNamespace)
        &&  sCacheNamespace.length  > 0)
    {
        return this.oRegistry[sCacheNamespace][sJQuerySelector];
    }
    
    return this.oRegistry[sJQuerySelector];
}

/**
 * Check if matching elements are cached for a selector or a selector in a namespace
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 * @returns {Boolean}
 */
PlentyElementCache.prototype.exists = function(sJQuerySelector, sCacheNamespace)
{
    if(     $.isset(sCacheNamespace)
        &&  sCacheNamespace.length > 0)
    {
        return      $.isset(this.oRegistry[sCacheNamespace])
                &&  $.isset(this.oRegistry[sCacheNamespace][sJQuerySelector]);
    }
    else
    {
        return      $.isset(this.oRegistry[sJQuerySelector]);
    }
}

/**
 * Sets a set of matched elements to the cache
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 * @returns {void}
 */
PlentyElementCache.prototype.set = function(sJQuerySelector, sCacheNamespace)
{
    if(     $.isset(sCacheNamespace)
        &&  sCacheNamespace.length  > 0)
    {
        if($.isset(this.oRegistry[sCacheNamespace]) == false)
        {
            this.oRegistry[sCacheNamespace] = new Object();
        }
        
        this.oRegistry[sCacheNamespace][sJQuerySelector] = jQuery(sJQuerySelector);
    }
    else
    {
        this.oRegistry[sJQuerySelector] = jQuery(sJQuerySelector);
    }
}

/**
 * Unsets a set of matched elements in the cache.
 * 
 * Unset either for a selector, a selector in a namespace or a whole namespace (by leaving the first param blank)
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 */
PlentyElementCache.prototype.unset = function(sJQuerySelector, sCacheNamespace)
{
    if(     $.isset(sCacheNamespace)
        &&  sCacheNamespace.length  > 0)
    {
        if(     $.isset(sJQuerySelector)
            &&  sJQuerySelector.length  > 0)
        {
            // unset selector in namespace
            delete this.oRegistry[sCacheNamespace][sJQuerySelector];
        }
        else
        {
            // unset whole namespace
            delete this.oRegistry[sCacheNamespace];
        }
    }
    else
    {
        if(     $.isset(sJQuerySelector)
            &&  sJQuerySelector.length > 0)
        {
            // unset selector
            delete this.oRegistry[sJQuerySelector];
        }
    }
}

/**
 * 
 * Class registers paths to javascript files, so that the same script isn't loaded twice.
 */
function PlentyScriptRegistry()
{
    // Registry object, script's src tag's values are registered here
    this.oRegistry = new Object();
    PlentyScriptRegistry.oInstance = null;
}

/**
 * Singleton
 * 
 * @returns {PlentyScriptRegistry}
 */
PlentyScriptRegistry.getInstance = function()
{
    if(PlentyScriptRegistry.oInstance == null)
    {
        PlentyScriptRegistry.oInstance = new PlentyScriptRegistry();
    }
    
    return PlentyScriptRegistry.oInstance;
};

/**
 * Register script
 * 
 * @param {String} sSource The path to the script
 */
PlentyScriptRegistry.prototype.register = function(sSource)
{
    if(sSource.length > 0)
    {
        this.oRegistry[sSource] = true;
    }
}

/**
 * Is a script registered with that path?
 * 
 * @param {String} sSource The path to the script
 */
PlentyScriptRegistry.prototype.isRegistered = function(sSource)
{
    return      $.isset(this.oRegistry[sSource])
            &&  this.oRegistry[sSource]         == true
}

/*
 * jQuery extensions.
 * 
 * Functions will be available via "$." or "jQuery." respectively.
 */
jQuery.extend({
    /**
     * Takes use of the PlentyElementCache class.
     * 
     * All elements that are found via this function are cached by the selector as long as the page is not reloaded.
     * 
     * @param {String} sJQuerySelector
     * @param {String} sCacheNamespace
     * @returns {Object} A set of matching elements for the selector
     */
    c: function(sJQuerySelector, sCacheNamespace) {
        return  PlentyElementCache
                    .getInstance()
                        .get(sJQuerySelector, sCacheNamespace);
    },
    /**
     * Direct access to the PlentyElementCache instance.
     * 
     * Use this, for example, to unset parts of the cache.
     * 
     * @returns {PlentyElementCache}
     */
    getCache: function() {
        return  PlentyElementCache
                    .getInstance();
    },
    /**
     * Loads a script via ajax just once
     * 
     * @param {String} sSource
     */
    getPlentyScriptOnce: function(sSource) {
        if( PlentyScriptRegistry
                .getInstance()
                    .isRegistered(sSource) === false)
        {
            // Load script via synchronous ajax
            jQuery.getPlentyScript(sSource);
            // Register script source
            PlentyScriptRegistry
                .getInstance()
                    .register(sSource);
        }
    },
    /**
     * Loads a CSS file via ajax
     * 
     * To load a CSS file just once, use $.getPlentyCssOnce()
     * 
     * @param {String} sSource
     */
    getPlentyCss: function(sSource)
    {
        if(     $.isset(sSource)
            &&  sSource.length > 0)
        {
            $('head').append('<link>');
            css = $('head').children(':last');
            css.attr({
                rel:  'stylesheet',
                type: 'text/css',
                href: sSource
            });
        }
    },
    /**
     * Loads a CSS file just once
     * 
     * @param {String} sSource
     */
    getPlentyCssOnce: function(sSource)
    {
        if( PlentyScriptRegistry
                .getInstance()
                    .isRegistered(sSource) === false)
        {
            // Register
            PlentyScriptRegistry
                .getInstance()
                    .register(sSource);
            // Get
            $.getPlentyCss(sSource);
        }
    },
    /**
     * Returns true if param is not undefined and not null
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    isset: function(mixed)
    {
        return      mixed   !== undefined
                &&  mixed   !== null;
    },
    /**
     * Returns true if param is null
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    is_null: function(mixed)
    {
        return mixed == null;
    },
    /**
     * Returns true if param is not undefined and not null
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    is_undefined: function(mixed)
    {
        return mixed === undefined;
    },
    /**
     * Returns true if param is an object
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    is_object: function(mixed)
    {
        return typeof mixed == 'object';
    }
});
