/*jslint nomen: true, plusplus: true, passfail: true, browser: true, devel: true */
/*global $, jQuery, Pongho */

$.fn.serializeFiles = function () {
    var obj = $(this),
        formData = new FormData();

    /* ADD FILE TO PARAM AJAX */
    $.each(obj.find("input[type='file']"), function (i, tag) {
        $.each($(tag)[0].files, function (i, file) {
            formData.append(tag.name, file);
        });
    });

    $.each(obj.serializeArray(), function (i, val) {
        formData.append(val.name, val.value);
    });

    return formData;
};

$.fn.serializeJSON = function (options) {
    "use strict";

    var opts = $.extend({}, {
        attach: []
    }, options);

    function splitInputNameIntoKeysArray(name) {
        return $.map(name.split('['), function (key) {
            var last = key[key.length - 1];

            return last === ']' ? key.substring(0, key.length - 1) : key;
        });
    }

    function deepSet(o, keys, value) {
        if (typeof o === 'undefined') {
            throw "ArgumentError: param 'o' expected to be an object or array, found undefined";
        }

        if (!keys || keys.length === 0) {
            throw "ArgumentError: param 'keys' expected to be an array with least one element";
        }

        var key = keys[0];

        if (keys.length === 1) {
            if (o instanceof Array && key === '') {
                o.push(value);
            } else {
                o[key] = value;
            }
        } else {
            if (typeof o[key] === 'undefined') {
                o[key] = keys[1] === '' ? [] : {};
            }

            deepSet(o[key], keys.slice(1), value);
        }
    }

    var ary = this.serializeArray(),
        result = {};

    if (opts.attach instanceof Array) {
        $.map(opts.attach, function (element) {
            ary.push(element);
        });
    }

    $.each(ary, function () {
        deepSet(result, splitInputNameIntoKeysArray(this.name), this.value);
    });

    return result;
};

$.fn.ajaxForm = function () {
    "use strict";

    return $(this).each(function () {
        var wrapper = $(this),
            button,
            action = '';

        wrapper.on('click', 'button[type="submit"]', function () {
            button = this;
            action = button.value;
        });

        wrapper.on('change', 'input[type="file"]', function (event) {
            var $el = $(this),
                maxFileSize = $el.data('max-file-size') || Pongho.maxFileSize || 2000000,
                file = this.files[0],
                errorBox = $el.data('error-box');

            if (file.size > maxFileSize) {
                event.preventDefault();

                if (!errorBox) {
                    errorBox = $('<li />').prependTo(
                        $('<ul id="box-error" class="box error"></ul>').insertBefore(
                            $el.closest('.control-group')
                        )
                    );

                    $el.data('error-box', errorBox);
                }

                errorBox.text(Pongho.lang.fileUploadErrors.maxFileSize);

                $el.val('');
            } else if (errorBox) {
                errorBox.closest('ul').remove();
                $el.removeData('error-box');
            }
        });

        wrapper.on('submit', 'form', function (event) {
            event.preventDefault();

            // Rimuovo un eventuale box di informazioni/errori
            wrapper.find('.box').remove();

            wrapper.trigger('before-update');

            var form = $(this),
                formData = {},
                processData = false,
                contentType = false,
                tab = form.find('.tabs li.active');

            function prepareStandardFormData() {
                // IE <= 9
                if (window.FormData === undefined) {
                    formData = form.serializeArray();
                    processData = true;
                    contentType = 'application/x-www-form-urlencoded; charset=UTF-8';

                    if (action !== '') {
                        formData.push({
                            'name': button.name,
                            'value': action
                        });

                        // Se ho delle tab all'interno della form, mi assicuro di ritornare nella stessa tab dalla quale ho salvato
                        if (tab.length > 0) {
                            tab.each(function () {
                                var t = $(this),
                                    ref = t.closest('ul').data('ref') || 'tab';
                                formData.push({
                                    'name' : 'tabs[' + ref + ']',
                                    'value' : t.data('name')
                                });
                            });
                        }
                    }
                } else {
                    formData = form.serializeFiles();

                    if (button) {
                        formData.append(button.name, action);

                        // Se ho delle tab all'interno della form, mi assicuro di ritornare nella stessa tab dalla quale ho salvato
                        if (tab.length > 0) {
                            tab.each(function () {
                                var t = $(this),
                                    ref = t.closest('ul').data('ref') || 'tab';
                                formData.append('tabs[' + ref + ']', t.data('name'));
                            });
                        }
                    }
                }
            }

            function prepareSerializedFormData() {
                var attach = [];

                if (button) {
                    attach = [{
                        name: button.name,
                        value: action
                    }];
                }

                formData = new FormData();

                formData.append('form', JSON.stringify(form.serializeJSON({attach: attach})));

                $.each(form.find('input[type="file"]'), function () {
                    var fieldName = this.name;

                    $.each(this.files, function () {
                        formData.append(fieldName, this);
                    });
                });

                if (tab.length > 0) {
                    tab.each(function () {
                        var t = $(this),
                            ref = t.closest('ul').data('ref') || 'tab';

                        formData.append('tabs[' + ref + ']', t.data('name'));
                    });
                }
            }

            switch (form.data('request-format')) {
                case 'serialized':
                    prepareSerializedFormData();
                    break;

                default:
                    prepareStandardFormData();
                    break;
            }

            $.ajax({
                url: form.attr('action'),
                data: formData,
                type: 'POST',
                processData: processData,
                contentType: contentType,
                success: function (response) {
                    if (typeof response === 'object' && response.redirect) {
                        window.location.replace(response.redirect);
                    }

                    $(window).scrollTop(0);

                    wrapper.html(response);
                    wrapper.trigger('after-update');

                    window.setTimeout(function () {
                        wrapper.find('#box-info').fadeOut(function () {
                            $(this).remove();
                        });
                    }, 10000);
                }
            });
        });
    });
};

