/*
 * default-gallery-slider erweitert auf allg. switcher
 * - validate und das ganze rein, plus formularfelder
 * - jso_Slider zu jso_Switcher, jso_Slide zu jso_Page
 *
 * - jso_Page kann aber eben auch in anderen Elementen sein
 *   > wenn in jso_Form -> zu fieldsets
 *   > wenn in jso_Form/jso_Switcher -> zu slides
 *      entweder jso_Switcher als "root"-Element definierbar
 *      oder definierbar jso_Form/jso_Switcher/jso_Page -> /jso_Switcher/jso_Page verwenden
 *        zB window.jso['/Form/Switcher/Page'] = '/Switcher/Page'; --> komplett den Pfad für Vererbung verwenden!
 *
 *
 * - FormText, FormFile usw müsste jso_FormElement als prototype definieren können irgendwie ...
 *   d.h. einfach im haupt-verzeichnis: window.jso['/FormText'] = '/_prototypes/FormElement,/_prototypes/FormText'
 *      --> der reihe nach erst FormElement prototypen, dann FormText
 *
 * - message callback mit .call(oThis) aufrufen?
 *
 *
 * - slides: soll eigentl. slideContainer die Ani machen?
 *   ENTWEDER machen slides das selber bei sendMsg('show') [jedes checkt ja selber ob es sichtbar is oder nich!]
 *   ODER     container macht es eben, is aber nur in begrenztem rahmen mögl wie hier oder?
 *
 *   vorteil von jedem Obj selber: 'show', sAniType -> zB slide_left, dann weiß jedes slide, wenn es angezeigt ist
 *   muss es links raussliden, wenn es das is was angezeigt werden soll von rechts nach links reinsliden
 *   slideContainer könnte sich dafür sogar auch registrieren und ggf. am container-css solang was ändern usw ...
 *   evtl. jsoAnimation = { 'type': 'slide', 'speed': 500, 'direction': 'left' }
 *
 */


//TODO documentation: this resets everything within /Form/Slides (also sub-JSOs) to the root path
//                    therefore all JSOs within Slide like slideContainer, navButtons etc "think"
//                    they are in /Slides ...
//                    without _, e.g. just /, resets just the Slides classpath, not sPath!
window.jso['/Form/Slides'] = '_';
//window.jso['/Form/Slides'] = '';
//window.jso['/Form/Slides/slideContainer'] = '/Slides';
//window.jso['/Form/Slides/slideContainer/Slide'] = '/Slides/slideContainer';

window.jso['/Slides'] = function() {
    var iCount     = -1;
    var iCurr      =  0; // Here 0, in slideContainer 1 -> Slide doesn't get slided in ;)
    var oContainer = null;
    var that       = this;
    var iAutoSlide = 9000;
    var oParams    = this.getParams();
    
    this.setPageCount = function(iCountIn) {
        iCount = iCountIn;
    }
    
    this.getPageCount = function() {
        return iCount;
    }
    
    this.getCurrPage = function() {
        return iCurr;
    }
    
    this.setContainer = function(oContainerIn) {
        oContainer = oContainerIn;
    }
    
    this.getContainer = function() {
        return oContainer;
    }
    
    this.initAutoSlide = function() {
        var oTimer = undefined;
        var bIn    = false;
        var bGo    = false;
        var bRes   = false;
        
        that.jE.mouseenter(function() { bIn = true; });
        //TODO ggf. einfach bei "gotoSlide" einen Wert
        //that.jE.click(function(oEvent) {  for (var iI in oEvent) alert(iI+': '+oEvent[iI]);    bRes = true; });
        that.registerMessage('show', function() {
            bRes = true;
            bGo  = false;
            if (oTimer) { clearTimeout(oTimer); oTimer = undefined; }
        });
        that.jE.mouseleave(function() {
            bIn = false;
            if (bRes) {
                if (oTimer) clearTimeout(oTimer);
                oTimer = setTimeout(autoSlide, iAutoSlide);
            }
            else if (bGo) {
                bGo = false;
                autoSlide();
            }
            bRes = false;
        });
        
        var autoSlide = function() {
            if (!bIn) {
                that.nextSlide(true);
                
                if (oTimer) clearTimeout(oTimer);
                oTimer = setTimeout(autoSlide, iAutoSlide);
                
                bRes = false;
            }
            else {
                bGo = true;
                if (oTimer) { clearTimeout(oTimer); oTimer = undefined; }
            }
        }
        
        oTimer = setTimeout(autoSlide, iAutoSlide);
    }
    
    // Wenn's halt ein slideContainer is, slided der bei der message
    // Wenn es ein fadeContainer is, muss der halt iPage runden (slide kann ja auch zu halben Slides sliden)
    this.gotoSlide = function(iPage) {
        var aRtn = this.sendMessage('on_gotoSlide', { 'iCurr': iCurr, 'iPage': iPage });
        var aErr = new Array();
        
        for (var iI = 0; iI < aRtn.length; iI++) {
            if ((typeof aRtn[iI] == 'object') && (aRtn[iI][0] == 'error'))   aErr.push(aRtn[iI][1]);
            else if ((typeof aRtn[iI] == 'boolean') && (aRtn[iI] == false)) aErr.push(false);
        }
        
        if (aErr.length) {
            this.sendMessage('error_gotoSlide', { 'iCurr': iCurr, 'iPage': iPage, 'aErr': aErr });
        }
        else {
            // Call ready-func of slide, after that sendMessage!
            oContainer.oSlides[iPage - 1].ready(function() {
                if ((iPage > 0) && (iPage <= iCount)) {
                    iCurr = iPage;
                    that.sendMessage('show', iPage);
                    
                    if (oParams.store && that.jE.attr('id')) window.cookieFunc.createCookie('jso_Slide_' + that.jE.attr('id'), iPage);
                }
            });
        }
    }
    
    this.nextSlide = function(bToFirst) {
        if (iCurr < iCount) this.gotoSlide(iCurr + 1);
        else if (bToFirst) this.gotoSlide(1);
    }
    
    this.prevSlide = function(bToLast) {
        if (iCurr > 1) this.gotoSlide(iCurr - 1);
        else if (bToLast) this.gotoSlide(iCount);
    }
    
    this.Slides = function() {
        this.jE.addClass('jsc_Slides');
        
        this.initializeChildren();
        
        this.initSlides();
    }
    
    this.initSlides = function() {
        var sFr = '';
        try {
            var sFr = location.href.parseUrl().fragment;
        }
        catch (oErr) {
            //alert(oErr);
        }
        
        var aFr = Array();
        
        if (sFr) aFr = String('http://www.example.org/index.php?' + sFr).parseQuery();
        //sFr = sFr.parseQuery();
        
        if (aFr['_obj_id_'+this.getId()]) {
            var iSlide = parseInt(aFr['_obj_id_'+this.getId()]);
            
            if (isNaN(iSlide) || (iSlide < 1)) iSlide = 1;
            
            this.gotoSlide(iSlide);
        }
        else if (this.jE.attr('id') && aFr[this.jE.attr('id')]) {
            var iSlide = parseInt(aFr[this.jE.attr('id')]);
            
            if (isNaN(iSlide) || (iSlide < 1)) iSlide = 1;
            
            this.gotoSlide(iSlide);
        }
        else if (oParams.store && this.jE.attr('id')) {
            var iSlide = parseInt(window.cookieFunc.readCookie('jso_Slide_' + this.jE.attr('id')));
            
            if (isNaN(iSlide) || (iSlide < 1)) iSlide = 1;
            
            this.gotoSlide(iSlide);
        }
        else this.gotoSlide(1);
        
        if (oParams.autoSlide) {
            this.initAutoSlide();
        }
        
        //TODO necessary? handleMessages ... is stupid ... :(
        this.handleMessage(oContainer, 'loading');
        this.handleMessage(oContainer, 'loaded');
    }
    
    //alert(this.sPath);
}

