/*
 * Initiert und steuert die Scrollboxen für Webservice-Inhalte
 * 
 * @author Wolfgang Merkens <wm@traveltainment.de>
 * @copyright  2010 Traveltainment AG
 */
 
/*
 * Erweitere alle Funktionsobjekte um eine Methode »bind« über die 
 * prototype-Eigenschaft des Function-Konstruktors.
 */
if (typeof(Function.prototype.bind) != 'function') {     
    Function.prototype.bind = function(object) {         
        // Speichere die gegenwärtige Funktion in »theMethod«.
        var theMethod = this;        
        // Die Closure-Funktion schließt »theMethod«, »object« und »arguments« ein.
        // Rufe die Funktion im Kontext des Objektes »object« auf,
        // reiche dabei die restlichen Parameter durch und
        // gib den Rückgabewert der Funktion zurück.
        return function() {
            return theMethod.apply(object, arguments);
        }
    }     
}

/*
 * Konstruktor
 */
function TTScrollBox() {      
    this.actBoxId       = ''; //id der aktuell geöffneten Box 
    this.actScrollType  = ''; //content-Typ der aktuell geöffneten Box  
    this.actSourceElem  = null; //Quell-Element, welches die aktuelle Box geöffnet hat
    this.livingBoxes    = new Array(); //array mit id und typ bislang geöffneter Boxen
    this.boxHeight      = '600'; //Default Höhe der Boxen (600px) 
    this.box            = null; //Objekt der aktuellen ScrollContentBox   
    this.loadImage      = ''; //Name der Grafik für den Ladevorgang
    this.openEffect     = true; //Scrolleffekt beim Öffnen ja/nein
    this.closeEffect    = true; //Scrolleffekt beim Schließen ja/nein
    this.durationOpen   = 500; //Default-Scroll-Dauer in ms (500) 
    this.durationClose  = 300; //Default-Scroll-Dauer in ms (300) 
    this.reqDuration    = null; //akt. benutzte Scrolldauer (wird an js-func navigate übergeben)
    this.stepTime       = 20; //Default-Scroll-Speed in ms (20) 
    this.bottomRefElem  = null;
    this.boxBottom      = null;
    this.boxCloseElem   = null;  
    this.actRefBox      = null;  
    this.socketClose    = new Object(); 
    this.actPort        = '';
    this.forceRequest   = false;    //forciert einen neuen Ajaxrequest, z.B. für die Ajax-Terminseite nötig
}

/*
 * Box für scrollbaren Webservice-Content generieren
 */
TTScrollBox.prototype.boxControl = function(elem) {     
    if (typeof(elem) != 'object') {
        var elem = document.getElementById(elem);
    }
    //Default-Startwerte         
    this.newBoxId        = '';
    this.boxStatus       = '';    
    this.newScrollType   = '';     
    this.boxAction       = '';
    this.procedure       = '';
    this.newRefBox       = null;
    this.newReqArt       = '';
    this.newParams       = ''; 
    this.newSourceElem   = elem;    
    this.socketOpen      = new Object();  
    this.newPort         = '';              
    // --- Attribute der geklickten Box definieren    
    if (typeof(elem) == 'object' && typeof(elem.attributes) == 'object' && elem.attributes.length > 0) {
        this.newRefBox     = document.getElementById(elem.getAttribute('scrollreference', 0));
        this.newScrollType = elem.getAttribute('scrolltype', 0);                  
        this.newReqArt     = elem.getAttribute('scrollrequest', 0);
        this.forceRequest  = Boolean(elem.getAttribute('scrollforcerequest', 0));
        this.newParams     = elem.getAttribute('scrollparams', 0);
        this.newPort       = elem.getAttribute('scrollport', 0);
        if (this.newPort == null) {
            this.newPort = '';
        }          
        //params-string zerlegen
        if (this.newParams != null && this.newParams != '') {
            var tmpParam = this.newParams.split('&');
            if (tmpParam.length > 0) {
                for(var i = 0; i < tmpParam.length; i ++) {
                    var tmpRequest = tmpParam[i].split('=');
                    if (tmpRequest[0] == 'idContent') {
                        this.newBoxId = tmpRequest[1];
                        break;    
                    }
                }
            }    
        }         
        // --- Weitere Prozedur bestimmen 
        this.setBoxProcedure();          
    }          
}

/*
 * Entscheidet, welche 'open/close'-Prozedur gestartet wird
 */