$.fn.repeater = function (command, callback) {
    "use strict";

    return $(this).each(function () {

        var repeater = $(this),
            container = repeater.closest('.repeater-container'),
            form = container.closest('form'),
            language = container.data('language'),
            blankItem = repeater.find('> .repeater-blank-row'),
            $maxLevels,
            maxLevels = 1,
            sortableOptions;

        if (!repeater.data('blankItem')) {
            // Correggo un problema con il datepicker
            blankItem.find('.input_date').removeClass('hasDatepicker');
            blankItem.find('.input_datetime').removeClass('hasDatepicker');
            blankItem.find('.input_time').removeClass('hasDatepicker');

            repeater.data('blankItem', blankItem.removeClass('repeater-blank-row').clone());

            blankItem.remove();
        }

        if (!repeater.data('counter')) {
            repeater.data('counter', 1);
        }

        function addRow(callback) {
            var row = repeater.data('blankItem').clone();
            // Gestisco i campi
            row
                .find('input, select, textarea')
                    .each(function () {
                        this.name = this.name.replace('[new]', '[new' + repeater.data('counter') + ']');
                    })
                .end()
                .attr('data-id', 'new' + repeater.data('counter'))
                .attr('id', function (index, attr) {
                    return attr.replace(/\-new/g, '-new' + repeater.data('counter'));
                });

            // Tutti gli altri elementi
            row.find('*').attr('id', function (index, attr) {
                if (attr) {
                    return attr.replace(/\-new\-/g, '-new' + repeater.data('counter') + '-');
                }

                return attr;
            });

            if (callback) {
                callback(row);
            }

            if (repeater.data('new-row-position') === 'first') {
                row.prependTo(repeater).show();
            } else {
                row.appendTo(repeater).show();
            }

            repeater.trigger('row_add', [row]);

            repeater.data('counter', repeater.data('counter') + 1);
        }

        if (command && repeater.data('repeater') === true) {
            switch (command) {
                case 'add':
                    addRow(callback);
                    return;
            }
        }

        repeater.data('repeater', true);

        $maxLevels = $(container.data('maxlevels'));

        if ($maxLevels.val()) {
            maxLevels = $maxLevels.val();
        } else if (Pongho && Pongho.nestedRepeater && Pongho.nestedRepeater.maxLevels) {
            maxLevels = Pongho.nestedRepeater.maxLevels;
        }

        sortableOptions = $.extend({}, {
            delay: 200,
            disableNesting: 'no-nest',
            forcePlaceholderSize: true,
            handle: '.sortable-handle',
            items: 'li',
            maxLevels: maxLevels,
            opacity: .6,
            placeholder: 'sortable-placeholder repeater-row',
            revert: 250,
            tabSize: 30,
            tolerance: 'pointer',
            toleranceElement: '> div'

        }, container.data('options') || {});

        // sortable
        if (repeater.hasClass('repeater-sortable')) {
            repeater.sortable(sortableOptions);

            form.submit(function () {
                var position = 1;

                $.map(repeater.sortable('toArray'), function (id) {
                    $('#' + id).find('.sortable-position').val(position);

                    position++;
                });
            });
        }

        // nestedSortable
        if (repeater.hasClass('repeater-nested-sortable')) {
            repeater.nestedSortable(sortableOptions);

            // gestisco i campi per la gerarchia
            form.submit(function () {
                $.each(repeater.nestedSortable('toArray'), function (index, data) {
                    if (data.item_id === 'root' || data.item_id === 'item') {
                        return;
                    }

                    if (data.parent_id === 'root') {
                        data.parent_id = '';
                    }

                    var row = $('[data-id="' + data.item_id + '"]', repeater);

                    $('.nested-parent_id', row).val(data.parent_id);
                    $('.nested-left', row).val(data.left);
                    $('.nested-right', row).val(data.right);
                });
            });
        }

        // correggo un problema con il focus dei campi
        repeater.on('mousedown', '.sortable-handle', function () {
            $(this).closest('.repeater-row').find('input, select, textarea').blur();
        });

        // se modifico il numero dei livelli massimi aggiorno il nestedSortable
        $maxLevels.keyup(function () {
            repeater.nestedSortable('option', 'maxLevels', parseInt($maxLevels.val(), 10));
        });

        // comandi avanzati
        repeater.on('click', '.repeater-actions-open', function (event) {
            event.preventDefault();
            $(this).closest('.repeater-row').addClass('active');
        });
        repeater.on('click', '.repeater-actions-close', function (event) {
            event.preventDefault();
            $(this).closest('.repeater-row').removeClass('active');
        });

        repeater.on('click', '.repeater-delete-row', function (event) {
            var delBtn = $(this),
                li = $(this).closest('.repeater-row'),
                ol = li.closest('repeater');

            // Se aggiungo il data-confirm, controllo la conferma dell'utente prima di procedere
            if (delBtn.data('confirm') && !confirm(delBtn.data('confirm'))) {
                return;
            }

            repeater.trigger('row_delete', [li]);

            li.fadeOut(function () {
                li.remove();

                if (ol.find('li').length == 0 && !ol.is(repeater)) {
                    ol.remove();
                }

                repeater.trigger('row_deleted', [li]);
            });

            event.preventDefault();
        });

        // pulsante per aggiungere le nuove righe

        container.on('click', '> .actions .repeater-add-row', function (event) {
            event.preventDefault();
            addRow();
        });

        // Condizione di aggiunta automatica di una nuova riga
        var addNewRow = repeater.data('add-new-row');
        if (addNewRow === 'always') {
            addRow();
        } else if (addNewRow === 'empty') {
            if (repeater.find('.repeater-row').length === 0) {
                addRow();
            }
        }
    });
};