//window.jso['/Box/subtabBox/slideContainer'] = '/Slides';
window.jso['/Box/subtabBox/slideContainer'] = '_Slides';
window.jso['/subtabBox/slideContainer'] = '_Slides';
window.jso['/verttabBox/slideContainer']    = '_Slides';
window.jso['/Form/verttabBox/slideContainer']    = '_Slides';
window.jso['/Slides/slideContainer'] = function() {
    /*
     * TODO
     *
     * - check (with messages?) if height of sub-element was changed --> update own height (vertTabs in subTabs!)
     *
     */
    
    var that    = this;
    var iW      = NaN;
    var iCurrSl = 0;
    var bActive = false;
    var oParams = this.getParams();
    var oTimer  = null;
    var sOverfl = this.jE.css('overflow');
    
    this.aSlides = new Array();
    this.oSlides = new Array();
    
    var oCSS = {
        'border-width' : '0 1px' //,
        //'overflow'     : 'hidden'
    };
    var oSlideCSS = {
        'position'     : 'absolute',
        'display'      : 'none'
        //'background-color': 'white'
    };
    var oBorderCSS = {
        'display'          : 'block',
        'margin-left'      : '1px',
        'height'           : '1px',
        'background-color' : '#e8e8e8'
    };
    
    this.showSlide = function(sMsg, iSlide) {
        // Don't execute if same slide!
        if (iCurrSl == iSlide) return;
        
        // Hide all slides, CSS should be reset before animating anyway
        that.jE.children('.jso_Slide').hide();
        
        var iFadeSpeed = 400;
        
        /*
         * fadeContainer
         */
        
        //TODO Always get current params ... 
        //if (that.getParams()['fade']) ? or if (that.getParam('fade')) ?
        if (iCurrSl == 0) {
            var iNewHeight = that.oSlides[iSlide - 1].getWH().outerHeight;
            //if (oDimensions.height == 0) iNewHeight = 0;
            //alert(iNewHeight);
            //if (iNewHeight < iMin) iNewHeight = iMin;
            
            that.jE.stop(true).css('height', iNewHeight + 'px');
            that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').fadeIn(iFadeSpeed);
        }
        else if (oParams['fade']) {
            //that.jE.children('.jso_Slide:visible').fadeOut();
            //that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').fadeIn();
            
            if (oTimer) {
                clearTimeout(oTimer);
                oTimer = null;
            }
            
            if (oParams['varHeight']) {
                //var sO = that.jE.css('overflow');
                //if (!sO) sO = 'visible';
                // why doesn't setting overflow hidden work? hmmm but timer is cooler anyway ;)
                
                //setTimeout(function() { that.jE.show(); alert(that.oSlides[0].jE.show().height()); that.jE.hide(); }, 500);
                
                
                // Irgendwie noch optimieren damit am ende immer opacity 1 drin is?
                
                if (that.oSlides[iCurrSl - 1].jE.height() > that.oSlides[iSlide - 1].jE.height()) {
                    oTimer = setTimeout(function() { that.jE.stop(true).animate({ 'height': that.oSlides[iSlide - 1].jE.height() }, iFadeSpeed); }, iFadeSpeed / 3);
                    
                    that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).show().css('opacity', 1).fadeOut(iFadeSpeed);
                    that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').stop(true).hide().fadeIn(iFadeSpeed, function() { that.jE.css('opacity', 1); });
                }
                else if (that.oSlides[iCurrSl - 1].jE.height() < that.oSlides[iSlide - 1].jE.height()) {
                    that.jE.stop(true).animate({ 'height': that.oSlides[iSlide - 1].jE.height() }, iFadeSpeed);
                    
                    // Because all slides are hidden - see above ...
                    that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').show();
                    
                    // iCurrSl is reset to new slide in this function -> executed before timeout -> need a copy!
                    var iTmpSlide = iCurrSl;
                    
                    oTimer = setTimeout(function() {
                        that.jE.children('.jso_Slide:eq('+(iTmpSlide - 1)+')').stop(true).show().css('opacity', 1).fadeOut(iFadeSpeed);
                        that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).hide().fadeIn(iFadeSpeed, function() { that.jE.css('opacity', 1); });
                    }, iFadeSpeed / 3);
                }
                else {
                    that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).show().css('opacity', 1).fadeOut(iFadeSpeed);
                    that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').stop(true).hide().fadeIn(iFadeSpeed, function() { that.jE.css('opacity', 1); });
                    
                    that.jE.stop(true).animate({ 'height': that.oSlides[iSlide - 1].jE.height() }, iFadeSpeed);
                }
            }
            else {
                that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).show().css('opacity', 1).fadeOut(iFadeSpeed);
                that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').stop(true).hide().fadeIn(iFadeSpeed, function() { that.jE.css('opacity', 1); });
            }
            
        }
        else {
            that.jE.css('overflow', 'hidden');
            
            if (iCurrSl < iSlide) {
                // DEFAULT Slide
                that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).show().css('left', 0).animate({ 'left': -1 * iW }, function() { jQuery(this).hide(); that.jE.css('overflow', sOverfl); });
                that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').stop(true).css('left', iW).show().animate({ 'left': 0 });
                
                // Over-Slide
                //that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).show().css('left', 0).animate({ 'left': 0 }, function() { jQuery(this).hide(); });
                //that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').stop(true).css('left', iW).show().animate({ 'left': 0 });
            }
            else {
                that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).show().css('left', 0).animate({ 'left': iW }, function() { jQuery(this).hide(); that.jE.css('overflow', sOverfl); });
                that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').stop(true).css('left', -1 * iW).show().animate({ 'left': 0 });
                
                // Over-Slide
                //that.jE.children('.jso_Slide:eq('+(iCurrSl - 1)+')').stop(true).show().css('left', 0).animate({ 'left': 0 }, function() { jQuery(this).hide(); });
                //that.jE.children('.jso_Slide:eq('+(iSlide - 1)+')').stop(true).css({ 'left': -1 * iW, 'z-index': 1 }).show().animate({ 'left': 0 }, function() { jQuery(this).css('z-index', ''); });
                // --> navButtons temporär zIndex = 2 ...
            }
        }
        
        iCurrSl = iSlide;
    }
    
    this.slideContainer = function() {
        // Width AFTER initializeChildren!
        // Something's always wrong ... after initializeChildren? ...?
        //iW = this.jE.addClass('jsc_slideContainer').width();
        this.jE.addClass('jsc_slideContainer');
        iW = this.getWH().width;
        
        /*
        this.jE.children('.jso_Slide').each(function() {
            that.aSlides[iI] = jQuery(this).children('h1').text();
            
            if (jQuery(this).height() > iMax) iMax = jQuery(this).height();
            
            iI++;
        });
        */
        
        this.initializeChildren();
        
        this.oSlides = this.childObjs('Slide');
        //this.oSlides2 = jQuery.extend(this.childObjs('Slide'), this.childObjs('Page'));
        
        var iMax = 0;
        //for (var sI in that.oSlides) alert(sI + ': '+that.oSlides[sI].getTitle());
        
        for (var iI = 0; iI < that.oSlides.length; iI++) {
            if (!oParams['varHeight']) {
                var iH = that.oSlides[iI].jE.height(); //.show() ?
                if (iH > iMax) iMax = iH;
                //that.oSlides[iI].jE.hide();
            }
            
            that.aSlides[iI + 1] = that.oSlides[iI].getTitle();
            
            if (that.aSlides[iI + 1] == 'Firmenprofil') {
                var jT = that.oSlides[iI].jE;
                
                setTimeout(function() {
                    //alert(iH + '-' + jT.show().height());
                }, 500);
            }
            
            this.handleMessage(that.oSlides[iI], 'loading');
            this.handleMessage(that.oSlides[iI], 'loaded');
        }
        
        
        //this.jE.addClass('jsc_slideContainer').children('.jso_Slide').css(oSlideCSS).css('width', (iW - 30)).filter(':first').css('display', 'block');
        this.jE.children('.jso_Slide').css(oSlideCSS).filter(':first').css('display', 'block');
        
        // Hmmmm ... width necessary? Why don't the Slides just use 100% of the space? They are block elements! ...
        this.jE.children('.jso_Slide').css('width', (iW - (this.jE.children('.jso_Slide').innerWidth()- this.jE.children('.jso_Slide').width())));
        
        /*
        if (!oParams['fade']) {
            //TODO clarify css ... the - 30 here sucks ... why isn't setting inner width enough? no padding at Slide?
            this.jE.children('.jso_Slide').css('width', (iW - 0));
        }
        */
        
        var oP = this.callerObj();
        //TODO do everywhere where oP is handled in case no parent is available (wrong html setup)
        if (!oP.setPageCount) return;
        
        if (oParams['varHeight']) {
            //that.jE.show();
            //that.callerObj().jE.show();
            this.jE.css('height', that.oSlides[0].jE.outerHeight());
            //that.jE.hide();
            
            //setTimeout(function() {
                /*
                that.callerObj().callerObj().jE.show();
                that.callerObj().jE.show();
                that.jE.show();
                */
                //alert(that.callerObj().sPath + ': ' + that.oSlides[0].jE.outerHeight());
                
            //}, 1000);
        }
        else {
            if (oP.getMinHeight) {
                this.parentReady(function() {
                    var iMin = oP.getMinHeight();
                    
                    if (iMin > iMax) iMax = iMin;
                    
                    for (var iI = 0; iI < that.oSlides.length; iI++) that.oSlides[iI].jE.css('height', iMax + 'px');
                
                    that.jE.css('height', iMax);
                });
            }
            else {
                //TODO by oSlides? Why not .children('.jso_Slides'), or is that here better?
                //     why set height for slides at all? isn't it enough to set the container?
                for (var iI = 0; iI < that.oSlides.length; iI++) that.oSlides[iI].jE.css('height', iMax + 'px');
                
                this.jE.css('height', iMax);
            }
        }
        
        
        // Auto update for with, if in a % container and window is resized?
        //TODO templating ... subsections in templates for all of these elements including style-definitions in the style-attr?
        //     Not nice but better than CSS within the JavaScript ... also e.g. navButtons: for-loop through template-subsection
        //if (this.jE.css('border-top-width') != '0px') {
        if (oParams['Corners']) {
            this.jE.css(oCSS);
            this.jE.before(jQuery(document.createElement('span')).css(oBorderCSS).css({ 'top': '-1px', 'width': iW }));
            this.jE.after (jQuery(document.createElement('span')).css(oBorderCSS).css({ 'bottom': '-1px', 'width': iW }));
        }
        
        
        
        oP.setPageCount(this.jE.children('.jso_Slide').length);
        oP.setContainer(this);
        
        oP.registerMessage('show', this.showSlide);
        
        
        
        /*
         * childrenReady --> get object (from .data(this, 'obj'))
         *      -> sendMessage('show'/'slide'/...)?
         *
         */
    }
    
    return this;
}