TTScrollBox.prototype.setBoxProcedure = function() {
    //Gibt es bereits eine geöffnete Box?    
    if (this.actBoxId != '') {        
        //geklickte Box ist bereits geöffnet
        if (this.actBoxId == this.newBoxId) {
            //Gleicher Content-Typ?
            if (this.actScrollType == this.newScrollType) {
                this.procedure = 'selfClose_noOpen';
                this.closeTheBox();
            } else {                
                this.refreshBoxInSameReference();
            }                 
        } else {
            //Akt.Box schliessen und neue öffnen
            this.procedure = 'oldClose_newOpen';  
            this.closeTheBox();  
        }   
    } else {
        //Box öffnen / alle anderen sind geschlossen
        this.procedure = 'noClose_newOpen';
        this.setNewBoxProcess();
    } 
}

/*
 * Wurde Container für diese Box schon einmal angelegt oder muß dieser 
 * neu erzeugt werden? 
 */
TTScrollBox.prototype.defineTheBox = function() {     
    var isDefined = true;     
    //Container neu anlegen?
    if(document.getElementById('scrollContent_' + this.newScrollType + '_' + this.newBoxId) == null) {
        if (typeof(this.newRefBox) != 'undefined') {
            //id für newDiv anlegen
            var newDiv          = document.createElement('div');        
            var newDiv_id       = document.createAttribute('id');
            newDiv_id.nodeValue = 'scrollContent_' + this.newScrollType + '_' + this.newBoxId;
            newDiv.setAttributeNode(newDiv_id); 
            //class für newDiv anlegen
            var newDiv_class       = document.createAttribute('class');
            newDiv_class.nodeValue = 'tt_scrollContent_' + this.newScrollType;
            newDiv.setAttributeNode(newDiv_class);              
            // --- func insertAfter fügt div hinter Referenz-Box ein
            this.insertAfter(this.newRefBox, newDiv);             
            // abfangen
            if(document.getElementById('scrollContent_' + this.newScrollType + '_' + this.newBoxId) == null) {
                return false;
            }             
            //Bottom-Zeile für Content-Box?
            this.bottomRefElem = document.getElementById('scrollContent_' + this.newScrollType + '_' + this.newBoxId);                          
            //ind. callback-Func?
            if (typeof(ttsb_createBottomContent) == 'function') {                
                this.boxBottom = ttsb_createBottomContent(this);
            } else {
                //standard-Func
                this.createBottomContent();
            }               
        } else {
            isDefined = false;
        }   
    }       
    if (isDefined) {
        this.box = document.getElementById('scrollContent_' + this.newScrollType + '_' + this.newBoxId);          
        if (this.box != null) {
            this.box.style.height  = '0px';
            this.box.style.display = 'none';  
            if (this.boxBottom == null) {
                this.boxBottom = document.getElementById('scrollContentBottom_' + this.newScrollType + '_' + this.newBoxId);
                if (this.boxCloseElem == null) {
                    this.boxCloseElem = document.getElementById('scrollContentBottomClose_' + this.newScrollType + '_' + this.newBoxId);
                }               
            }
            if (this.boxBottom != null) {
                this.boxBottom.style.display = 'none';
                if (this.boxCloseElem != null) {
                    this.boxCloseElem.style.display = 'none';
                }
            }
        }
    }     
    return isDefined;      
}

//Neue Contentbox wird im dom-baum hinter Referenz-Box angelegt
TTScrollBox.prototype.insertAfter = function(referenceNode, newNode) {
    if (referenceNode) {
        if (referenceNode.parentNode) {
            if (referenceNode.nextSibling) {         
                referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
            } else {
                referenceNode.parentNode.appendChild(newNode);
            }
        } else {
            referenceNode.appendChild(newNode);
        } 
    }  
}

/*
 * Definiert eine neue Box und öffnet sie  
 */
TTScrollBox.prototype.setNewBoxProcess = function() {      
    if (this.defineTheBox()) {
        this.actBoxId      = this.newBoxId; 
        this.actScrollType = this.newScrollType; 
        this.actSourceElem = this.newSourceElem; 
        this.actRefBox     = this.newRefBox;
        this.actPort       = this.newPort;
        this.boxStatus     = this.updateLivingBoxes();          
        if (this.boxStatus == 'old') {  
            this.openTheBox();                    
            refreshContent(this.newBoxId, this.newScrollType);  
        } else if (this.boxStatus == 'new') {                    
            this.openTheBox();
            navigate(this.newParams, 'scrollContent_' + this.newScrollType + '_' + this.newBoxId, this.loadImage, this.newReqArt, this.newPort, this.reqDuration);    
        } 
    }      
}