$.fn.panelAccordion = function () {
    "use strict";

    return $(this).each(function () {

        var title = $(this).find('h3');

        title.css("cursor", "pointer").prepend("<span>▸</span> ").data("open", false).next().hide();

        title.click(function() {
            var t = $(this);

            if (t.data("open")) {
                t.find("span", t).text("▸");
                t.data("open", false).next().slideUp();
            } else {
                t.find("span", t).text("▾");
                t.data("open", true).next().slideDown();
            }
        });
    });
};

$.fn.linkType = function () {
    "use strict";

    function onLinkTypeSelectChange() {
        var sel = $(this),
            types = sel.closest('.link-type-wrapper').find('div.link-type'),
            curKey = sel.find('option:selected').data('value'),
            curType = types.filter('div.link-type-' + curKey),
            span = curType.find('span'),
            row = sel.closest('li');

        types.removeClass('visible').find('span').html('');

        if (span.length) {
            var name = span.data("name");
            // Potrei essere all'interno di un repeater
            if (row.length) {
                name = name.replace('[new]', '[' + row.data('id') + ']');
            }

            span.html(function () {
                return '<select name="' + name + '">' + Pongho.linkField[span.data('language')][curKey] + '</select>';
            });

            span.find('select').val(span.data('value'));
        }

        curType.addClass('visible');
    }

    return $(this).each(onLinkTypeSelectChange).on('change', onLinkTypeSelectChange);
};