window.jso['/Slides/slideContainer/Slide'] = function() {
    var that    = this;
    var oParams = this.getParams();
    var iSlide  = this.jE.prevAll('.jso_Slide').length + 1;
    
    var sTitle = undefined;
    
    var oReadyRunning = false;
    
    /*
     * TODO
     * - add jsc_Slide class -> jso_Slide for browsers without JS, jsc_Slide additionally for the others
     * - with that style e.g. navButton: jsc_prevButton, jsc_nextButton
     *
     */
    
    this.getTitle = function() {
        if (sTitle && (sTitle == 'Kontaktdaten')) {
            var sP = this.sPath;
            var sO = this.sObjPath;
            var x = 'y';
        }
        
        if (sTitle) return sTitle;
        
        //return this.jE.children('h1:first').length ? this.jE.children('h1:first').text() : this.jE.children('img:first').attr('alt');
        return this.jE.children('h1:first').length ? this.jE.children('h1:first').text() : this.jE.text();
    }
    
    this.ready = function(oCallback) {
        var oParams = this.getParams();
        
        if (oParams['ajax']) {
            if (!this.jE.attr('href')) return;
            
            if (oReadyRunning) return;
            oReadyRunning = true;
            
            this.sendMessage('loading');//, this.getTitle()); -> Titel noch nicht Verfügbar ...
            
            jQuery.post(this.jE.attr('href'), { 'ajax': true }, function(sData) {
            //jQuery.get(this.jE.attr('href'), {}, function(sData) {
                //var jData = jQuery(document.createElement('div')).html(sData.replace(/^.*<body.*>(.+?)<\/body>.*$/, '$1'));
                
                // Replace Tag with div, insert Content, remove jsp_ajax!
                that.replaceTag('div');
                //alert(sData);
                //TODO: z.B. that.append(jData.find('#' + sId)), falls in einem body-Bereich ein gewisses Element gefunden werden soll!
                sData = sData.replace(/^.*<body.*>(.+?)<\/body>.*$/, '$1');
                
                if (sData.indexOf('<!--SE_AJAX_RESPONSE-->') != -1) {
                    //sData = sData.replace(/^.*<!--SE_AJAX_RESPONSE-->(.+?)<!--\/SE_AJAX_RESPONSE-->.*$/, '$1');
                    sData = sData.substring(sData.indexOf('<!--SE_AJAX_RESPONSE-->') + 23, sData.lastIndexOf('<!--/SE_AJAX_RESPONSE-->'));
                }
                
                jData = jQuery(sData);
                
                //if (that.jE.find('img').length) {
                //    that.jE.find('img:first').ready(function() {
                //        oCallback();
                //    });
                //}
                //else 
                //jData.find('img').loaded(function() { oCallback(); });
                
                if (jData.filter('img').length) {
                    jData.load(function() { that.sendMessage('loaded'); that.jE.removeClass('jsp_ajax').html(jData); that.initializeByParam(); oCallback(); });
                }
                else {
                    jData.ready(function() { that.sendMessage('loaded'); that.jE.removeClass('jsp_ajax').html(jData); that.initializeByParam(); oCallback(); });
                }
                
                oReadyRunning = false;
            });
        }
        else {
            if (oParams.delay) {
                if (oParams['parseJSDs']) this.parseJSDs();
                else if (oParams['all'])  this.initializeAllChildren();
                else if (oParams['next']) this.initializeNextChildren();
                else                      this.initializeChildren();
                
                that.jE.removeClass('jsp_delay');
                oParams.delay = false;
                
                //alert(that.jE.html());
            }
            
            oCallback();
        }
    }
    
    this.Slide = function() {
        //TODO jsp_all --> jsp_next!
        if (!oParams.ajax && !oParams.delay) {
            if (oParams['parseJSDs']) this.parseJSDs();
            else if (oParams['all'])  this.initializeAllChildren();
            else if (oParams['next']) this.initializeNextChildren();
            else                      this.initializeChildren();
        }
        
        this.initSlide();
    }
    
    this.initSlide = function(bAddClass) {
        if (bAddClass) that.jE.addClass('jso_Slide');
        
        if (oParams['validate']) {
            //TODO this only has to be in /Slides/slideContainer/Page
            //     NOT in /Page! Object /Slides/Page, what to do?
            //     
            //     Also see this.getTitle: base function (ajax - text(), else h1), but overloaded in /Gallery/Page -> img alt!
            
            // register Message at parent, parent itself then has to register the msg at its parent!
            
            
            //TODO form validate messages inherit - nich mehr nötig!
            //     also mal noch drin, damit navButtons tun (aber nur noch bei iCurr < iPage, also vor, wird validiert!)
            //     aber das auch irgendwie besser machen? Soll Form bei 'validate' mitsenden, welches Obj. das getriggert hat,
            //     und hier nur was machen wenn das innerhalb Slides war?
            this.parentObj().parentObj().registerMessage('on_gotoSlide', this.validate);
        }
        
        this.parentObj().registerMessage('validate', this.validate);
        
        this.parentReady(function() {
            if (that.jE.prev('.jso_PageTitle').length) {
                var oPrev = that.sPath;
                var oRoot = that.sObjPath;
                
                sTitle = window.aes.getObj(that.jE.prev('.jso_PageTitle')).getTitle();
                //alert(that.getTitle());
            }
            
            iSlide = that.jE.prevAll('.jso_Slide').length + 1;
        });
    }
    
    this.validate = function(sMsg, oData) {
        //TODO hmmmm ... depends ... prev/next - ok. verttabs - not ok ... change this.validate in /verttabBox/Slide!
        //if (oData.iCurr > oData.iPage) return;
        
        var aErr = new Array();
        
        /*
        if (iSlide == oData.iCurr) {
            for (var iI = 0; iI < that.oChildren.length; iI++) {
                if (that.oChildren[iI].validate) {
                    var sErr = that.oChildren[iI].validate();
                    
                    if (sErr) aErr.push(sErr);
                }
            }
        }
        */
        
        // If gotoSlide - just check if current slide. otherwise always check!
        if ((iSlide == oData.iCurr) || (sMsg == 'validate')) aErr = that.sendMessage('validate');
        //alert(iSlide + ':' + oData.iCurr + '-------' + (aErr.join('').length ? new Array('error', aErr.join(', ')) : true));
        
        var bErr = aErr.join('').length ? true : false;
        
        that.sendMessage('valid', { bValid: !bErr });
        
        // .join is a quickfix, since sendMsg ALWAYS returns an array with one element for each
        // obj the msg was send, it doesn't check if the return exists ... always pushes it to the return array
        if (sMsg == 'validate') return aErr;
        else                    return bErr ? new Array('error', aErr.join(', ')) : true;
        // ... and this sucks. Should be handled the same way by jso_Form and jso_slideContainer (which fires the on_gotoSlide!)
    }
    
    /*
     * Methode .ready(oCallback)
     * wenn kein Ajax -> direkt oCallback
     * wenn oParams['ajax']
     *   - $.post mit ajax = true schicken
     *   - message (zB an Chef, der sich mit regMsg angemeldet hat): loading
     *   - wenn ajax fertig, loaded-message an chef UND oCallback()!
     *   - parameter an oCallback übergeben?
     *
     * jso_loadingAnimation
     *   - register bei chef: loading, loaded
     *   - chef muss die msg, wenn sie von slide kommt, weiterreichen, bzw. slide an container an chef
     *   - entsprechend Grafik anzeigen
     *   - hier auch gleich mal mit Templates und CSS rumexperimentieren. CSS einfach bei TPL rein?
     *     ggf. jso Container (div class="jso">), damit CSS "gekapselt" werden kann, dann
     *     direkt ins TPL das CSS, das soll ja sowieso immer speziell angepasst sein [isses ja in gallery.php!]
     *          -> aufpassen dass nur Elemente geCSSt werden, die noch nicht existieren!
     *
     * getContainer/oContainer umbenennen, z.B. in getBox, oBox
     *
     */
}
window.jso['/DebugIt'] = function() {
    this.DebugIt = function() {
        alert(this.sPath + '--------' + this.jE.text());
    }
}