/*
 * Zur selben ReferenzBox ist bereits eine andere ScrollContentBox geöffnet. Diese wird 
 * geschlossen und eine neue wird zur gleichen ReferenzBox geöffnet (ohne Scrolleffekte)   
 */
TTScrollBox.prototype.refreshBoxInSameReference = function() {  
    this.boxAction = 'close';      
    if (this.box) {
        //Aktive Box wird geschlossen
        this.box.style.height  = '0px'; 
        this.box.style.display = 'none'; 
        //ind. callback-Func?
        if (typeof(ttsb_setBoxStatusClose) == 'function') {                
            this.setSocketClose();
            ttsb_setBoxStatusClose(this.socketClose);
        }
        if (this.boxBottom != null) {                          
            if (this.boxCloseElem != null) {
                this.boxCloseElem.style.display = 'none';
                this.boxCloseElem = null;
            }
            this.boxBottom.style.display = 'none';
            this.boxBottom = null;
        }
        this.actBoxId      = ''; 
        this.actScrollType = '';
        this.actPort       = '';
        this.actSourceElem = null;
        this.actRefBox     = null;
        this.box           = null;
        //Neue Box öffnen
        if (this.defineTheBox()) {
            this.actBoxId      = this.newBoxId; 
            this.actScrollType = this.newScrollType;
            this.actSourceElem = this.newSourceElem; 
            this.actPort       = this.newPort;
            this.actRefBox     = this.newRefBox; 
            this.boxStatus     = this.updateLivingBoxes();
            this.boxAction     = 'open';               
            this.box.style.height  = this.boxHeight + 'px'; 
            this.box.style.display = 'block';
            if (this.boxBottom != null) {
                this.boxBottom.style.display = 'block';
                if (this.boxCloseElem != null) {
                    this.boxCloseElem.style.display = 'block';
                }
            }             
            //ind. callback-Func?
            if (typeof(ttsb_setBoxStatusOpen) == 'function') {                
                this.setSocketOpen();
                ttsb_setBoxStatusOpen(this.socketOpen);
            }                     
            if (this.boxStatus == 'old') {
                refreshContent(this.newBoxId, this.newScrollType);  
            } else if (this.boxStatus == 'new') {
                navigate(this.newParams, 'scrollContent_' + this.newScrollType + '_' + this.newBoxId, this.loadImage, this.newReqArt, this.newPort, this.reqDuration);    
            } 
        }
    }     
}

/*
 * Öffnet eine neue Box 
 */
TTScrollBox.prototype.openTheBox = function() { 
    this.boxAction = 'open';       
    if (this.box) {        
        if (this.boxHeight > 0) { 
            if (this.openEffect) { 
                this.reqDuration = this.durationOpen;
                this.box.style.height  = '0px';
                this.box.style.display = 'block';                
                this.transform(0, this.boxHeight);
                if (this.boxBottom != null) {
                    this.boxBottom.style.display = 'block';
                    if (this.boxCloseElem != null) {
                        this.boxCloseElem.style.display = 'block';
                    }
                }    
            } else {
                this.box.style.height  = this.boxHeight + 'px'; 
                this.box.style.display = 'block'; 
                if (this.boxBottom != null) {
                    this.boxBottom.style.display = 'block';
                    if (this.boxCloseElem != null) {
                        this.boxCloseElem.style.display = 'block';
                    }
                }  
            }              
            //ind. callback-Func?
            if (typeof(ttsb_setBoxStatusOpen) == 'function') {                
                this.setSocketOpen();
                ttsb_setBoxStatusOpen(this.socketOpen);
            }               
        }                  
    }      
}

/*
 * Schließt eine Box 
 */
TTScrollBox.prototype.closeTheBox = function() {  
    this.boxAction = 'close';      
    if (this.box) {
        if (this.boxHeight > 0) {
            if (typeof(this.procedure) == 'undefined' || this.procedure == '') {
                this.procedure = 'selfClose_noOpen';
            }  
            if (this.boxBottom != null) {                 
                if (this.boxCloseElem != null) {
                    this.boxCloseElem.style.display = 'none';
                    this.boxCloseElem = null;
                }
                this.boxBottom.style.display = 'none';
                this.boxBottom = null;
            }            
            if (this.closeEffect) {                 
                this.reqDuration = this.durationClose;
                this.transform(0, this.boxHeight);    
            } else {
                this.box.style.height  = '0px'; 
                this.box.style.display = 'none'; 
                //ind. callback-Func?
                if (typeof(ttsb_setBoxStatusClose) == 'function') {                
                    this.setSocketClose();
                    ttsb_setBoxStatusClose(this.socketClose);
                }                
                this.actBoxId      = ''; 
                this.actScrollType = '';
                this.actPort       = '';
                this.actSourceElem = null;
                this.actRefBox     = null;
                this.box           = null; 
                //Soll eine neue Box geöffnet werden?
                if (this.procedure != 'selfClose_noOpen') {
                    this.setNewBoxProcess();
                }                  
            }                             
        }    
    }      
}

