/*
 * Umożliwia wysłanie zapytania i wprowadza
 * odpowiednią do wskazanego elementu ID
 * lub uzyskanego w odpowiedzi jako nazwą taga korzennego
 *
 * @version 6.1.3
 *
 * 5.1.0 - Wyłączenie roizpaczy jeśłi nie ma widoków. To jest prawidłowe działanie.
 *         Także zmiana komunikatu kiedy nie ma obiektu do którego należy wrzucić zawartość*
 * 5.2.0 - Nowy sposób reprezentacji zmiennych (bardziej uniwersalny)
 * 5.3.0 - (obs) Wprowadzenie celu wyprowadzenia statusu statusTarget
 * 5.4.0 - (obs) Rozróżnienie metody get od send ze względu na parametry
 *          Można się zastanowić na nad metodą post. Niemniej mamy FormDestSender
 * 5.5.0 - (obs) Wprowadzenie after insert
 * 6.0.0 - (obs) Poprawa zaczytywania skryptów
 * 6.0.1 - (trunk) Wyrzucenie funkcji insert (nieoczyszczony)
 * 6.0.2 - (trunk) Oczyszczenie pliku
 * 6.1.0 - (trunk) Dodanie informacji o queryString i tablicy parametrów
 * 6.1.1 - (p7) Poprawka wyświetlania dwóch elementów w ten sam kubełek
 * 6.1.2 - (web2.4) nowe API xHTML - scriptInsert jako wklejenie tekstu
 * 6.1.3 - (web2.4) Poprawki do nowego API
 */

DestSender.prototype.responseFunction = DestSender_responseFunction;


/* dwie funkcje stanowiące to samo, czyli wysłanie żądania */
DestSender.prototype.send = DestSender_send;
DestSender.prototype.get = DestSender_get;


/*****************************************************
 * Definicje funckji ustawiających wstawianie
 * wymuszają one jednocześnie wstawianie za pomocą XML,
 * a nie responseText i innerHTML
 */

/**
 * Ustawia wstawianie przed wskazanym dzieckie elementu
 * parametrem może być id elementu lub sam element
 */
DestSender.prototype.setInsertBefore = null;

/**
 * Ustawia wstawianie za ostatnim dzieckiem elementu
 * parametrem może być id elementu lub sam element
 */
DestSender.prototype.setAppendChild = null;


/**
 * Ustawia wstawianie przed wskazanym wierszem wskazanej tabeli
 * parametrem może być tabela lub id tabeli oraz numer wiersza
 * 0 - wstawia na początek, brak parametru jako ostatni wiersz
 */
DestSender.prototype.setInsertTableRow = null;

/**
 * Poprawić należy te funkcje aby umożliwiała rzeczywiście
 * zamianę ewentulanych stringów na obiekty html
 */
DestSender.prototype.getElement = null;


/**
 * Funkcja służy do wyłapywania błędów
 * podczas odbioru odpowiedzi
 */
DestSender.prototype.errorHandler = null;

DestSender.prototype.request = null;

/**
 * funckja wywoływna po otrzymaniu odpowiedzi
 * jeśli zwróci nieprawdę nie bedzie wykonywane wstawianie
 */
DestSender.prototype.listener = null;

/**
 * Dodaje funkcję do listy funkcji wywoływanych
 * po odebraniu informacji
 */
DestSender.prototype.onload = null;

/**
 * Dodaje funkcję do listy funkcji wywoływanych
 * po wstawieniu elementów
 */
DestSender.prototype.afterInsert = null;

/**
 * Dodaje funkcję do listy wywoływanych
 * tuż przed wysłaniem zapytania
 */
DestSender.prototype.init = null;



DestSender.prototype.store = DestSender_store;
DestSender.prototype.save = DestSender_store;
DestSender.prototype.restore = DestSender_restore;


/**
 * Dla wartości parametru true, ignorowane sa zawartości
 * podesłane przez serwer
 */
DestSender.prototype.setIgnoreServerDest = null;

/**
 * Ustawienie tego paramtru powoduje wyświetlanie informacji
 * jeśli przesyłka powróci pusta
 */
DestSender.prototype.emptyAlert = null;

/**
 * Zwraca wartość zmiennej Odebranej przez sendera
 * @param name nazwa zmiennej
 * @return wartość zmiennej
 */
DestSender.prototype.getVariable = null;
DestSender.prototype.variables = null;

/**
 * Umożliwia wprowadznie alternatywnej funkcji insertującej
 * pobrane widoki do poszczególnych elementow
 */
//DestSender.prototype.insertFunction = null;

/**
  * Funkcja wyświetlająca alerty przesłane z serwera
  * pobrane widoki do poszczególnych elementow
  */
DestSender.prototype.alertFunction = null;


/**
 * DestSender
 * 
 * Należałoby dorobić jeszcze aby defResponse wywoływane było jeszcze
 * z innej fukcji, która spełni podstawowe założnenia systemu, czyli 
 * obsłuży listenera oraz byc może sprawdzenie poprawności. 
 * Może zrobić wiele listenerów oraz 
 * 
 * Parametry
 * @param destination - id elementu, do którego nalezy wprowadzić odpowiedź
 *        ewentualnie konkretny obiekt HTML do którego należy wsadzić zawartość 
 * @param http_method - metoda przesłania danyc GET lub POST
 * @param enctype
 */