window.jso['/Form'] = function() {
    var that = this;
    var oParams = this.getParams();
    
    this.addInheritMessage('validate');
    
    this.Form = function() {
        //TODO add 'next' ('closest'?)
        if (oParams['all']) this.initializeAllChildren();
        else if (oParams['next']) {
            this.initializeNextChildren();
        }
        else                this.initializeChildren();
    }
    
    this.submit = function() {
        var aErr = that.sendMessage('validate');
        
        //TODO brrrr ... unschön! aber wenn aErr per inheritMsg behandelt wird, ist das
        //           "mehrdimensional" ... wie wird das von den Messages geliefert?
        //           Ggf. bei den Messages schon mergen? --> Viele Unterelemente, viele Dimensionen!
        if (aErr && aErr.join('').replace(/,/g, '').length) {
            //alert(aErr.join('-').replace(/,,/g, ','));
            return false;
        }
        else {
            if (oParams.ajax) {
                /*
                var oFields = that.jE.serializeArray();
                var oPost   = new Object();
                
                for (var iI in oFields) {
                    if (oFields[iI].name.substr(oFields[iI].name.length - 2) == '[]') {
                        oPost[oFields[iI].name] = oFields[iI].value;
                    }
                    else oPost[oFields[iI].name] = oFields[iI].value;
                }
                
                jQuery.post(that.jE.attr('action'), oPost, function(sData, sStatus) {
                */
                jQuery.post(that.jE.attr('action'), that.jE.serialize(), function(sData, sStatus) {
                    // SEND MESSAGE 'success', mit sData, sStatus, action usw ...!!
                    
                    if (sData.indexOf('jso_alert') > -1) {
                        sData = sData.substr(sData.indexOf('~~~~') + 4);
                        sData = sData.substr(0, sData.indexOf('~~~~'));
                        
                        alert(sData);
                    }
                    else {
                        that.jE.html(sData);
                    }
                    
                    //TODO
                    // that.jE.after(sData).remove(); ?
                    // Return should be JSON - sStatus, sMsg, ...
                    
                    /*
                    if (sData == 'true') {
                        that.jE.html('<h1>Vielen Dank für Ihre Anfrage!</h1><p>Ein Vertriebsmitarbeiter wird umgehend mit Ihnen Kontakt aufnehmen.</p>');
                    }
                    else alert(sData);
                    */
                }, 'html');
            }
            else {
                that.jE.submit();
            }
            
            return true;
        }
    }
}


