/*
 * Umożliwia wysłanie zapytania i wprowadza
 * odpowiednią do wskazanego elementu ID
 * lub uzyskanego w odpowiedzi jako nazwą taga korzennego
 */

DestSender.prototype.responseFunction = DestSender_responseFunction;

/* dwie funkcje stanowiące to samo, czyli wysłanie żądania */
DestSender.prototype.send = DestSender_send;
DestSender.prototype.get = DestSender_send;


/*****************************************************
 * 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 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;

/**
 * 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
 * @version 5.04
 */
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)
                this.variables = xml.getElementsByTagName('variables')[0];

            var value = this.variables ? this.variables.getAttribute(name) : ""
            return 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 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 ładująca przesłaną zawartość (content)
         * do miejsca docelowego wskazanego przez cel (target)
         */
        DestSender.prototype.insertFunction = function(targets, funkcja) {
//                alert('destSender: '+ target);
            var ok = true;
            for(var target in targets) {
                var desthtml = $el(target);
                if (desthtml) {
                    /* nie powinna usuwać wcześniej załadowanych stylów */
//                    alert('Wdupczam do ' + target + ': ' + targets[target] );
                    desthtml.innerHTML += targets[target];
                } else {
                    ok = false;
                    alert(
                        "Rozpacz!!! Problem z umieszczeniem w elemencie:\n\r" +
                            target);
                }
            }
            if (funkcja) funkcja();
            return ok;
        }


        /**
         * Domyślna funkcja wyświetlająca alert przesłany w odpowiedzi
         */
        DestSender.prototype.alertFunction = function(komunikat) {
            alert(komunikat);
        }


        /**
         * Ustawia wstawianie przed wskazanym dzieckie elementu
         * parametrem może być id elementu lub sam element
         */
        DestSender.prototype.setInsertBefore = function(parentNode, childNode) {
            this.insertMethod = "insertBefore";
            this.insertParams = new Array(parentNode, childNode);
        }


        /**
         * Ustawia wstawianie za ostatnim dzieckiem elementu
         * parametrem może być id elementu lub sam element
         */
        DestSender.prototype.setAppendChild = function(parentNode) {
            this.insertMethod = "appendChild";
            this.insertParams = new Array(parentNode);
        }



        /**
         * 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 = function(table, rowNumber) {
            this.insertMethod = "tableRow";
            this.insertParams = new Array(table, rowNumber);
        }

        /**
         * 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.destID = destination;
    if (destination) this.ignoreServerDest = true;
    else this.ignoreServerDest = false;
    this.insertMethod = null;

}


/**
 * 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;
}


/* Domyślna funkcja listenera nicnierobiąca i pozwalająca na dalszy 
 * bieg domyślej funkcji response
 */
function DestSender_listener(responseText, responseXML, instance) {
    return true;
}

/**
 * Funkcja obsługująca odpowiedź z serwera
 * bez interpretacji. Wstawia odczytaną zawartość
 * w miejsce wskazane w konstruktorze lub bezpośrednio
 * w metodzie load (byc może get)
 */
function DestSender_loadFunction(
    status, statusText, responseText, responseXML, instance, sender) {

}