$.fn.newLinkType = function () {
    "use strict";

    var Pongho = window.Pongho || {},
        linkTypes = Pongho.linkType || {};

    function onChange(wrapper, select, handlers) {
        var selector = '.link-type-' + select.val(),
            handler = handlers.filter(selector),
            content = (
                    wrapper.data('language')
                        ? linkTypes[wrapper.data('collection')][wrapper.data('language')][select.val()]
                        : linkTypes[wrapper.data('collection')]['null'][select.val()]
                ) || "",
            row = wrapper.closest('.repeater-row');

        if (content) {
            content = $(content);
            content.val(handler.data('value'));
        }

        handlers.removeClass('visible');
        var field = $(content),
            name = handler.data('name');

        if (row.length) {
            name = name.replace('[new]', '[' + row.data('id') + ']');
        }

        field.attr('name', name);
        handler.html(field).addClass('visible');
    }

    return $(this).each(function () {
        var wrapper = $(this),
            select = wrapper.find('.link-type-select'),
            handlers = wrapper.find('.link-type');

        select.on('change', function () {
            onChange(wrapper, select, handlers);
        });

        onChange(wrapper, select, handlers);
    });
};

//todo: aggiungere supporto a link esterni e tab caricate in ajax
$.fn.newTabs = function () {
    "use strict";

    function activateTab(tab, ref, panels) {
        tab.siblings().removeClass('active');
        tab.addClass('active');

        var panel = panels.parent().find('#' + ref + '_' + tab.data('name'));

        panels.hide();
        panel.show().trigger('activate', panel);

//        if (Pongho.wysiwyg !== undefined) {
//            console.log(window.tinymce, tinymce);
//            window.tinymce.hide();
////            tinymce.show();
//        }
    }

    return $(this).each(function () {
        var tabs = $(this),
            ref = tabs.data('ref') ? tabs.data('ref') : 'tab',
            tab = tabs.find('li.active'),
            panels = tabs.parent().find('> .tabsPanel');

        tabs.on('click', 'a', function (event) {
            event.preventDefault();
            activateTab($(this).parent(), ref, panels);
        });

        activateTab(tab.length ? tab : tabs.find('li:first-child'), ref, panels);
    });
};

/**
 * ColorPicker Spectrum
 */
$.fn.attachColorpicker = function () {
    "use strict";

    return $(this).each(function () {
        var el = $(this),
            opts = $.extend({
                preferredFormat: "hex6",
                showInitial: true,
                showInput: true,
                chooseText: "Scegli",
                cancelText: "Annulla"
            }, el.data());

        el.spectrum(opts);
    });
};

$.fn.autosuggest = function () {
    "use strict";

    return $(this).each(function () {
        var el = $(this);

        el.autocomplete({
            source: el.data('url'),
            select: function (event, ui) {
                $(el.data('master')).val(ui.item.id);
                $(el.data('label')).text(ui.item.label);
            },
            close: function () {
                el.val('');
            }
        });
    });
};