window.jso['_FormSubmit'] = '/defButton';
window.jso['/FormSubmit'] = function() {
    var that = this;
    var oParams = this.getParams();
    
    this.FormSubmit = function() {
        if (!that.jE.children('img').length) this.defButton();
        
        this.jE.click(function() {
            //var oC = that.callerObj();
            var oC = that.jE.closest('.jso_Form').getObj();
            
            if (oC.submit) if (!oC.submit()) {
                that.defButtonBlink();
            }
            
            that.jE.blur();
            return false;
        });
    }
}




window.jso['/FormLabel'] = function() {
    var that    = this;
    var jMaster = undefined;
    
    this.setRequired = function() {
        this.jE.html(this.jE.html() + '  <sup>*</sup>');
    }
    
    var showValid = function(sMsg, oD) {
        if (oD.bValid) {
            that.jE.css('color', '');
            //that.jE.children('span.jsc_Error').stop(true).fadeOut(function() { jQuery(this).remove(); });
            that.jE.children('span.jsc_Error').remove();
        }
        else {
            that.jE.css('color', 'red');
            that.jE.children('span.jsc_Error').remove(); // Just to make sure ...
            
            jQuery('<span />').addClass('jsc_Error').css('top', (that.jE.outerHeight() + jMaster.outerHeight() + 1)+'px')
                              .text(oD.sMsg).appendTo(that.jE);
        }
    }
    
    this.FormLabel = function() {
        if (!that.jE.attr('for')) return;
        
        if (jQuery('#' + that.jE.attr('for')).length) {
            jMaster = jQuery('#' + that.jE.attr('for'));
            
            this.parentReady(function() {
                window.aes.getObj(jMaster).registerMessage('valid', showValid);
                
                that.jE.mouseenter(that.showTooltip).mouseleave(that.hideTooltip);
                jMaster.mouseenter(that.showTooltip).mouseleave(that.hideTooltip);
            });
        }
    }
    
    this.showTooltip = function() {
        that.jE.children('span.jsc_Error').stop(true).css('opacity', 0).fadeIn(150, function() { jQuery(this).css('opacity', 1); });
    }
    
    this.hideTooltip = function() {
        that.jE.children('span.jsc_Error').stop(true).css('opacity', 1).fadeOut(150, function() { jQuery(this).css('opacity', 0); });
    }
}

