/*
 * Diese JavaScript Datei ist für das Bewertungssystem gedacht.
 *
 * Das ganze Script wurde gegen Dojo 1.6 geschrieben, kann allerdiengs
 * mit höheren Dojo 1.X Varianten funktionieren da Dojo verspricht
 * Abwärtskompatibel innerhalb der gleichen Major Version zu bleiben.
 *
 * djConfig muss man so konfigurieren dass "en-us" als locale immer
 * extra geladen wird. Das ganze könnte so aussehen
 *
 * var djConfig = {
 *     parseOnLoad: true,
 *     extraLocale: ['en-us']
 * };
 *
 * Ansonsten muss zur Verwendung dieses Skriptes ebenfalls Dojo in die
 * Seite eingebunden werden und ebenfalls ein Dijit Theme geladen
 * werden. Weitere Dateien die geladen werden müssen:
 *
 * dojox/form/resources/Rating.css
 *
*/

dojo.require("dojo.number");
dojo.require("dijit.Dialog");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.CheckBox");
dojo.require("dijit.form.Form");
dojo.require("dijit.form.MultiSelect");
dojo.require("dijit.form.RadioButton");
dojo.require("dijit.form.Select");
dojo.require("dijit.form.TextBox");
dojo.require("dijit.form.Textarea");
dojo.require("dijit.layout.ContentPane");
dojo.require("dojox.form.Rating");
dojo.require("dojox.layout.TableContainer");

