/**
 * Accessible Tabs - jQuery plugin for accessible, unobtrusive tabs
 * Build to seemlessly work with the CCS-Framework YAML (yaml.de) not depending on YAML though
 * @requires jQuery - tested with 1.9.1, 1.7 and 1.4.2 but might as well work with older versions
 *
 * english article: http://blog.ginader.de/archives/2009/02/07/jQuery-Accessible-Tabs-How-to-make-tabs-REALLY-accessible.php
 * german article: http://blog.ginader.de/archives/2009/02/07/jQuery-Accessible-Tabs-Wie-man-Tabs-WIRKLICH-zugaenglich-macht.php
 * 
 * code: http://github.com/ginader/Accessible-Tabs
 * please report issues at: http://github.com/ginader/Accessible-Tabs/issues
 *
 * Copyright (c) 2007 Dirk Ginader (ginader.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

;(function($) {
    var debugMode = false;
    $.fn.extend({
        // We assume there could be multiple sets of tabs on a page, so,
        // the unique id for each invididual tab's heading is identified with params q and r (e.g., id="accessibletabscontent0-2")
        getUniqueId: function(p, q, r){
            if (r===undefined) {r='';} else {r='-'+r;}
            return p + q + r;
        },
        accessibleTabs: function(config) {
            var defaults = {
                wrapperClass: 'tabs-content', // Classname to apply to the div that is wrapped around the original Markup
                currentClass: 'is-active', // Classname to apply to the LI of the selected Tab
                tabhead: 'h4', // Tag or valid Query Selector of the Elements to Transform the Tabs-Navigation from (originals are removed)
                tabheadClass: 'tab-head is-hidden', // Classname to apply to the target heading element for each tab div
                tabbody: '.content', // Tag or valid Query Selector of the Elements to be treated as the Tab Body
                fx:'fadeIn', // can be "fadeIn", "slideDown", "show"
                fxspeed: 'fast', // speed (String|Number): "slow", "normal", or "fast") or the number of milliseconds to run the animation
                currentInfoText: '', // text to indicate for screenreaders which tab is the current one
                currentInfoPosition: 'prepend', // Definition where to insert the Info Text. Can be either "prepend" or "append"
                currentInfoClass: 'current-info', // Class to apply to the span wrapping the CurrentInfoText
                tabsListClass:'tabs-list', // Class to apply to the generated list of tabs above the content
                tabsListItemClass:'tab-title', // Class to apply to the generated list item of tabs above the content
                syncheights:false, // syncs the heights of the tab contents when the SyncHeight plugin is available http://blog.ginader.de/dev/jquery/syncheight/index.php
                syncHeightMethodName:'syncHeight', // set the Method name of the plugin you want to use to sync the tab contents. Defaults to the SyncHeight plugin: http://github.com/ginader/syncHeight
                cssClassAvailable:true, // Enable individual css classes for tabs. Gets the appropriate class name of a tabhead element and apply it to the tab list element. Boolean value
                saveState:false, // save the selected tab into a cookie so it stays selected after a reload. This requires that the wrapping div needs to have an ID (so we know which tab we're saving)
                autoAnchor:false, // will move over any existing id of a headline in tabs markup so it can be linked to it
                pagination:false, // adds buttons to each tab to switch to the next/previous tab
                position:'top', // can be 'top' or 'bottom'. Defines where the tabs list is inserted.
                wrapInnerNavLinks: '', // inner wrap for a-tags in tab navigation. See http://api.jquery.com/wrapInner/ for further informations
                firstNavItemClass: '', // Classname of the first list item in the tab navigation
                lastNavItemClass: '', // Classname of the last list item in the tab navigation
                clearfixClass: '' // Name of the Class that is used to clear/contain floats
            };
            var keyCodes = {
                37 : -1, //LEFT
                38 : -1, //UP
                39 : +1, //RIGHT 
                40 : +1 //DOWN
            };
            var positions = {
                top : 'prepend',
                bottom : 'append'
            };
            this.options = $.extend(defaults, config);

            var tabsCount = 0;
            if($("body").data('accessibleTabsCount') !== undefined){
                tabsCount = $("body").data('accessibleTabsCount');
            }
            $("body").data('accessibleTabsCount',this.size()+tabsCount);

            var o = this;
            return this.each(function(t) {
                var el = $(this);
                var list = '';
                var tabCount = 0;
                var ids = [];

                // LUXMEDIA MOD
                var tabHeaders =  $(el).children().filter(":header");
                // EOF

                $(el).wrapInner('<div class="'+o.options.wrapperClass+'"></div>');

                // LUXMEDIA MOD
                // $(el).find(o.options.tabhead).each(function(i){
                $(tabHeaders).each(function(i){
                // EOF
                    var id = '';
                    var elId = $(this).attr('id');
                    if(elId){
                        // Skip this item if it already exists.
                        if(elId.indexOf('accessibletabscontent') === 0) {
                            return;
                        }
                        id =' id="'+elId+'"';
                    }
                    var tabId = o.getUniqueId('accessibletabscontent', tabsCount+t, i);//get a unique id to assign to this tab's heading
                    var navItemId = o.getUniqueId('accessibletabsnavigation', tabsCount+t, i);//get a unique id for this navigation item
                    ids.push(tabId);
                    // LUXMEDIA MOD
                    var cssClass = '';
                    var itemClass = '';
                    if(o.options.cssClassAvailable === true) {
                        if($(this).attr('class')) {
                            cssClass = $(this).attr('class');
                            cssClass = ' class="'+cssClass+'"';
                        }
                    }
                    if(o.options.tabsListItemClass) itemClass = ' class="'+o.options.tabsListItemClass+'"';
                    list += '<li id="'+navItemId+'"'+itemClass+'><a'+id+''+cssClass+' href="#'+tabId+'">'+$(this).html()+'</a></li>';
                    // EOF
                    $(this).attr({"id": tabId, "class": o.options.tabheadClass, "tabindex": "-1"});//assign the unique id and the tabheadClass class name to this tab's heading
                    tabCount++;
                });

                if (o.options.syncheights && $.fn[o.options.syncHeightMethodName]) {
                    $(el).find(o.options.tabbody)[o.options.syncHeightMethodName]();
                    $(window).resize(function(){
                        $(el).find(o.options.tabbody)[o.options.syncHeightMethodName]();
                    });
                }

                // Ensure that the call to setup tabs is re-runnable
                var tabs_selector = '.' + o.options.tabsListClass;
                if(!$(el).find(tabs_selector).length) {
                    if (o.options.clearfixClass) { o.options.clearfixClass += ' '; }
                    $(el)[positions[o.options.position]]('<ul class="'+o.options.clearfixClass+o.options.tabsListClass+' tab-amount'+tabCount+'"></ul>');
                }

                $(el).find(tabs_selector).append(list);

                // initial show first content block and hide the others
                var content = $(el).find(o.options.tabbody);
                if (content.length > 0) {
                    $(content).hide();
                    $(content[0]).show();
                }
                // LUXMEDIA MOD
                $(el).find("ul."+o.options.tabsListClass+">li:first").addClass(o.options.currentClass);
                if (o.options.firstNavItemClass) $(el).find("ul."+o.options.tabsListClass+">li:first").addClass(o.options.firstNavItemClass);
                if (o.options.currentInfoText) $(el).find('a')[o.options.currentInfoPosition]('<span class="'+o.options.currentInfoClass+'">'+o.options.currentInfoText+'</span>');
                if (o.options.lastNavItemClass) $(el).parents("ul."+o.options.tabsListClass).children('li:last').addClass(o.options.lastNavItemClass);
                // EOF

                if (o.options.wrapInnerNavLinks) {
                  $(el).find('ul.'+o.options.tabsListClass+'>li>a').wrapInner(o.options.wrapInnerNavLinks);
                }

                $(el).find('ul.'+o.options.tabsListClass+'>li>a').each(function(i){
                    $(this).click(function(event){
                        event.preventDefault();
                        el.trigger("showTab.accessibleTabs", [$(event.target)]);
                        if(o.options.saveState && $.cookie){
                            $.cookie('accessibletab_'+el.attr('id')+'_active',i);
                        }
                        $(el).find('ul.'+o.options.tabsListClass+'>li.'+o.options.currentClass).removeClass(o.options.currentClass)
                        .find("span."+o.options.currentInfoClass).remove();
                        $(this).blur();

                        // LUXMEDIA MOD
                        // nicely animate tabs
                        var hideMe = $(el).find(o.options.tabbody+':visible');
                        var showMe = $(el).find(o.options.tabbody).eq(i);
                        var showMeHeight = $(showMe).actual("outerHeight");
                        if(!o.options.syncheights) {
                            try {
                                $(hideMe).fadeOut(o.options.fxspeed).promise().done( function() {
                                    // show activated tab after current tab is hidden
                                    
                                    // adapt container height to new tab content height
                                    $(showMe).parent().animate({"height":showMeHeight},o.options.fxspeed).promise().done( function() {
                                        // show new tab
                                        $(showMe).fadeIn(o.options.fxspeed);
                                    });
                                });
                            } catch(e) {
                                $(hideMe).hide();
                                $(el).find(o.options.tabbody).eq(i)[o.options.fx](o.options.fxspeed);
                                debug(e);
                            }
                        } else {
                            $(hideMe).hide();
                            $(showMe)[o.options.fx](o.options.fxspeed);
                        }
                        // EOF
                        
                        $(this)[o.options.currentInfoPosition]('<span class="'+o.options.currentInfoClass+'">'+o.options.currentInfoText+'</span>')
                        .parent().addClass(o.options.currentClass);
                        //now, only after writing the currentInfoText span to the tab list link, set focus to the tab's heading

                        $($(this).attr("href")).focus().keyup(function(event){
                            if(keyCodes[event.keyCode]){
                                o.showAccessibleTab(i+keyCodes[event.keyCode]);
                                $(this).unbind( "keyup" );
                            }
                        });

                        // $(el).find('.accessibletabsanchor').keyup(function(event){
                        //     if(keyCodes[event.keyCode]){
                        //         o.showAccessibleTab(i+keyCodes[event.keyCode]);
                        //     }
                        // });
                    });

                    $(this).focus(function(){
                        $(document).keyup(function(event){
                            if(keyCodes[event.keyCode]){
                                o.showAccessibleTab(i+keyCodes[event.keyCode]);
                            }
                        });
                    });
                    $(this).blur(function(){
                        $(document).unbind( "keyup" );
                    });

                });

                if(o.options.saveState && $.cookie){
                    var savedState = $.cookie('accessibletab_'+el.attr('id')+'_active');
                    debug($.cookie('accessibletab_'+el.attr('id')+'_active'));
                    if(savedState !== null){
                        o.showAccessibleTab(savedState,el.attr('id'));
                    }
                }

                if(o.options.autoAnchor && window.location.hash){
                    var anchorTab = $('.'+o.options.tabsListClass).find(window.location.hash);
                    if(anchorTab.size()){
                        anchorTab.click();
                    }
                }

                if(o.options.pagination){
                    var m = '<ul class="pagination">';
                    m +='    <li class="previous"><a href="#{previousAnchor}"><span>{previousHeadline}</span></a></li>';
                    m +='    <li class="next"><a href="#{nextAnchor}"><span>{nextHeadline}</span></a></li>';
                    m +='</ul>';
                    var tabs = $(el).find('.tabbody');
                    var tabcount = tabs.size();
                    tabs.each(function(idx){
                        $(this).append(m);
                        var next = idx+1;
                        if(next>=tabcount){next = 0;}
                        var previous = idx-1;
                        if(previous<0){previous = tabcount-1;}
                        var p = $(this).find('.pagination');
                        var previousEl = p.find('.previous');
                        previousEl.find('span').text($('#'+ids[previous]).text());
                        previousEl.find('a').attr('href','#'+ids[previous])
                        .click(function(event){
                            event.preventDefault();
                            $(el).find('.tabs-list a').eq(previous).click();
                        });
                        var nextEl = p.find('.next');
                        nextEl.find('span').text($('#'+ids[next]).text());
                        nextEl.find('a').attr('href','#'+ids[next])
                        .click(function(event){
                            event.preventDefault();
                            $(el).find('.tabs-list a').eq(next).click();
                        });
                    });
                }
            });
        },
        showAccessibleTab: function(index,id){
            debug('showAccessibleTab');
            var o = this;
            if(id) {
                var el = $('#'+id);
                var links = el.find('ul.'+o.options.tabsListClass+'>li>a');
                el.trigger("showTab.accessibleTabs", [links.eq(index)]);
                links.eq(index).click();
            } else {
                return this.each(function() {
                    var el = $(this);
                    el.trigger("showTab.accessibleTabs");
                    var links = el.find('ul.'+o.options.tabsListClass+'>li>a');
                    el.trigger("showTab.accessibleTabs", [links.eq(index)]);
                    links.eq(index).click();
                });
            }
        },
        showAccessibleTabSelector: function(selector){
            debug('showAccessibleTabSelector');
            var el = $(selector);
            if(el){
                if(el.get(0).nodeName.toLowerCase() === 'a'){
                    el.click();
                }else{
                    debug('the selector of a showAccessibleTabSelector() call needs to point to a tabs headline!');
                }
            }
        }
    });
    // private Methods
    function debug(msg,info){
        if(debugMode && window.console && window.console.log){
            if(info){
                window.console.log(info+': ',msg);
            }else{
                window.console.log(msg);
            }
        }
    }
})(jQuery);