//TODO Grundelement FormElement oder so? --> alle von da erben!
//     -> beispielsweise .validate schon drin, aber eine Methode .validator o.ä. wird aufgerufen!
window.jso['/FormText'] = function() {
    var that    = this;
    var oParams = this.getParams();
    
    this.validate = function() {
        if (oParams['required'] && !that.jE.attr('value').length) {
            //that.jE.css('border', '1px solid red');
            
            that.sendMessage('valid', { bValid: false, sMsg: 'Pflichtfeld' });
            
            return that.jE.attr('name') + ' ist Pflichtfeld';
        }
        else {
            //that.jE.css('border', '1px solid #e5e5e5');
            that.sendMessage('valid', { bValid: true });
        }
        
    }
    
    this.FormText = function() {
        //TODO nach dem label bei parent().children() suchen!
        if (oParams['required'] && jQuery('.jso_FormLabel').filter('[for=' + this.jE.attr('id') + ']').length) {
            this.parentReady(function() {
                window.aes.getObj(jQuery('.jso_FormLabel').filter('[for=' + that.jE.attr('id') + ']')).setRequired();
            });
        }
        
        if (window.jso_form_data[that.jE.attr('id')]) that.jE.val(window.jso_form_data[that.jE.attr('id')]);
        
        this.callerObj().registerMessage('validate', this.validate);
    }
}
window.jso['/FormTextarea'] = function() {
    var that    = this;
    var oParams = this.getParams();
    
    this.validate = function() {
        if (oParams['required'] && !that.jE.attr('value').length) {
            that.sendMessage('valid', { bValid: false, sMsg: 'Pflichtfeld' });
            
            return that.jE.attr('name') + ' ist Pflichtfeld';
        }
        else {
            that.sendMessage('valid', { bValid: true });
        }
    }
    
    this.FormTextarea = function() {
        if (oParams['required'] && jQuery('.jso_FormLabel').filter('[for=' + this.jE.attr('id') + ']').length) {
            this.parentReady(function() {
                window.aes.getObj(jQuery('.jso_FormLabel').filter('[for=' + that.jE.attr('id') + ']')).setRequired();
            });
        }
        
        if (window.jso_form_data[that.jE.attr('id')]) that.jE.val(window.jso_form_data[that.jE.attr('id')]);
        
        this.callerObj().registerMessage('validate', this.validate);
    }
}
window.jso['/FormEmail'] = function() {
    var that    = this;
    var oParams = this.getParams();
    
    this.validate = function() {
        if (oParams['required'] && !that.jE.attr('value').length) {
            that.sendMessage('valid', { bValid: false, sMsg: 'Pflichtfeld' });
            
            return that.jE.attr('name') + ' ist Pflichtfeld';
        }
        else if (that.jE.attr('value').length && (that.jE.attr('value').search('^[-_0-9a-zA-Z\\.]+@([-_0-9a-zA-Z]+\\.)+[a-zA-Z]+$') == -1)) {
            that.sendMessage('valid', { bValid: false, sMsg: 'Keine gültige E-Mail-Adresse' });
            
            return that.jE.attr('name') + ' ist keine gültige E-Mail-Adresse';
        }
        else {
            that.sendMessage('valid', { bValid: true });
        }
        
    }
    
    this.FormEmail = function() {
        //TODO nach dem label bei parent().children() suchen!
        if (oParams['required'] && jQuery('.jso_FormLabel').filter('[for=' + this.jE.attr('id') + ']').length) {
            this.parentReady(function() {
                window.aes.getObj(jQuery('.jso_FormLabel').filter('[for=' + that.jE.attr('id') + ']')).setRequired();
            });
        }
        
        if (window.jso_form_data[that.jE.attr('id')]) that.jE.val(window.jso_form_data[that.jE.attr('id')]);
        
        this.callerObj().registerMessage('validate', this.validate);
    }
}
window.jso['/FormUrl'] = function() {
    var that    = this;
    var oParams = this.getParams();
    
    this.validate = function() {
        if (oParams['required'] && !that.jE.attr('value').length) {
            that.sendMessage('valid', { bValid: false, sMsg: 'Pflichtfeld' });
            
            return that.jE.attr('name') + ' ist Pflichtfeld';
        }
        else if (that.jE.attr('value').length && (that.jE.attr('value').search('^(http:\\/\\/)?([\\-0-9a-zA-Z]+\\.)+[a-zA-Z]+(\\/[\\?,;=&:\\.\\-_0-9a-zA-Z]*)*$') == -1)) {
            that.sendMessage('valid', { bValid: false, sMsg: 'Keine gültige Web-Adresse' });
            
            return that.jE.attr('name') + ' ist keine gültige Web-Adresse';
        }
        else {
            //that.jE.css('border', '1px solid #e5e5e5');
            that.sendMessage('valid', { bValid: true });
        }
        
    }
    
    this.FormUrl = function() {
        //TODO nach dem label bei parent().children() suchen!
        if (oParams['required'] && jQuery('.jso_FormLabel').filter('[for=' + this.jE.attr('id') + ']').length) {
            this.parentReady(function() {
                window.aes.getObj(jQuery('.jso_FormLabel').filter('[for=' + that.jE.attr('id') + ']')).setRequired();
            });
        }
        
        if (window.jso_form_data[that.jE.attr('id')]) that.jE.val(window.jso_form_data[that.jE.attr('id')]);
        
        this.callerObj().registerMessage('validate', this.validate);
    }
}

window.jso['/FormSelect'] = function() {
    var that    = this;
    var oParams = this.getParams();
    
    this.validate = function() {
        if (oParams['required'] && !that.jE.children('input[type=checkbox]:checked').length) {
            that.sendMessage('valid', { bValid: false, sMsg: 'Mindestens einen Eintrag auswählen' });
            
            return that.jE.attr('name') + ' ist Pflichtfeld';
        }
        else {
            that.sendMessage('valid', { bValid: true });
        }
    }
    
    this.FormSelect = function() {
        //if (oParams.inputs) {
            this.jE.addClass('jsc_FormSelectDiv');
            // replaceTag('div'), ...
            // CHECK: replaceTag good method for copying, see Box
        //}
        //alert(this.jE.attr('id') + '-' + jQuery('.jso_FormLabel[for=' + this.jE.attr('id') + ']').length);
        if (oParams['required'] && jQuery('.jso_FormLabel[for=' + this.jE.attr('id') + ']').length) {
            this.parentReady(function() {
                window.aes.getObj(jQuery('.jso_FormLabel[for=' + that.jE.attr('id') + ']')).setRequired();
            });
        }
        
        if (window.jso_form_data[that.jE.attr('id')]) {
            var aChecked = window.jso_form_data[that.jE.attr('id')].split(',');
            
            for (var iI = 0; iI < aChecked.length; iI++) {
                if (that.jE.children('#' + that.jE.attr('id') + '_' + aChecked[iI]).length) {
                    that.jE.children('#' + that.jE.attr('id') + '_' + aChecked[iI]).attr('checked', 'checked');
                    
                }
            }
        }
        
        this.callerObj().registerMessage('validate', this.validate);
    }
}