/*
 * Array der bereits geöffneten Boxen auffrischen  
 */
TTScrollBox.prototype.updateLivingBoxes = function() {     
    var boxType = 'old'; 
    var newKey  = this.livingBoxes.length;
    var z       = 0;      
    if (newKey > 0 && !this.forceRequest) {
        //Ist aktive Box bereits gespeichert?
        for(var i = 0; i < newKey; i ++) {
            if (this.livingBoxes[i]['id'] == this.actBoxId && this.livingBoxes[i]['type'] == this.actScrollType) {
                z ++;
                break;
            }    
        } 
    } 
    //Neuen Speicher für aktive Box anlegen
    if (z == 0 || this.forceRequest) {
        this.livingBoxes[newKey]         = new Object();
        this.livingBoxes[newKey]['id']   = this.actBoxId;
        this.livingBoxes[newKey]['type'] = this.actScrollType;          
        boxType = 'new';
    }   
    return boxType;        
}

/*
 * Standard-Bottom-Zeile unterhalb der ScrollContentBox  
 */
TTScrollBox.prototype.createBottomContent = function() {    
    // --- Äußeres Div der bottom-Zeile erzeugen
    var mainDiv = document.createElement('div');        
    //id für mainDiv anlegen
    var mainDiv_id       = document.createAttribute('id');
    mainDiv_id.nodeValue = 'scrollContentBottom_' + this.newScrollType + '_' + this.newBoxId;
    mainDiv.setAttributeNode(mainDiv_id);
    //class für mainDiv anlegen
    var mainDiv_class       = document.createAttribute('class');
    mainDiv_class.nodeValue = 'tt_scrollBoxBottom';
    mainDiv.setAttributeNode(mainDiv_class);  
    // --- func insertAfter fügt bottom-Zeile in Dom-Baum ein
    this.insertAfter(this.bottomRefElem, mainDiv);     
    this.boxBottom = document.getElementById(mainDiv_id.nodeValue); 
    if (this.boxBottom) {    
        // --- Inneres Div der bottom-Zeile erzeugen
        var innerDiv = document.createElement('div');
        //id für innerDiv anlegen
        var innerDiv_id       = document.createAttribute('id');
        innerDiv_id.nodeValue = 'scrollContentBottomClose_' + this.newScrollType + '_' + this.newBoxId;
        innerDiv.setAttributeNode(innerDiv_id);
        //class für innerDiv anlegen
        var innerDiv_class       = document.createAttribute('class');
        innerDiv_class.nodeValue = 'tt_scrollBoxBottomClose';
        innerDiv.setAttributeNode(innerDiv_class);
        // --- Inneres Div in äußeres Div einfügen    
        this.boxBottom.appendChild(innerDiv);
        // --- Close-Div mit onclick-Funktion belegen 
        this.boxCloseElem = document.getElementById(innerDiv_id.nodeValue);
        this.boxCloseElem.onclick = function() {
            this.setBoxProcedure();         
        }.bind(this); 
    }        
}

/*
 * Definiert Werte zur Übergabe an callback-Funktion "ttsb_setBoxStatusOpen"  
 */
TTScrollBox.prototype.setSocketOpen = function() {     
    this.socketOpen.refBox       = this.newRefBox;
    this.socketOpen.box          = this.box;
    this.socketOpen.boxId        = this.newBoxId;
    this.socketOpen.scrollType   = this.newScrollType;
    this.socketOpen.sourceElem   = this.newSourceElem;  
    this.socketOpen.scrollPort   = this.newPort;  
    this.socketOpen.boxCloseElem = this.boxCloseElem;
    this.socketOpen.boxBottom    = this.boxBottom; 
}

/*
 * Definiert Werte zur Übergabe an callback-Funktion "ttsb_setBoxStatusClose"  
 */
TTScrollBox.prototype.setSocketClose = function() {     
    this.socketClose.refBox       = this.actRefBox;
    this.socketClose.box          = this.box;
    this.socketClose.boxId        = this.actBoxId;
    this.socketClose.scrollType   = this.actScrollType;
    this.socketClose.sourceElem   = this.actSourceElem;
    this.socketClose.scrollPort   = this.actPort;     
}