function DestSender(destination, http_method, enctype) {
    

    if (!DestSender.functionCreated) {
        DestSender.functionCreated = true;

        /**
         * Zwraca wartość zmiennej Odebranej przez sendera
         * @param name nazwa zmiennej
         * @return wartość zmiennej
         */
        DestSender.prototype.getVariable = function(name) {

            var xml = this.responseXML;
            if (!xml) return null;

            if (!this.variables) {
                var variables = xml.getElementsByTagName('variable');
                this.variables = new Array();
                var varName, varValue, typ, temp;
                for (var i = 0; i < variables.length; i++) {
                    varName = variables[i].getAttribute('name');
                    varValue = variables[i].firstChild.data;

                    /* sprawdzenie, czy istnieje już taka zmienna */
                    typ = typeof(this.variables[varName]);
                    if (typ == 'undefined' && varName.substr(-2) != '[]')
                        this.variables[varName] = varValue;
                    else {
                        /* jeśli nie jest jeszcze tablicą */
                        if (typ != 'object') {
                            temp = this.variables[varName];
                            this.variables[varName] = new Array();
                            this.variables[varName].push(temp);
                        }

                        this.variables[varName].push(varValue);
                    }
                }
            }

            var value;

            if (this.variables) {
                value = this.variables[name];
                if (typeof(value) == 'undefined')
                value = this.variables[name + '[]'];
            }
            return value ? value : '';
        }


        /**
         * Dodaje funkcję do listy funkcji wywoływanych
         * po odebraniu informacji
         */
        DestSender.prototype.onload = function(funkcja) {
            if (!this.onloadArray) this.onloadArray = new Array();
            this.onloadArray.push(funkcja);
            return this;
        }


        /**
         * Dodaje funkcję do listy funkcji wywoływanych
         * po odebraniu informacji
         */
        DestSender.prototype.afterInsert = function(funkcja) {
            if (!this.afterInsertArray) this.afterInsertArray = new Array();
            this.afterInsertArray.push(funkcja);
            return this;
        }


        /**
         * Dodaje funkcję do listy wywoływanych
         * tuż przed wysłaniem zapytania
         */
        DestSender.prototype.init = function(funkcja) {
            if (!this.initArray) this.initArray = new Array();
            this.initArray.push(funkcja);
            return this;
        }


        /**
         * Domyślna funkcja wyświetlająca alert przesłany w odpowiedzi
         */
        DestSender.prototype.alertFunction = function(komunikat) {
            alert(komunikat);
        }


        /**
         * Poprawić należy te funkcje aby umożliwiała rzeczywiście
         * zamianę ewentulanych stringów na obiekty html
         */
        DestSender.prototype.getElement = function(element) {
            return element;
        }


        /**
         * Funkcja służy do wyłapywania błędów
         * podczas odbioru odpowiedzi
         */
        DestSender.prototype.errorHandler = function(status, statusText) {
            if (status != '200') {
                alert("Rozpacz!!! Błąd serwera: " + statusText);
                return;
            }
        }


        /**
         * Dla wartości parametru true, ignorowane sa zawartości
         * podesłane przez serwer
         */
        DestSender.prototype.setIgnoreServerDest =
        function DestSender_setIgnoreServerDest(ignore) {
            this.ignoreServerDest = ignore;
        }


    } // do if(created)


    if (!http_method) http_method = "GET";
    this.request = new Asynchronous(http_method, null, enctype);

    var instance = this;
    this.request.complete = 
    function(status, statusText, responseText, responseXML, sender){
        DestSender.prototype.responseFunction(
            status, statusText, responseText, responseXML, instance, sender)
    }
    this.destination = destination;
    this.ignoreServerDest = false;

}


/**
 * Meotda zapamiętuje atrybuty o podanym kluczu, które mogą być potem
 * odtworzone p otrzymaniu przesyłki. Można służyć do zapajmiętania
 * przycisku, który wykonał akcję ajax
 */
function DestSender_store(key, value) {
    if (!this.memory) this.memory = new Array();
    this.memory[key] = value;
}

/**
 * Meotda odtwearza warto9ści zapamiętane operacją save
 */
function DestSender_restore(key) {
    if (this.memory) return this.memory[key];
    else return null;
}


/**
* Wysyła zapytanie pod wskazany adres w url
* jako drugi parametr można podać tablicę asocjacyjną
* z parametrami wysyłki
*/
function DestSender_send(url, getParamsArray, content) {

    this.paramsArray = getParamsArray;
    var params = dtUtils.arrayToURLParams(getParamsArray);
    this.queryString = params;

    /* Sprawdzenie, czy url, nie zawiera już separatora parametrów */
    var paramSep = '';
    if (url.indexOf('?') == -1) paramSep = '?';

    /* ładowanie funkcji inicjacyjnych */
    if (this.initArray) {
        var stop = false;
        for (var index in this.initArray) {
            stop |= this.initArray[index](this);
        }
        if (stop) return;
    }

    if (this.response !== null)
        this.request.call(url + paramSep + params, content);
}