window.jso['/FormImage'] = function() {
    var that    = this;
    var oParams = this.getParams();
    var oUpload = undefined;
    var sBorderColor = that.jE.css('border-color');
    
    this.validate = function() {
        if (oParams['required'] && !that.jE.children('input').attr('value').length) {
            that.sendMessage('valid', { bValid: false, sMsg: 'Bitte ein Bild hochladen!' });
            that.jE.css('border-color', 'red');
        }
        else {
            that.sendMessage('valid', { bValid: true });
            that.jE.css('border-color', sBorderColor);
        }
    }
    
    this.FormImage = function() {
        if (window.jso_form_data[that.jE.children('input').attr('id')]) {
            that.jE.children('input').val(window.jso_form_data[that.jE.children('input').attr('id')]);
            that.jE.css('background-image', 'url(uploads/tx_userseexec/' + that.jE.children('input').val() + ')');
        }
        
        if (oParams.required) that.jE.find('li.del').css('display', 'none');
        
        oUpload = new AjaxUpload(that.jE.find('li.upload'), {
            //TODO siehe jQuery - get - auf ? checken, je nachdem ?no_cache oder &no_cache ...
            action: location.href + '&no_cache=1',
            
            name: that.jE.children('input').attr('name'),
            data: { uploaded_file: that.jE.children('input').attr('name') },
            onComplete: function (sFile, sResponse) {
                //alert(sFile);
                //alert(sResponse);
                
                if (sResponse) {
                    that.jE.children('input').val(sFile);
                    that.jE.css('background-image', 'url(uploads/tx_userseexec/' + that.jE.children('input').val() + ')');
                }
                else alert('Fehler ...');
            }
        });
        
        that.jE.find('li.del').click(function() {
            that.jE.children('input').val('');
            that.jE.css('background-image', 'none');
        });
        
        this.callerObj().registerMessage('validate', this.validate);
    }
}

















window.jso['/Slides/navMenu'] = function() {
    /* 
     * jsp_next, jsp_prev --> vor/zurück anzeigen
     * jsp_num            --> numerische Links, keine TextLinks
     *          -> unsinn? Weil in /Slides IMMER num?
     * 
     * next/prev: einerseits das HTML dazu, andererseits bei onGoto auf
     * 1 / letztes slide checken -> ausgrauen, außerdem oP.nextPage ...?
     * 
     * jsp_auto bei Slides -> wenn nicht mouseover, timeouten und sliden
     *  -> timeout zuende und mouseover -> auf mouseleave warten
     *  -> wenn letzte Seite, auf erste!
     * 
     */
    var that = this;
    
    this.getNavElement = function(iI, iMax, oC) {
        var jElem = jQuery(document.createElement('a')).appendTo(jQuery(document.createElement('li')).appendTo(this.jE)).attr('href', '#').html(iI);
        
        //if (iI == 1) jElem.addClass('active').before('<img class="jsc_borderLeft" src="http://www.dci.de/fileadmin/templates/themenwelten/img/corner_left_company.gif" />');
        
        return jElem;
    }
    
    /*
    this.setActive = function(sMsg, iLink) {
        that.jE.find('a').removeClass('active').filter(':eq('+(iLink)+')').addClass('active');
    }
    */
    
    this.onAdditionalGoto = function(oP, oLink) {
        if (jQuery(oLink).hasClass('jsc_prev'))      oP.prevSlide(true);
        else if (jQuery(oLink).hasClass('jsc_next')) oP.nextSlide(true);
    }
    
    this.navMenu = function() {
        this.initNavMenu();
        
        /*
        var jPrev = jQuery(document.createElement('a')).appendTo(jQuery(document.createElement('li'))).attr('href', '#')
                    .html('<img src="http://data.dci-se.de/img/navMenu-subtab_prev.gif" />').addClass('jsc_prev');
        */
        var jPrev = jQuery(document.createElement('img')).appendTo(jQuery(document.createElement('li'))).addClass('jsc_prev')
                    .attr('src', 'http://data.dci-se.de/img/navMenu-subtab_prev.gif').css('margin-right', '1px').css('cursor', 'pointer');
        var jNext = jQuery(document.createElement('img')).appendTo(jQuery(document.createElement('li'))).addClass('jsc_next')
                    .attr('src', 'http://data.dci-se.de/img/navMenu-subtab_next.gif').css('margin-right', '1px').css('cursor', 'pointer');
        
        jPrev.before('<img class="jsc_borderLeft" src="http://data.dci-se.de/img/navMenu-subtab_corner_left.gif" />');
        jNext.after('<img class="jsc_borderRight" src="http://data.dci-se.de/img/navMenu-subtab_corner_right.gif" />');
        
        this.setAdditionalElem(jPrev, true);
        this.setAdditionalElem(jNext);
    }
}





window.jso['/Slides/navButtons'] = function() {
    /* Evtl. funktion this.rootObj(sTag)
     * -> parents(sTag + ':first') ?
     *    oder macht parents, wenn man was übergibt, eh den ersten?
     *
     * -> oP = this.rootObj('Slides');
     * -> wenn navButtons innerhalb slideBox andere position als fadeBox!
     */
    
    var oP   = null;
    var that = this;
    
    var oCSS = {
        'position': 'absolute',
        'left': '20px'
    };
    var oLinkCSS = {
        'background-color': '#808080',
        'display': 'block',
        'float': 'left',
        'padding': '3px 7px',
        'margin-right': '1px',
        'color': 'white',
        'text-decoration': 'none',
        'font-size': '11px',
        'line-height': '14px'
    };
    
    this.setActive = function(sMsg, iLink) {
        that.jE.children('a').removeClass('active').css('font-weight', 'normal').filter(':eq('+(iLink - 1)+')').addClass('active').css('font-weight', 'bold');
    }
    
    this.navButtons = function() {
        oP = this.parentObj();
        
        var oOffset = oP.getContainer().jE.position();
        
        oP.registerMessage('show', this.setActive);
        this.jE.css(oCSS).css('top', (oOffset.top + 1) + 'px');
        
        
        // To create buttons, use this.createButtons which is defined in /navButtons
        // --> reusable stlye ;)
        for (var iI = 1; iI <= oP.getPageCount(); iI++) {
            jQuery.data(jQuery(document.createElement('a')).attr('href', '#').css(oLinkCSS).html(iI).click(function() {
                oP.gotoSlide(jQuery.data(this, 'page'));
                
                return false;
            }).appendTo(this.jE).mouseenter(mouseOver).mouseleave(mouseOut).get(0), 'page', iI);
        }
    }
    
    
    var mouseOver = function() { jQuery(this).css('font-weight', 'bold'); }
    var mouseOut  = function() { if (!jQuery(this).hasClass('active')) jQuery(this).css('font-weight', 'normal'); }
}

window.jso['/navButton'] = function(superClass) { //, fId) {
    var oP      = this.parentObj();
    var that    = this;
    var oParams = this.getParams();
    
    var sM = 'papaString';
    
    checkFirst = function(sMsg, iSlide) {
        if ((oP.getPageCount() == iSlide) && oParams['next']) that.jE.hide();
        else if ((1 == iSlide) && oParams['prev'])            that.jE.hide();
        else that.jE.show();
        
        //$(sM + '_papaStr');
    }
    
    //var $ = this.$(fId, this.iObjs++);
    //$('after', 'hallo');
    
    oP.registerMessage('show', checkFirst);
}