/**
* Wysyła zapytanie pod wskazany adres w url
* jako drugi parametr można podać tablicę asocjacyjną
* z parametrami wysyłki
*/
function DestSender_send(url, paramsArray, content) {

    var params = dtUtils.arrayToURLParams(paramsArray);

    /* 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);
}


/**
 * Funkcja obsługująca odpowiedź z serwera
 * oraz wstawia do odpowiedniego miejsca
 * wskazanego w konstruktorze lub wskazanego
 * w odpowiedzi. W przypadku różnych mniejdc
 * priorytetowym jest...
 */
function DestSender_responseFunction(
    status, statusText, responseText, responseXML, instance, sender) {

//            alert("Odczytane: " + responseText);
//            alert("Odczytane: " + responseXML.firstChild.firstChild.firstChild.data);

    /** 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.command = instance.getVariable('command');

    /* komunikaty przesyłki */
//    var alerts = responseXML.getElementsByTagName('alert');
//    var globalAlert = instance.getVariable('alert');
//    if (globalAlert) alert(globalAlert);



    /* 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;
    }
//    alert('Jade dalej');

    if (responseXML == null || !responseXML.hasChildNodes()) {
        if (instance.emptyAlert) {
            alert("Rozpacz!!! " + instance.emptyAlert);
        }
        return;
    }


    /* PRZEGLĄDANIE ZAWARTOŚCI PRZESYŁKI */

    /* przeszukiwanie polega na przeglądzie po wszystkich
     * elekentach view oraz wybraniu z nich atrybutów:
     * - dest - cel przesyłki
     * - method - metoda wrzucania
     */

    var views = responseXML.getElementsByTagName('view');

    if (!views.length) {
        alert("Rozpacz!!! Nie ma żadnych widoków:\n\r" + responseText);
        return;
    }

    var destName = null;
    var method = null;

    /* tablica będzie przechowywać zawartość do wstawienia
     * dla poszczególnych celów wskazywanych przez klucz tablicy */
    var targets = new Array();

    /* sprawdzenie, czy predefiniowano */

    if (instance.destID) {
        if (!instance.destID.nodeName) destName = instance.destID;
    }

    if (instance.insertMethod) {
        method = instance.insertMethod;
    }


    var scriptRunner = loaderFactory.createJScriptRunner();
//    var styleLoader = loaderFactory.createStyleLoader();

    /* Pętla po ele,entach view */

    for (var i = 0; i < views.length; i++) {
        var view = views[i];

        var dn = view.getAttribute('target');
        if (dn && dn != '' && !instance.ignoreServerDest) destName = dn;

        if (!instance.insertMethod) {
            method = view.getAttribute("method");
        }

        var styleLoader;
        if (destName) styleLoader = loaderFactory.createStyleLoader(destName);

        /* Pobranie wszystkich nodów dla view
         * i odpowiednia obsługa zawartości
         * alert('Nazwa nody to: ' + tags[tagIndex].nodeName + ' => ' + tags[tagIndex].nodeType );
         */
        var tags = view.childNodes;

        var wsad = "";

        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 ? */
                    scriptRunner.loadJScript(tag);
                    break;

                case 'style':
                case 'link':

                    /* style są w zawartości czy linku ? */
                    styleLoader.loadStyle(tag);
                    break;

                case '#cdata-section':
//                        alert('Zawartość HTML: ' + tag.data);
                    wsad = tag.data;
                    break;

                default:
//                        alert('Nic tu nie ma: ' + tag.nodeValue);

            }

        }

        /* wybór metody do wstawienia elementu */
        switch (method) {

            case 'tableRow':
                alert('Wstawianie tableRow - niezimplementowane');
                break;

            case 'appendChild':
                alert('Wstawianie appendChild - niezimplementowane');
                break;

            case 'insertBefore':
                alert('Wstawianie insertBefore - niezimplementowane');
                break;

            default:
                if (destName && wsad) {
                    if (!targets[destName]) targets[destName] = "";
                    targets[destName] += wsad;
//                        else alert("Rozpacz!!! Nie ma celu dla:\n\r" + wsad);
                }
        }

        var target = null;
        if (destName) {
            target = $el(destName);
            if (target) target.innerHTML = "";
        }

        /* wszystko jest już wpisane, można zgłosić runnerowi, że OK */
        if (styleLoader) styleLoader.itsAll();
    }

    /* wstawienie do właściwego elementu */
//    instance.insertFunction(targets);


    instance.insertFunction(targets, function(){
            scriptRunner.itsAll();
    });
//    alert('Niby wstawiłem tresc jebaną: ' + instance.insertFunction);
//    scriptRunner.itsAll();

}