/**
* Wysyła zapytanie pod wskazany adres w url
* jako drugi parametr można podać tablicę asocjacyjną
* z parametrami wysyłki
*/
function DestSender_get(url, getParamsArray, callback) {
    if (callback) this.afterInsert(callback);
    this.send(url, getParamsArray);
}


/**
 * Funkcja obsługująca odpowiedź z serwera
 * oraz wstawia do odpowiedniego miejsca
 * wskazanego w konstruktorze lub wskazanego
 * w odpowiedzi. Parametry status i statusText to odpowiedzi Http a nie zmienne
 * odpowiedzi, które potem są ustawiane jako zmienne DestSendera
 */
function DestSender_responseFunction(
    status, statusText, responseText, responseXML, instance, sender) {

    /** zapamiętanie odpowiedzi XML */
    instance.responseXML = responseXML;
    instance.status = instance.getVariable('status');
    if (instance.status == '') instance.status = 1;
    else {
        var status_num = Number(instance.status);
        if (status_num != NaN) instance.status = status_num;
    }
    
    instance.statusText = instance.getVariable('statusText');
    instance.statusTarget = instance.getVariable('statusTarget');

    /* wyprowadzenie statusu we wskazanym miejscu przez statusTarget */
    if (instance.statusTarget) {
        var cel = document.getElementById(instance.statusTarget);
        cel.innerHTML = instance.statusText;
    }

    instance.command = instance.getVariable('command');

    /* sprawdzenie warunków poprawnego odbioru */

    if (instance.errorHandler) instance.errorHandler(status, statusText);

    /* poinformowanie listenera o odczytaniu informacji
     * i ewentualne zatrzymanie aksji
     */

    if (instance.listener) {
        var nobreak = instance.listener(responseText, responseXML, instance);
        if (!nobreak) return;
    }

    if (instance.onloadArray) {
        nobreak = true;
        for (var index in instance.onloadArray) {
            nobreak &= instance.onloadArray[index](responseText, responseXML, instance);
        }
        if (!nobreak) return;
    }

    if (responseXML == null || !responseXML.hasChildNodes()) {
        if (instance.emptyAlert) {
            alert("Rozpacz!!! " + instance.emptyAlert);
        }
        return;
    }

    /* PRZEGLĄDANIE ZAWARTOŚCI PRZESYŁKI */

    var views = responseXML.getElementsByTagName('view');

    if (!views.length) {
//        alert("Rozpacz!!! Nie ma żadnych widoków:\n\r" + responseText);
        return;
    }

    /* przechowuje nazwę elementu do którego trzeba wrzucić wsady */
    var target = null;

    /* przechowuje odnośnik elementu o do którego trzeba wrzucić wsady */
    var targetElement = null;


    /* Pętla po ele,entach view */
    var targetArray = new Array();

    for (var i = 0; i < views.length; i++) {
        var view = views[i];

        /* ustalenie celu */
        var dn = view.getAttribute('target');
        if (dn && dn != '' && !instance.ignoreServerDest) target = dn;
        else target = instance.destination;

        /* wyznaczenie celu. Poniższa komplikacja aby target czyszczony był tylko raz */
        targetElement = targetArray[target];
        if (!targetElement) {
            targetElement = document.getElementById(target);
            if (targetElement) {
                targetArray[target] = targetElement;
                targetElement.innerHTML = '';
            }
        }
        if (targetElement) {

            /* Pobranie wszystkich nodów dla view */
            var tags = view.childNodes;

            for (var tagIndex = 0; tagIndex < tags.length; tagIndex++) {

                var tag = tags[tagIndex];

                switch(tag.nodeName) {

                    case 'alert':
                        instance.alertFunction(innerXML(tag));
                        break;

                    case 'script':

                        /* scrypt jest w zawartości czy linku ? */
                        new ScriptRunner(tag, targetElement, targetElement.lastChild);
                        break;

                    case 'style':
                    case 'link':

                        /* style są w zawartości czy linku ? */

                        /* tyu chyba nie powinno diałać, dlatego to remuję */
//                        var style = tag.cloneNode(false);
//                        var styleScript = innerXML(style);
//                        if (styleScript) style.innerHTML = styleScript;
//                        targetElement.appendChild(styleScript);

                        /* a to podejrzewam, ze działa */
                        var style = tag.cloneNode(true);
                        targetElement.appendChild(style);

                        break;

                    case '#cdata-section':

                        if (!targetElement) {
                            alert('Nie ma kubełka: ' + target);
                        } else {
                            xHTML.insertScript(tag.data, targetElement, targetElement.lastChild);
                        }

                        break;

                    default:

                }

            }
        }
    }

    if (instance.afterInsertArray) {
        for (var afterIndex in instance.afterInsertArray) {
            instance.afterInsertArray[afterIndex](responseText, responseXML, instance);
        }
    }

}