window.jso['/Slides/navButton'] = function(superClass){ //, fId) {
    var oP   = null;
    var that = this;
    var sDef = 'next';
    
    var sM = 'babyString';
    
    
    /*
     * HTML Contents and CSS
     */
    var sType;
    var sText;
    var oNewPage;
    
    var oCSS = {
        'position': 'absolute',
        'width' : '20px',
        'height' : '20px',
        'font-size' : '25px',
        'line-height' : '16px',
        'text-align': 'center',
        'cursor' : 'pointer'
    };
    var oTitleCSS = {
        'position': 'absolute',
        'top': 0,
        'overflow': 'hidden',
        'padding': '3px 10px',
        'background-color': '#808080',
        'color': 'white',
        'font-size': '11px',
        'white-space': 'nowrap',
        'line-height': '14px'
        
    };
    
    var setDefaults = function() {
        if (sType == 'prev') {
            oTitleCSS.left = '20px';
            oCSS.left      = '-20px';
            sText          = '&laquo;';
            
            oNewPage = function() {
                return oP.getCurrPage() - 1;
            };
            
            // Also possible ... always go to first slide
            // oNewPage = 1;
        
        }
        else if (sType == 'next') {
            oTitleCSS.right = '20px';
            oCSS.right      = '-20px';
            sText           = '&raquo;';
            
            oNewPage = function() {
                return oP.getCurrPage() + 1;
            };
        }
    }
    
    this.navButton = function() {
        oP = this.parentObj();
        
        //this.$('before');
        //var $ = this.$(fId, this.iObjs++);
        //$('after', 'nee');
        //alert($('after'));
        
        //var o = this.xy();
        //o();
        //that.xy = superClass.xy;
        //that.xy();
        
        var oParams = this.getParams();
        
        if (oParams['next'])      sType = 'next';
        else if (oParams['prev']) sType = 'prev';
        else                      sType = sDef;
        
        setDefaults.call(this);
        this.jE.css(oCSS);
        
        var jContainer = oP.getContainer().jE;
        var oOffset    = jContainer.position();
        var iHeight    = jContainer.outerHeight();
        var iTop       = Math.round(oOffset.top + (iHeight / 2) - (this.jE.height() / 2));
        
        this.jE.css('top', iTop).html(sText).click(function() {
            oP.gotoSlide((jQuery.isFunction(oNewPage) ? oNewPage.call(that) : oNewPage));
        });
        
        oP.registerMessage('show', fadeMouseover);
        oP.registerMessage('error_gotoSlide', errorMouseover);
        //oP.registerMessage('show', that.jE.mouseleave);
        
        
        // Because addMouseOver wouldn't have "this" otherwise!
        addMouseOver.call(this);
    }
    
    var addMouseOver = function() {
        // Mouseover
        this.jE.mouseenter(function() { eventMouseLeave.call(that); });
        
        this.jE.mouseleave(function() {
            that.jE.css('color', '').children('span').stop(true).animate({ 'width': 0 }, function() { jQuery(this).remove(); });
        });
    }
    
    var eventMouseLeave = function() {
        var oContainer = oP.getContainer();
        var sTitle     = oContainer.aSlides[(jQuery.isFunction(oNewPage) ? oNewPage.call(this) : oNewPage)];
        
        if (sTitle) {
            var jTitle = jQuery(document.createElement('span')).css(oTitleCSS).appendTo(this.jE).text(sTitle);
            
            var iW = jTitle.width();
            
            if (jQuery.browser.msie || jQuery.browser.opera) iW = (6 * sTitle.length) + 'px';
            
            jTitle.css('width', 0).animate({ 'width': iW });
        }
        
        this.jE.css('color', 'red');
    }
    
    var fadeMouseover = function() {
        var iSlide = (jQuery.isFunction(oNewPage) ? oNewPage.call(that) : oNewPage);
        //that.jE.children('span').stop(true).animate({ 'width': 0 }, function() { jQuery(that).remove(); });
        
    		var oContainer = oP.getContainer();
    		var sTitle     = oContainer.aSlides[iSlide];
		    
		    if (sTitle) {
            that.jE.children('span').stop(true).fadeOut('fast', function() {
        				jQuery(this).remove();
        				
        				var jTitle = jQuery(document.createElement('span')).css(oTitleCSS).appendTo(that.jE).text(sTitle);
        				
        				var iW = jTitle.width();
        				
        				if (jQuery.browser.msie || jQuery.browser.opera) iW = (6 * sTitle.length) + 'px';
        				
        				jTitle.fadeIn('fast');
            });
        }
    }
    
    var errorMouseover = function() {
        // Hier evtl. Check einbauen ob das wirklich der eigene Button war, zB
        // temp. private variable auf "clicked" setzen oder so
        
        that.jE.children('span').animate({ 'color': 'white' }, 50, function() {
            jQuery(this).animate({ 'color': 'red' }, 50, function() {
                jQuery(this).animate({ 'color': 'white' }, 50, function() {
                    jQuery(this).animate({ 'color': 'red' }, 50, function() {
                        jQuery(this).animate({ 'color': 'white' }, 50);
                    });
                });
            });
        });
    }
    
    return this;
}





















window.jso['/loadingAnimation'] = function(superClass) { //, fId) {
    var oP      = this.parentObj();
    var that    = this;
    
    showLoader = function(sMsg) {
        /* loadingAni - top!
         * erster Aufruf - warum ani nich da?
         * erster Aufruf - Höhe?
         */
        
        if (that.jE.offset().top == 0) {
            that.jE.css('margin-top', 0);
        }
        
        that.jE.fadeIn(250);
    }
    
    hideLoader = function(sMsg) {
        that.jE.fadeOut(250);
    }
    
    //TODO - get Template and the CSS within
    //this.jE.text('Loading ...').css({ 'position': 'absolute', 'top': '30px', 'right': '20px', 'display': 'none' });
    this.jE.html('<img src="http://data.dci-se.de/img/loading.gif" />').css({ 'position': 'absolute', 'top': '50%', 'left': '50%', 'display': 'none', 'margin': '-150px 0 0 -150px', 'opacity': 0.40 });
    
    oP.registerMessage('loading', showLoader);
    oP.registerMessage('loaded',  hideLoader);
}








/*
 *
 * childrenReady -> macht man doch eh selber, eigentlich,
 *                  brauchts des dann?
 * childrenLoaded schon eher ...
 *
 */