dojo.declare('cms4.rating', null, {
    /* Konstruktor der die anzeige im Frontend aufbaut.
     * Unterteilt in mehrere Methoden die mit "_init" beginnen
     */
    constructor: function(args){
        // Statische Konfiguration
        this.base = '/ajax/rating/form/' + args.data.id + '/';

        // Konfiguraton und anzeige node zuweisen
        this.data = args.data;
        this.view = args.view;

        // Andere Attribute hier nochmal der Übersichtshalber
        // auflisten die eventuell später befüllt werden.
        this.form   = undefined;
        this.dialog = undefined;
        this.stars  = [];

        // Element zum klicken im Frontend generieren
        this._init();
    },
    "_init": function(){
        var self = this;

        // Zuerst einige Argumente überarbeiten
        self._init_data();

        // Extra Dialog soll gezeigt werden, daher Durchschnittswert
        // aller Sternenfelder präsentieren und bei Click auf diesen
        // Dialog präsentieren
        if ( self.data.show_dialog ) {
            dojo.forEach(self.data.fields, function(field){
                if ( field.type == 'stars' ) {
                    // Deaktiviertes Stern Feld erstellen
                    var star = new dojox.form.Rating({
                        'numStars': field.extra.numstars || 5,
                        'value':    dojo.number.round(field.average, 0) || 0,
                        'disabled': 1
                    });

                    // Frontend Sternenfeld abspeichern für späteren
                    // zugriff auf die objekte
                    self.stars.push({
                        'field': field,
                        'star':  star
                    });

                    // Wenn man das deaktivierte Feld anklickt, so soll
                    // man den Dialog angezeigt bekommen
                    dojo.connect(star, 'onStarClick', self, self.show_dialog);

                    // HTML Anzeige bauen
                    var node = self._build_star_view(field, star);
                    dojo.place(node, self.view);
                }
            });
        }
        // Extra Dialog soll nicht gezeigt werden, daher alle
        // Sternfelder direkt anzeigen mit durchschnitsswert und
        // auswählbar
        else {
            dojo.forEach(self.data.fields, function(field){
                if ( field.type == 'stars' ) {
                    // Sternfeld erzeugen
                    var star = new dojox.form.Rating({
                        'name':     field.id,
                        'numStars': field.extra.numstars || 5,
                        'value':    dojo.number.round(field.average, 0) || 0,
                        'disabled': !self.data.can_save
                    });

                    // Sternfelder abspeichern für späteren zugriff
                    self.stars.push({
                        'field': field,
                        'star':  star
                    });

                    // Beim anklicken eines Sternes speichern wenn nötig
                    var handle = dojo.connect(star, 'onStarClick', function(event){
                        self.send_star(star, handle);
                    });

                    // HTML Anzeige bauen
                    var node = self._build_star_view(field, star);
                    dojo.place(node, self.view);
                }
            });
        }
    },
    // Baut die vollständige anzeige des Sternenfeldes zusammen und liefert
    // den HTML Node zurück
    '_build_star_view': function(field, star){
        var self = this;

        var node  = dojo.create('div', {'class': 'star_field'});
        var title = dojo.create('span', {
            'class':   'title',
            innerHTML: field.title
        });
        var description = dojo.create('span', {
            'class':   'description',
            innerHTML: field.description,
        });
        var average = dojo.create('span', {
            'class':   'average',
            innerHTML: dojo.number.round(field.average, 2) || 0
        });
        var count = dojo.create('span', {
            'class':   'count',
            innerHTML: field.count || 0
        });

        dojo.place(title,   node);
        dojo.place(description, node);
        star.placeAt(node);
        dojo.place(average, node);
        dojo.place(count,   node);

        return node;
    },
    // Überarbeitet einige konfigurationswerte. Zum Beispiel String zu
    // Zahlen umwandeln
    "_init_data": function(){
        var self = this;

        // Bestimmte Felder in Zahlen umwandeln
        var data_number_fields = ['can_save', 'id', 'multiple_rating', 'need_login', 'show_dialog'];
        dojo.forEach(data_number_fields, function(field){
            self.data[field] = dojo.number.parse(self.data[field], {
                'locale': 'en_US',
                'strict': true,
                'type':   'decimal'
            });
        });

        // Bestimmte Felder bei den Feldern in zahlen umwandeln
        dojo.forEach(self.data.fields, function(field){
            var numbers = ['is_needed', 'sort'];
            dojo.forEach(numbers, function(number){
                field[number] = dojo.number.parse(field[number], {
                    'locale': 'en_US',
                    'strict': true,
                    'type':   'decimal'
                });
            });
        });
    },
    "_init_dialog": function(){
        var self = this;

        // Formular das alle Eingabefelder umschliesst zum abfragen
        // der eingabedaten
        var form  = new dijit.form.Form({});
        self.form = form;

        // Tabelle das die Eingabefelder enthält für korrekte
        // Formatierung
        var table = new dojox.layout.TableContainer({
            cols:       1,
            showLabels: true
        });
        table.placeAt(form.domNode);

        // Alle Felder bauen und der Tabelle hinzufügen
        dojo.forEach(self.data.fields, function(field){
            var object;
            switch ( field.type ) {
                case 'single_text':
                    object = self._init_type_single_text(field);
                break;
                case 'multi_text':
                    object = self._init_type_multi_text(field);
                break;
                case 'checkbox':
                    object = self._init_type_checkbox(field);
                break;
                case 'radio':
                    object = self._init_type_radio(field);
                break;
                case 'single_select':
                    object = self._init_type_single_select(field);
                break;
                case 'stars':
                    object = self._init_type_stars(field);
                break;
                case 'submit':
                    object = self._init_type_submit(field);
                break;
            }
            if ( object ) {
                object.placeAt(table);
            }
        });

        // Dialog generieren mit dem Content
        var dialog = new dijit.Dialog({
            'closable':  true,
            'slideFrom': 'left',
            'title':     self.data.text_title_dialog
        });
        dialog.set('content', form);
        self.dialog = dialog;

        return;
    },
    "_init_type_single_text": function(field){
        return new dijit.form.TextBox({
            'id':    field.html_id,
            'name':  field.id,
            'label': field.title,
            'title': field.description
        });
    },
    "_init_type_multi_text": function(field){
        return new dijit.form.Textarea({
            'id':    field.html_id,
            'name':  field.id,
            'label': field.title,
            'title': field.description,
            'style': 'margin: 0; padding:0'
        });
    },
    "_init_type_checkbox": function(field){
        return new dijit.form.CheckBox({
            'id':    field.html_id,
            'name':  field.id,
            'label': field.title,
            'title': field.description
        });
    },
    "_init_type_radio": function(field){
        var pane = new dijit.layout.ContentPane({
            'id':    field.html_id,
            'label': field.title,
            'title': field.description
        });
        dojo.forEach(field.extra.options, function(option){
            var radio = new dijit.form.RadioButton({
                'name':  field.id,
                'label': option.text,
                'value': option.value
            });
            var label = dojo.create('label', {'for': radio.id, 'innerHTML': option.text });

            radio.placeAt(pane.domNode);
            dojo.place(label, pane.domNode);
        });
        return pane;
    },
    "_init_type_single_select": function(field){
        var select = new dijit.form.Select({
            'id':    field.html_id,
            'name':  field.id,
            'label': field.title,
            'title': field.description
        });
        dojo.forEach(field.extra.options, function(option){
            select.addOption({
                label: option.text,
                value: option.value
            });
        });
        return select;
    },
    "_init_type_multi_select": function(field){
        // TODO: MultiSelect später noch implementieren
    },
    "_init_type_stars": function(field){
        return new dojox.form.Rating({
            'numStars': field.extra.numstars || 5,
            'id':       field.html_id,
            'name':     field.id,
            'label':    field.title,
            'title':    field.description
        });
    },
    "_init_type_submit": function(field){
        var self   = this;
        var submit = new dijit.form.Button({
            'id':    field.html_id,
            'label': field.title,
            'title': field.description
        });
        dojo.connect(submit, 'onClick', function(){
            self.send_input();
        });
        return submit;
    },

    /* Die normalen Methoden */

    // Zeigt das Dialogfeld
    "show_dialog": function(){
        var self = this;

        // Wenn Benutzer Speichern darf dann Eingabemaske präsentieren
        if ( self.data.can_save ) {
            // Wenn eingabemaske schon generiert wurde dann anzeigen
            if ( self.dialog ) {
                self.dialog.show();
            }
            // ansonsten generieren und anzeigen
            else {
                self._init_dialog();
                self.dialog.show();
            }
        }
        // Benutzer darf nicht Speichern. Warn Dialog anzeigen lassen
        else {
            self.message(self.data.text_already_submit, self.data.text_title_submit);
        }
    },
    // Zeigt einen simplen Warn Dialog an mit einer text Nachricht
    // ähnlich der alert() Funktion, allerdiengs als dijit.Dialog
    "message": function(message, title){
        var self = this;

        if ( !title ) {
            title = 'Achtung'
        }

        if ( message ) {
            // Dialog generieren mit dem Content
            var dialog = new dijit.Dialog({
                'closable':  true,
                'slideFrom': 'left',
                'title':     title
            });

            // Allgemeinen div
            var div = dojo.create('div');
            // Nachricht in div einfügen
            dojo.place(dojo.create('div', {innerHTML: message}), div);
            // OK Button
            var button = new dijit.form.Button({
                label: 'OK',
                style: 'margin: 5px auto',
                onClick: function(){
                    dialog.hide();
                    dialog.destroyRecursive();
                }
            });
            button.placeAt(div);

            // Content setzen
            dialog.set('content', div);
            // Dialog zeigen
            dialog.show();
        }

        return;
    },
    // Eingaben des benutzers werden zum Server gesendet
    "send_input": function(){
        var self = this;

        // Funktion nur relevant wenn man eine Eingabemaske hat
        if ( !self.data.show_dialog ) {
            return;
        }

        // Daten die zum Server gesendet werden sollen zusammenfassen
        var input = self.form.get('value');
        input.pks = self.data.pks;

        // Daten zum Server senden
        var stars = dojo.xhrPost({
            url:      self.base + 'form_input',
            handleAs: 'json',
            content:  {
                input: dojo.toJson(input)
            }
        });

        // Nach dem senden Dialog schließen und sterne updaten
        stars.then(function(data){
            // Neue Information Speichern ob man weiterhin speichern darf
            self.data.can_save = data.can_save;

            self.close_dialog();
            self.update_stars(data);
            self.deactivate_stars(data);
        });

        return;
    },
    // Sendet die Auswahl eines einzelnen Stern feldes direkt zum server
    "send_star": function(star, handle){
        var self = this;

        // Sofort beenden wenn der Stern deaktiviert wurde
        if ( star.get('disabled') == true ) {
            return;
        }

        // Funktion sollte nur dann aufgerufen werden wenn man die
        // Eingabemaske nicht sieht
        if ( self.data.show_dialog ) {
            return;
        }

        // Wert der zum Server gesendet werden soll
        var send = dojo.xhrPost({
            url:      self.base + 'star_input',
            handleAs: 'json',
            content:  {
                pks:   self.data.pks.join(';'),
                star:  star.get('name'),
                input: star.get('value')
            }
        });

        // Wenn senden erfolgreich dann sterne updaten
        send.then(function(data){
            self.update_stars(data);
            self.deactivate_stars(data);
        });

        return;
    },
    // Schliest Dialog und resettet Form
    "close_dialog": function(){
        var self = this;
        if ( self.dialog ) {
            self.dialog.hide();
            self.form.reset();
        }
        return;
    },
    // Updated Sterne auf ihren neuen Wert
    "update_stars": function(data){
        var self = this;

        // Gehe alle Sterne durch die angegeben wurden
        dojo.forEach(data.stars, function(item){
            // Hole star objekt
            var star    = self.get_star(item.id);
            // Runden die Sterne
            var average = dojo.number.round(item.average);
            // Updated objekt
            star.set('value', average);
            star._renderStars(average);
            // Update durchschnittswert
            var view = new dojo.NodeList(self.view);
            dojo.attr(view.query('.average')[0], 'innerHTML', dojo.number.round(item.average, 2));
            dojo.attr(view.query('.count')[0],   'innerHTML', item.count);
        });
        return;
    },
    // Sterne deaktivieren
    "deactivate_stars": function(data){
        var self = this;

        // Gehe alle Sterne durch die angegeben wurden
        dojo.forEach(data.stars, function(item){
            var star = self.get_star(item.id);
            star.set("disabled", true);
        });
        return;
    },
    // Liefert ein Sternfeld anhand seiner field.id zurück
    "get_star": function(index){
        var self = this;
        var items = dojo.filter(self.stars, function(item){
            return item.field.id == index
        });
        return items[0].star;
    }
});

dojo.ready(function(){
    dojo.query('.cms4_rating_system').forEach(function(item){
        var data_node = dojo.query(item).query('.data')[0];
        var view_node = dojo.query(item).query('.view')[0];
        var data      = dojo.fromJson(dojo.attr(data_node, 'innerHTML'));
        var rating    = new cms4.rating({
            "data": data,
            "view": view_node
        });
    });
});

