/* --------------------------------------------------------------
 emails.js 2016-02-22
 Gambio GmbH
 http://www.gambio.de
 Copyright (c) 2016 Gambio GmbH
 Released under the GNU General Public License (Version 2)
 [http://www.gnu.org/licenses/gpl-2.0.html]
 --------------------------------------------------------------
 */

jse.libs.emails = jse.libs.emails || {};

/**
 * ## Emails Library
 *
 * This library contains all the admin/emails page common functionality and is used by the page
 * controllers. You might also use this library in other pages where you need to trigger specific
 * email operations in the server.
 *
 * You will need to provide the full URL in order to load this library as a dependency to a module:
 *
 * ```javascript
 * gx.controller.module(
 *   'my_custom_page',
 *
 *   [
 *      gx.source + '/libs/emails'
 *   ],
 *
 *   function(data) {
 *      // Module code ... 
 *   });
 *```
 *
 * Required Translation Sections: 'admin_labels', 'buttons', 'db_backup', 'emails', 'lightbox_buttons', 'messages'
 *
 * @module Admin/Libs/emails
 * @exports jse.libs.emails
 */
(function (exports) {

    'use strict';

    exports.CONTACT_TYPE_SENDER = 'sender';
    exports.CONTACT_TYPE_RECIPIENT = 'recipient';
    exports.CONTACT_TYPE_REPLY_TO = 'reply_to';
    exports.CONTACT_TYPE_BCC = 'bcc';
    exports.CONTACT_TYPE_CC = 'cc';

    /**
     * Reset Modal (DOM)
     *
     * This method will reset the emails modal back to its initial state. The default
     * modal markup is used in the admin/emails page, but this method can work without
     * all the elements too.
     *
     * @param {object} $modal jQuery selector for the modal.
     */
    exports.resetModal = function ($modal) {
        // Clear basic elements
        $modal.find('input, textarea').val('');
        $modal.find('select option:first').prop('selected', 'selected');

        // Remove validation classes.
        $modal.trigger('validator.reset');

        // Remove all rows from DataTables.
        if ($modal.find('.dataTables_wrapper').length > 0) {
            $modal.find('.dataTables_wrapper table').DataTable().clear().draw();
            $modal.find('.dataTables_wrapper').find('.dataTables_length select option:eq(0)').prop(
                'selected', true);
        }

        // Set all tab widgets to the first tab.
        if ($modal.find('.tab-headline-wrapper').length > 0) {
            $modal.find('.tab-headline').css('color', '').show();
            $modal.find('.tab-headline-wrapper').each(function () {
                $(this).find('a:eq(0)').trigger('click'); // toggle first tab
            });
        }

        // Need to recreate the ckeditor instance every time the modal appears.
        if ($modal.find('#content-html').length > 0) {
            if (CKEDITOR.instances['content-html'] !== undefined) {
                CKEDITOR.instances['content-html'].destroy();
            }
            CKEDITOR.replace('content-html', {
                language: jse.core.config.get('languageCode')
            });
            CKEDITOR.instances['content-html'].setData('');
        }

        // If contact type hidden inputs are present then we have to re-apply their value.
        if ($modal.find('#sender-type').length > 0) {
            $modal.find('#sender-type').val('sender');
        }
        if ($modal.find('#recipient-type').length > 0) {
            $modal.find('#recipient-type').val('recipient');
        }
        if ($modal.find('#reply-to-type').length > 0) {
            $modal.find('#reply-to-type').val('reply_to');
        }

        // Update Tab Counters
        jse.libs.emails.updateTabCounters($modal);
    };

    /**
     * Returns the email information from modal (DOM).
     *
     * The method will grab the values from the modal and bundle them in a single object.
     * The returned object will have the same structure as the valueMapping object. This
     * method is recursive.
     *
     * @param {object} $modal jQuery selector for the modal.
     *
     * @return {object} Returns the email data of the modal.
     */
    exports.getEmailFromModal = function ($modal) {
        var email = {};

        // Required Email Fields
        email.sender = {
            email_address: $modal.find('#sender-email').val(),
            contact_name: $modal.find('#sender-name').val(),
            contact_type: exports.CONTACT_TYPE_SENDER
        };

        email.recipient = {
            email_address: $modal.find('#recipient-email').val(),
            contact_name: $modal.find('#recipient-name').val(),
            contact_type: exports.CONTACT_TYPE_RECIPIENT
        };

        email.subject = $modal.find('#subject').val();
        email.content_html = CKEDITOR.instances['content-html'].getData();

        // Optional Email fields
        email.email_id = ($modal.find('#email-id').val() !== '') ? $modal.find('#email-id').val() :
            null;
        email.is_pending = ($modal.find('#is-pending').val() === 'true');
        email.content_plain = ($modal.find('#content-plain').val() !== '') ? $modal.find(
            '#content-plain').val() : null;

        email.reply_to = ($modal.find('#reply-to-email').val() !== '') ? {} : null;
        if (email.reply_to) {
            email.reply_to.email_address = $modal.find('#reply-to-email').val();
            email.reply_to.contact_name = $modal.find('#reply-to-name').val();
            email.reply_to.contact_type = exports.CONTACT_TYPE_REPLY_TO;
        }

        // BCC & CC Contacts
        email.bcc = null;
        email.cc = null;
        var contacts = $modal.find('#contacts-table').DataTable().rows().data();

        $.each(contacts, function (index, contact) {
            if (email[contact.type] == null) {
                email[contact.type] = [];
            }

            email[contact.type].push({
                email_address: contact.email,
                contact_name: contact.name,
                contact_type: contact.type
            });
        });

        // Attachments
        email.attachments = null;
        var attachments = $modal.find('#attachments-table').DataTable().rows().data();
        $.each(attachments, function (index, attachment) {
            if (email.attachments === null) {
                email.attachments = [];
            }
            email.attachments.push(attachment);
        });

        return email;
    };

    /**
     * Loads email data on modal (DOM).
     *
     * @param {object} email Contains the email data.
     * @param {object} $modal jQuery selector for the modal.
     */
    exports.loadEmailOnModal = function (email, $modal) {
        // Required Email Fields
        $modal.find('#sender-email').val(email.sender.email_address);
        $modal.find('#sender-name').val(email.sender.contact_name);

        $modal.find('#recipient-email').val(email.recipient.email_address);
        $modal.find('#recipient-name').val(email.recipient.contact_name);

        $modal.find('#subject').val(email.subject);
        CKEDITOR.instances['content-html'].setData(email.content_html);

        $modal.find('#is-pending').val((email.is_pending) ? 'true' : 'false');

        // Optional Email Fields

        if (email.email_id !== null) {
            $modal.find('#email-id').val(email.email_id);
        }

        if (email.creation_date !== null) {
            $modal.find('#creation-date').val(email.creation_date);
        }

        if (email.sent_date !== null) {
            $modal.find('#sent-date').val(email.sent_date);
        }

        if (email.reply_to !== null) {
            $modal.find('#reply-to-email').val(email.reply_to.email_address);
            $modal.find('#reply-to-name').val(email.reply_to.contact_name);
        }

        if (email.content_plain !== null) {
            $modal.find('#content-plain').val(email.content_plain);
        }

        if (email.bcc !== null) {
            $.each(email.bcc, function (index, contact) {
                var row = {
                    email: jse.libs.normalize.escapeHtml(contact.email_address),
                    name: jse.libs.normalize.escapeHtml(contact.contact_name),
                    type: jse.libs.normalize.escapeHtml(contact.contact_type)
                };
                $modal.find('#contacts-table').DataTable().row.add(row).draw();
            });
        }

        if (email.cc !== null) {
            $.each(email.cc, function (index, contact) {
                var row = {
                    email: jse.libs.normalize.escapeHtml(contact.email_address),
                    name: jse.libs.normalize.escapeHtml(contact.contact_name),
                    type: jse.libs.normalize.escapeHtml(contact.contact_type)
                };
                $modal.find('#contacts-table').DataTable().row.add(row).draw();
            });
        }

        if (email.attachments !== null) {
            $.each(email.attachments, function (index, attachment) {
                attachment.path = jse.libs.normalize.escapeHtml(attachment.path);
                $modal.find('#attachments-table').DataTable().row.add(attachment).draw();
            });
        }

        // Update Tab Counters
        jse.libs.emails.updateTabCounters($modal);
    };

    /**
     * Sends an email collection
     *
     * Provide an array of email objects and this method will send them to the requested
     * URL through AJAX POST. You can omit the url and the default EmailsController will
     * be used.
     *
     * @param {array} collection Array of email objects.
     * @param {string} ajaxUrl (optional) The AJAX URL for the POST request.
     *
     * @return {object} Returns a promise object that will provide the server's response.
     */
    exports.sendCollection = function (collection, ajaxUrl) {
        ajaxUrl = ajaxUrl || jse.core.config.get('appUrl') + '/admin/admin.php?do=Emails/Send';

        var deferred = $.Deferred(),
            data = {
                pageToken: jse.core.config.get('pageToken'),
                collection: collection
            };

        $.post(ajaxUrl, data, function (response) {
            if (response.exception) {
                deferred.reject(response);
                return;
            }
            deferred.resolve(response);
        }, 'json');

        return deferred.promise();
    };

    /**
     * Queues the email collection
     *
     * Provide an array of email objects and this method will queue them to the requested
     * URL through AJAX POST. You can omit the url and the default EmailsController will
     * be used.
     *
     * @param {array} collection Array of email objects.
     * @param {string} ajaxUrl (optional) The AJAX URL for the POST request.
     *
     * @return {object} Returns a promise object that will provide the server's response.
     */
    exports.queueCollection = function (collection, ajaxUrl) {
        ajaxUrl = ajaxUrl || jse.core.config.get('appUrl') + '/admin/admin.php?do=Emails/Queue';

        var deferred = $.Deferred(),
            data = {
                pageToken: jse.core.config.get('pageToken'),
                collection: collection
            };

        $.post(ajaxUrl, data, function (response) {
            if (response.exception) {
                deferred.reject(response);
                return;
            }
            deferred.resolve(response);
        }, 'json');

        return deferred.promise();
    };

    /**
     * Deletes an email collection
     *
     * Provide an array of email objects and this method will delete them to the requested
     * URL through AJAX POST. You can omit the url and the default EmailsController will
     * be used.
     *
     * @param {array} collection Array of email objects.
     * @param {string} ajaxUrl (optional) The AJAX URL for the POST request.
     *
     * @return {object} Returns a promise object that will provide the server's response.
     */
    exports.deleteCollection = function (collection, ajaxUrl) {
        ajaxUrl = ajaxUrl || jse.core.config.get('appUrl') + '/admin/admin.php?do=Emails/Delete';

        var deferred = $.Deferred(),
            data = {
                pageToken: jse.core.config.get('pageToken'),
                collection: collection
            };

        $.post(ajaxUrl, data, function (response) {
            if (response.exception) {
                deferred.reject(response);
                return;
            }
            deferred.resolve(response);
        }, 'json');

        return deferred.promise();
    };

    /**
     * Returns default modal buttons
     *
     * Used by various sections of the admin/emails page. With the proper use of valueMapping object
     * you can use this method in other pages too.
     *
     * @param {object} $modal jQuery selector for the modal.
     * @param {object} $table jQuery selector for the main table.
     *
     * @return {object} Returns the dialog modal buttons.
     */
    exports.getDefaultModalButtons = function ($modal, $table) {
        var buttons = [
            {
                text: jse.core.lang.translate('close', 'buttons'),
                click: function () {
                    $(this).dialog('close');
                }
            },
            {
                text: jse.core.lang.translate('queue', 'buttons'),
                click: function () {
                    $modal.find('.tab-content.details').trigger('validator.validate');
                    if ($modal.find('.tab-content.details .error').length > 0) {
                        return; // There are fields with errors.
                    }
                    var email = jse.libs.emails.getEmailFromModal($modal);
                    jse.libs.emails.queueCollection([email])
                        .done(function (response) {
                            $table.DataTable().ajax.reload();
                            jse.libs.emails.getAttachmentsSize($('#attachments-size'));
                        })
                        .fail(function (response) {
                            jse.libs.modal.message({
                                title: jse.core.lang.translate('error', 'messages'),
                                content: response.message
                            });
                        });
                    $(this).dialog('close');
                }
            },
            {
                text: jse.core.lang.translate('send', 'buttons'),
                click: function () {
                    $modal.find('.tab-content.details').trigger('validator.validate');
                    if ($modal.find('.tab-content.details .error').length > 0) {
                        return; // There are fields with errors.
                    }
                    var email = jse.libs.emails.getEmailFromModal($modal);
                    jse.libs.emails.sendCollection([email])
                        .done(function (response) {
                            $table.DataTable().ajax.reload();
                            jse.libs.emails.getAttachmentsSize($('#attachments-size'));
                        })
                        .fail(function (response) {
                            jse.libs.modal.message({
                                title: jse.core.lang.translate('error', 'messages'),
                                content: response.message
                            });
                        });
                    $(this).dialog('close');
                }
            }
        ];

        return buttons;
    };

    /**
     * Returns preview modal buttons
     *
     * This method will return the preview modal buttons for the jQuery UI dialog widget. With the proper
     * use of valueMapping object you can use this method in other pages too.
     *
     * @param {object} $modal jQuery selector for the modal.
     * @param {object} $table jQuery selector for the main table.
     *
     * @return {object} Returns the dialog modal buttons.
     */
    exports.getPreviewModalButtons = function ($modal, $table) {
        var buttons = [
            {
                text: jse.core.lang.translate('close', 'buttons'),
                click: function () {
                    $(this).dialog('close');
                }
            },
            {
                text: jse.core.lang.translate('delete', 'buttons'),
                click: function () {
                    var modalOptions = {
                        title: 'Delete Email Record',
                        content: 'Are you sure that you want to delete this email record?',
                        buttons: [
                            {
                                text: jse.core.lang.translate('yes', 'lightbox_buttons'),
                                click: function () {
                                    var email = jse.libs.emails.getEmailFromModal($modal);

                                    jse.libs.emails.deleteCollection([email])
                                        .done(function (response) {
                                            $table.DataTable().ajax.reload();
                                            jse.libs.emails.getAttachmentsSize($('#attachments-size'));
                                        })
                                        .fail(function (response) {
                                            jse.libs.modal.message({
                                                title: jse.core.lang.translate('error',
                                                    'messages'),
                                                content: response.message
                                            });
                                        });
                                    $(this).dialog('close');
                                    $modal.dialog('close');
                                }
                            },
                            {
                                text: jse.core.lang.translate('no', 'lightbox_buttons'),
                                click: function () {
                                    $(this).dialog('close');
                                }
                            }
                        ]
                    };

                    jse.libs.modal.message(modalOptions);
                }
            },
            {
                text: jse.core.lang.translate('queue', 'buttons'),
                click: function () {
                    var email = jse.libs.emails.getEmailFromModal($modal);

                    // Duplicate record only if the original one is already sent.
                    // Otherwise we just need to update the data of the current email record.
                    if (!email.is_pending) {
                        delete email.email_id; // will duplicate the record
                    }

                    jse.libs.emails.queueCollection([email])
                        .done(function (response) {
                            $table.DataTable().ajax.reload();
                            jse.libs.emails.getAttachmentsSize($('#attachments-size'));
                        })
                        .fail(function (response) {
                            jse.libs.modal.message({
                                title: jse.core.lang.translate('error', 'messages'),
                                content: response.message
                            });
                        });
                    $(this).dialog('close');
                }
            },
            {
                text: jse.core.lang.translate('send', 'buttons'),
                click: function () {
                    var email = jse.libs.emails.getEmailFromModal($modal);
                    jse.libs.emails.sendCollection([email])
                        .done(function (response) {
                            $table.DataTable().ajax.reload();
                            jse.libs.emails.getAttachmentsSize($('#attachments-size'));
                        })
                        .fail(function (response) {
                            jse.libs.modal.message({
                                title: jse.core.lang.translate('error', 'messages'),
                                content: response.message
                            });
                        });
                    $(this).dialog('close');
                }
            }
        ];

        return buttons;
    };

    /**
     * Colorizes modal buttons for the edit mode
     *
     * jQuery UI does not support direct addition of classes to the dialog buttons,
     * so we need to apply the classes during the "create" event of the dialog.
     *
     * @param event {event} Event to trigger this function.
     * @param ui {object} Dialog UI.
     */
    exports.colorizeButtonsForEditMode = function (event, ui) {
        $(this).closest('.ui-dialog').find('.ui-button').eq(3).addClass('btn-primary'); // Send Button
    };

    /**
     * Colorizes modal buttons for preview mode
     *
     * jQuery UI does not support direct addition of classes to the dialog buttons,
     * so we need to apply the classes during the "create" event of the dialog.
     *
     * @param event {object} Event to trigger this function.
     * @param ui {object} Dialog UI.
     */
    exports.colorizeButtonsForPreviewMode = function (event, ui) {
        $(this).closest('.ui-dialog').find('.ui-button').eq(4).addClass('btn-primary'); // Send Button
    };

    /**
     * Deletes old attachments from selected removal date and before.
     *
     * @param {date} removalDate The date when the removal should start.
     * @param {object} ajaxUrl (optional) Specific ajaxUrl to be used for the request.
     * @returns {object} Returns a promise object to be used when the requests ends.
     */
    exports.deleteOldAttachments = function (removalDate, ajaxUrl) {
        ajaxUrl = ajaxUrl || jse.core.config.get('appUrl') + '/admin/admin.php?do=Emails/DeleteOldAttachments';

        var deferred = $.Deferred(),
            data = {
                pageToken: jse.core.config.get('pageToken'),
                removalDate: removalDate
            };

        $.post(ajaxUrl, data, function (response) {
            if (response.exception) {
                deferred.reject(response);
                return;
            }
            deferred.resolve(response);
        }, 'json');

        return deferred.promise();
    };

    /**
     * Deletes old emails from selected removal date and before.
     *
     * @param {string} removalDate The date when the removal should start.
     * @param {object} ajaxUrl (optional) Specific ajaxUrl to be used for the request.
     * @returns {object} Returns a promise object to be used when the requests ends.
     */
    exports.deleteOldEmails = function (removalDate, ajaxUrl) {
        ajaxUrl = ajaxUrl || jse.core.config.get('appUrl') + '/admin/admin.php?do=Emails/DeleteOldEmails';

        var deferred = $.Deferred(),
            data = {
                pageToken: jse.core.config.get('pageToken'),
                removalDate: removalDate
            };

        $.post(ajaxUrl, data, function (response) {
            if (response.exception) {
                deferred.reject(response);
                return;
            }
            deferred.resolve(response);
        }, 'json');

        return deferred.promise();
    };

    /**
     * Returns the attachments size in MB and refreshes the UI.
     *
     * This method will make a GET request to the server in order to fetch and display
     * the total attachments size, so that users know when it is time to remove old
     * attachments.
     *
     * @param {object} $target jQuery selector for the element to contain the size info.
     * @param {string} ajaxUrl (optional) Specific ajaxUrl to be used for the request.
     *
     * @return {object} Returns the promise object for chaining callbacks.
     */
    exports.getAttachmentsSize = function ($target, ajaxUrl) {
        ajaxUrl = ajaxUrl || jse.core.config.get('appUrl') + '/admin/admin.php?do=Emails/GetAttachmentsSize';

        var deferred = $.Deferred();

        $.get(ajaxUrl, function (response) {
            if (response.exception) {
                jse.libs.modal.message({
                    title: jse.core.lang.translate('error', 'messages'),
                    content: response.message
                });
                deferred.reject(response);
                return;
            }

            var size = (response.size.megabytes !== 0) ? response.size.megabytes + ' MB' : response.size
                .bytes + ' bytes';

            $target.text('(' + size + ')');
            deferred.resolve(response);
        }, 'json');

        return deferred.promise();
    };

    /**
     * Updates modal tabs counters.
     *
     * Displays item number on tabs so that users know how many items there are
     * included in the contacts and attachments tables.
     *
     * @param {object} $modal The modal selector to be updated.
     * @param {object} $contactsTable (optional) The contacts table selector, default selector: '#contacts-table'.
     * @param {object} $contactsTab (optional) The contacts tab selector, default selector: '.tab-headline.bcc-cc'.
     * @param {object} $attachmentsTable (optional) The attachments table selector, default
     * selector: '#attachments-table'.
     * @param {object} $attachmentsTab (optional) The attachments tab selector, default
     * selector: '.tab-headline.attachments'.
     */
    exports.updateTabCounters = function ($modal, $contactsTable, $contactsTab, $attachmentsTable,
                                          $attachmentsTab) {
        $contactsTable = $contactsTable || $modal.find('#contacts-table');
        $contactsTab = $contactsTab || $modal.find('.tab-headline.bcc-cc');
        $attachmentsTable = $attachmentsTable || $modal.find('#attachments-table');
        $attachmentsTab = $attachmentsTab || $modal.find('.tab-headline.attachments');

        if ($contactsTable.length === 0) {
            return; // There is no such table (emails.js unit testing).
        }

        var contactsCount = $contactsTable.DataTable().rows().data().length,
            newContactsText = $contactsTab.text().replace(/\(.*\)/g, '(' + contactsCount + ')'),
            attachmentsCount = $attachmentsTable.DataTable().rows().data().length,
            newAttachmentsText = $attachmentsTab.text().replace(/\(.*\)/g, '(' + attachmentsCount + ')');

        if (newContactsText.indexOf('(') === -1) {
            newContactsText += ' (' + contactsCount + ')';
        }

        if (newAttachmentsText.indexOf('(') === -1) {
            newAttachmentsText += ' (' + attachmentsCount + ')';
        }

        $contactsTab.text(newContactsText);
        $attachmentsTab.text(newAttachmentsText);
    };

    /**
     * Returns an object array with the selected emails of the main emails table.
     *
     * @param {object} $table (optional) The main table selector, if omitted the "#emails-table" selector
     * will be used.
     *
     * @returns {array} Returns an array with the emails data (collection).
     */
    exports.getSelectedEmails = function ($table) {
        $table = $table || $('#emails-table');

        var collection = [];

        $table
            .find('tr td input:checked')
            .each(function (index, checkbox) {
                collection.push($(checkbox).parents('tr').data());
            });

        return collection;
    };

})(jse.libs.emails);