//Höhe der ScrollContentBox neu bestimmen
TTScrollBox.prototype.setBoxHeight = function(boxheight) {
    if (isNaN(boxheight)) {
        return false;
    }
    this.boxHeight = String(boxheight);     
}

//Lade-Grafik für ScrollContentBox neu bestimmen (Format: "ajax_loader.gif")
TTScrollBox.prototype.setLoadImage = function(imgname) {
    if (imgname != '') {
        this.loadImage = String(imgname);
    }         
}

//Scrolleffekt beim Öffnen der ScrollContentBox neu bestimmen
TTScrollBox.prototype.setOpenEffect = function(trim) {
    if (trim == true || trim == 1) {
        this.openEffect = true;
    } else {
        this.openEffect = false;
    }
}

//Scrolleffekt beim Schliessen der ScrollContentBox neu bestimmen
TTScrollBox.prototype.setCloseEffect = function(trim) {
    if (trim == true || trim == 1) {
        this.closeEffect = true;
    } else {
        this.closeEffect = false;
    }
}

//Scroll-Dauer beim Öffnen der ScrollContentBox neu bestimmen
TTScrollBox.prototype.setDurationOpen = function(duration) {
    if (isNaN(duration)) {
        return false;
    }
    this.durationOpen = parseInt(duration);     
}

//Scroll-Dauer beim Schliessen der ScrollContentBox neu bestimmen
TTScrollBox.prototype.setDurationClose = function(duration) {
    if (isNaN(duration)) {
        return false;
    }
    this.durationClose = parseInt(duration);     
}

//Scroll-Speed beim Schliessen der ScrollContentBox neu bestimmen
TTScrollBox.prototype.setStepTime = function(speed) {
    if (isNaN(speed)) {
        return false;
    }
    this.stepTime = parseInt(speed);     
}

/*
 * 3 Methoden (transform, step, effect) zur Steuerung des Scrolleffektes  
 */
TTScrollBox.prototype.transform = function(from, to) {     
    this.posStart  = from;
    this.posEnd    = to;    
    this.startTime = (new Date()).getTime();     
    this.stepper   = window.setInterval(this.step.bind(this), this.stepTime);
}

TTScrollBox.prototype.step = function() { 
    var time = (new Date()).getTime();
    
    if (this.box) {
        //damit Scrolleffekt auch bei refreshContent sichtbar ist
        if (this.openEffect && this.boxAction == 'open' && this.box.style.overflow != 'hidden') {        
            this.box.style.overflow = 'hidden';   
        } else if (this.closeEffect && this.boxAction == 'close' && this.box.style.overflow != 'hidden') {        
            this.box.style.overflow = 'hidden';
        } 
        //Scrollprozess beenden?
        if (time >= (this.reqDuration + this.startTime)) {
            if (this.boxAction == 'open') {
                this.box.style.height = this.posEnd+"px";    
            } else {
                this.box.style.height = this.posStart+"px";    
            }        
            //damit Scrolleffekt auch bei refreshContent sichtbar ist
            if (this.openEffect && this.boxStatus == 'old' && this.boxAction == 'open' && this.box.style.overflow != 'visible') {
                this.box.style.overflow = 'visible';
            }         
            if (this.closeEffect && this.boxAction == 'close') {
                this.box.style.display = 'none'; 
                //ind. callback-Func?
                if (typeof(ttsb_setBoxStatusClose) == 'function') {                
                    this.setSocketClose();
                    ttsb_setBoxStatusClose(this.socketClose);
                }            
                this.actBoxId      = ''; 
                this.actScrollType = '';
                this.actPort       = '';
                this.actSourceElem = null;
                this.box           = null;             
            }         
            window.clearInterval(this.stepper);
            this.stepper = null;          
            //Soll eine neue Box geöffnet werden?
            if (this.closeEffect && this.boxAction == 'close' && this.procedure != 'selfClose_noOpen') {
                this.setNewBoxProcess();
            } 
        } else {
            var pos     = (time - this.startTime) / (this.reqDuration);  
            var posCalc = this.effect(pos) * (this.posEnd - this.posStart);      
            if (this.boxAction == 'open') {            
                this.box.style.height = String(Math.floor(posCalc + this.posStart)) + 'px';    
            } else {             
                this.box.style.height = String(Math.floor(this.posEnd - posCalc)) + 'px';               
            }
        }  
    }    
}

TTScrollBox.prototype.effect = function(pos) {
    return ((-Math.cos(pos * Math.PI) / 2) + 0.5);
}

/*
 * Instanz aufrufen
 */
var ttScrollBox = new TTScrollBox();
