'use strict';
define(function() {
  var GceSendMailServices = function(
    FeatureTypeFactory,
    QueryFactory,
    GlobalServices,
    $q,
    UsersFactory,
    ngDialog,
    FunctionFactory,
    gaJsUtils
  ) {
    var contexts = [];

    /**
     *    Get the mail description from the database table named "g2cenvoimail".
     *  To get the description of the mail we want to send from this field,
     *  we make a query on its name. The mail name is the second part of this field name.
     *  This field name is like "g2cenvoimail_mailname".
     */
    function getMailDescriptionFromDB(ctx, deferred) {
      //-- Get mail name.
      var mailName = ctx.mailFieldName.substr(13);
      //-- Get the description of the table named "g2cenvoimail"
      //-- which contains the description of the mails.
      FeatureTypeFactory.getFeatureTypeDescAsPromise(
        ctx.datastoreName,
        'g2cenvoimail'
      ).then(function(fti) {
        //-- Filter to obtain only the information of the mail concerned by this field.
        var where = "nom='" + mailName + "'";

        QueryFactory.data(fti.uid, where).then(function(res) {
          if (res.data.features.length != 0) {
            //-- We got the mail description, so load it in the scope.
            ctx.mailDesc = res.data.features[0];
            buildMailRecipientList(ctx);
            buildMailContent(ctx);
            deferred.resolve({ status: 'ok', ctxId: ctx.id });
          } else deferred.resolve({ status: 'cannot get mail', ctxId: ctx.id });
        });
      });
    }

    /**
     *     Html of the send mail confirmation dialog box.
     */
    function getSendConfirmHtml(envoiOuRenvoi, ctxId) {
      var dialogContent;
      if (envoiOuRenvoi == 'envoi')
        dialogContent = "<div>Confirmez vous l'envoi du mail ?</div>";
      else dialogContent = '<div>Confirmez vous le renvoi du mail ?</div>';
      dialogContent += '<div>';
      dialogContent +=
        "  <button ng-click='sendMailOk(" + ctxId + ")'>Oui</button>";
      dialogContent +=
        "  <button ng-click='sendmailAbort(" + ctxId + ")'>Non</button>";
      dialogContent += '</div>';

      return dialogContent;
    }

    /**
     *    Store directly in a scope property the boolean value
     *  indicating if a mail has already been sent for this field.
     */
    function setMailAlreadySent(ctx) {
      ctx.mailAlreadySent =
        ctx.sentMailContent != undefined && ctx.sentMailContent != '';
    }

    /**
     *    Recursive function that look for a field in the widget.
     * The field we are looking for is identified by its name.
     * So this field is a table field that must be present in the widget.
     */
    function getFieldValueFromParent(fieldName, theScope, ctx) {
      //-- If previous scope has no parent, or
      //-  max depth is reached no value found, so return empty string.
      if (theScope == undefined) return '';
      if (ctx.depthForFieldRecursiveSearch++ > 6) return '';

      //-- Look if a child contains the field.
      //-- If so return its value.
      for (var cs = theScope.$$childHead; cs; cs = cs.$$nextSibling) {
        if (cs.theField01 != undefined)
          if (cs.theField01.objectField.name == fieldName)
            return cs.theField01.objectField.value;
      }

      //-- No field found in this scope, so try to find it
      //-- in the parent scope of "theScope".
      return getFieldValueFromParent(fieldName, theScope.$parent, ctx);
    }

    /**
     *
     *     When the calling scope has a property "objectFields", we look for
     *  the property named after the parameter fieldName.
     *     In case there is no "objectFields" in the scope or the field has not been encountered in it,
     *  look for a field in the widget and return its current value when it is found.
     */
    function getFieldValue(fieldName, ctx) {
      //-- This directive is in a formfield or a ffl2 (form field level 2).
      //-- So the parent containing the fields of same levels
      //-- is the scope which is the parent of the parent of this directive's scope.
      //-- But anyway make a recursive search in case this module is used differently.
      //--
      ctx.depthForFieldRecursiveSearch = 0;

      //-- Scope objectFields property contains the field ?
      if (ctx.scope.objectFields != undefined)
        for (var propName in ctx.scope.objectFields)
          if (propName == fieldName) return ctx.scope.objectFields[propName];

      //-- No value found for scope.objectFields.
      return getFieldValueFromParent(fieldName, ctx.scope.$parent, ctx);
    }

    /**
     *    When mail has not been sent at all, the content gotten from
     * the mail description is calculated. The need of calculation is du to
     * the possible presence of expression in the body of the mail.
     * The expressions that can be evaluated are:
     * - !CURRENT_YEAR!:      Année courante / Current year
     * - !CURRENT_YEAR+N!:    Année courante + valeur de l'entier N / Current year plus integer value of N
     * - !FIELD!.!fieldname!  Valeur du champ nommé fieldname pourvu qu'il soit dans le widget /
     *                        Value of the field named "fieldname" provided that it's present in the widget.
     */
    function calculateMailContent(ctx) {
      var ind1,
        ind2,
        keyWord,
        value,
        reg,
        loopCnt = 0;

      //-- Replace all CURRENT_YEAR expression by its value.
      ind1 = ctx.mailContent.indexOf('!CURRENT_YEAR');
      while (ind1 != -1 && ++loopCnt != 100) {
        ind2 = ctx.mailContent.indexOf('!', ind1 + 1);
        keyWord = ctx.mailContent.substr(ind1, ind2 - ind1 + 1);
        reg = keyWord;
        if (keyWord.substr(13, 1) != '!')
          keyWord =
            keyWord.substr(0, 13) +
            '!' +
            keyWord.substr(13, keyWord.length - 14);
        value = GlobalServices.getValueForKeyWord(keyWord);
        ctx.mailContent = ctx.mailContent.replace(reg, '' + value.newValue);

        ind1 = ctx.mailContent.indexOf('!CURRENT_YEAR');
      }

      //-- Replace all FIELD expression by its value.
      loopCnt = 0;
      ind1 = ctx.mailContent.indexOf('!FIELD!');
      while (ind1 != -1 && ++loopCnt != 100) {
        ind2 = ctx.mailContent.indexOf('!', ind1 + 9);
        keyWord = ctx.mailContent.substr(ind1, ind2 - ind1 + 1);
        value = getFieldValue(
          ctx.mailContent.substr(ind1 + 9, ind2 - ind1 - 9),
          ctx
        );
        if (value.getMonth != undefined) value = value.toLocaleDateString();
        else value = '' + value;
        reg = new RegExp(keyWord, 'g');
        ctx.mailContent = ctx.mailContent.replace(reg, value);

        ind1 = ctx.mailContent.indexOf('!FIELD!');
      }

      //-- Replace all remaining !xxx! expression by its value.
      ind1 = ctx.mailContent.indexOf('!');
      while (ind1 != -1 && ++loopCnt != 100) {
        ind2 = ctx.mailContent.indexOf('!', ind1 + 1);
        keyWord = ctx.mailContent.substr(ind1, ind2 - ind1 + 1);
        value = GlobalServices.getValueForKeyWord(keyWord);
        if (value.newValue.toLocaleString != undefined)
          value.newValue = value.newValue.toLocaleString();
        ctx.mailContent = ctx.mailContent.replace(keyWord, '' + value.newValue);

        ind1 = ctx.mailContent.indexOf('!');
      }
    }

    /**
     *     When a mail has already been sent we do not change its content.
     *  When a mail has never been sent, we get the default content from
     *  the mail description and then calculate it in order to evaluate
     *  the contained expressions.
     */
    function buildMailContent(ctx) {
      setMailAlreadySent(ctx);
      if (ctx.mailAlreadySent) ctx.mailContent = ctx.sentMailContent;
      else {
        ctx.mailContent = ctx.mailDesc.properties['contenu'];
        calculateMailContent(ctx);
      }
    }

    /**
     *    Get the mail of each user stored in the recipient list
     * of the mail description.
     */
    function buildMailRecipientList(ctx) {
      var userUids, uid;

      ctx.recipients = [];
      if (ctx.mailDesc.properties['recipients'] != null) {
        //-- Recipient list is stored as an array of user UID
        //-- without string delimiter (example: [a01,b02,f99]).
        //-- From the we build a javascript array.
        userUids = ctx.mailDesc.properties['recipients'];
        userUids = userUids.replace(/\[/g, '');
        userUids = userUids.replace(/\]/g, '');
        userUids = userUids.split(',');

        UsersFactory.get().then(function(res) {
          var ind1, ind2;
          //-- Go through user list and get email of user making part of the recipient list.
          for (ind1 = 0; ind1 < userUids.length; ind1++) {
            uid = userUids[ind1].trim();
            for (ind2 = 0; ind2 < res.data.length; ind2++)
              if (uid == res.data[ind2].uid) {
                ctx.recipients.push(res.data[ind2].email);
                break;
              }
          }
        });
      }
    }

    function getMailRecipients(ctx) {
      return ctx.recipients;
    }

    function getMailSubject(ctx) {
      return ctx.mailDesc.properties['subject'];
    }

    /**
     *     Return mail content which is different depending on if it is a first
     *  mail sending or a new sending of the same mail.
     *
     *  ctx.mailContent contains the full description of the mail
     *                     as it is stored in the database when already sent.
     *                     When already sent the mail content contains
     *                     the number of times it has been sent,
     *                     and the dates of the sendings and the recipients.
     *  getMailContent only returns the message body of the mail.
     */
    function getMailContent(ctx) {
      var ind = ctx.mailContent.indexOf('Corps du message:');
      if (ind == -1) return ctx.mailContent;
      else return ctx.mailContent.substr(ind + 18);
    }

    function sendmailAbort(ctxId) {
      ngDialog.closeAll('');
      contexts[ctxId].deferred.resolve('aborted');
    }

    /**
     *     Once sent the mail is stored so that it become the field value.
     *  At first sending, the value is a text containing the adte and time of the sending
     *  then the mails of the recipients, and finally the message text.
     *  If the mail is sent again, we add the sending count at the begining as well as
     *  the date andtime and the list of mails address of this new sending.
     *  The mail list may change for a new sending because between the two sending
     *  the administrator may have benn changing the recipient list in the mail description.
     */
    function storeMail(ctx) {
      var ind,
        nb,
        mailToStore = '';
      var recipients = getMailRecipients(ctx);
      var today = new Date();

      if (ctx.mailAlreadySent) {
        ind = ctx.mailContent.indexOf("Nombre d'envois:");
        if (ind == -1) nb = 2;
        else nb = parseInt(ctx.mailContent.substr(ind + 16)) + 1;
        mailToStore = "Nombre d'envois:" + nb + '\n\n\n';
        mailToStore += '---------------\n';
        mailToStore +=
          "Date et heure de l'envoi no " +
          nb +
          ':\n' +
          today.getDate() +
          '/' +
          (1 + today.getMonth()) +
          '/' +
          today.getFullYear() +
          ' à ';
        mailToStore += today.getHours() + 'H' + today.getMinutes();
        mailToStore += '\n\nMail envoyé à:\n';
        mailToStore += recipients.join(' , ');
        mailToStore += '\n---------------';
        mailToStore += '\n\n\n' + ctx.mailContent;
      } else {
        mailToStore +=
          "Date et heure d'envoi du mail:\n" +
          today.getDate() +
          '/' +
          today.getMonth() +
          '/' +
          today.getFullYear() +
          ' à ';
        mailToStore += today.getHours() + 'H' + today.getMinutes();
        mailToStore += '\n\nMail envoyé à:\n';
        mailToStore += recipients.join(' , ');
        mailToStore += '\n\nCorps du message:\n';
        mailToStore += ctx.mailContent;
      }

      ctx.mailContent = mailToStore;
    }

    /**
     *    Function called when the user has confirmed the sending of the mail.
     */
    function sendMailOk(ctxId) {
      var ctx = contexts[ctxId];
      var mailDesc = [];

      ctx.sendingMail = true;
      mailDesc.push({
        name: 'mailTo',
        type: 'cst',
        value: getMailRecipients(ctx),
      });
      mailDesc.push({
        name: 'mailSubject',
        type: 'cst',
        value: getMailSubject(ctx),
      });
      mailDesc.push({
        name: 'mailContent',
        type: 'cst',
        value: getMailContent(ctx),
      });
      FunctionFactory.execute({ parameters: mailDesc }, 'sendMail', 'ja').then(
        function(res) {
          //-- If mail correctly sent then store it so that we'll have
          //-- the trace of the sent mail.
          if (res.data === 'true') {
            storeMail(ctx);
            setMailAlreadySent(ctx);
            gaJsUtils.successMessage('Mail envoyé');
            ctx.deferred.resolve({
              status: 'ok',
              mailContent: ctx.mailContent,
            });
          } else {
            gaJsUtils.errorMessage("Echec à l'envoi du mail !", '');
            ctx.deferred.resolve({ status: 'not sent' });
          }
          ctx.sendingMail = false;
        }
      );
      ngDialog.closeAll('');
    }

    /********************************************
     *
     *
     *    Actions triggered on user commands.
     *
     */

    function sendMail(ctxId) {
      contexts[ctxId].deferred = $q.defer();
      contexts[ctxId].scope.sendMailOk = sendMailOk;
      contexts[ctxId].scope.sendmailAbort = sendmailAbort;
      ngDialog.open({
        template: getSendConfirmHtml('envoi', ctxId),
        plain: true,
        scope: contexts[ctxId].scope,
      });
      return contexts[ctxId].deferred.promise;
    }

    function sendMailAgain(ctxId) {
      contexts[ctxId].deferred = $q.defer();
      ngDialog.open({
        template: getSendConfirmHtml('renvoi', ctxId),
        plain: true,
        scope: contexts[ctxId].scope,
      });
      return contexts[ctxId].deferred.promise;
    }

    /**
         *     Open a widget in order to show the mail which is gonna be sent.
         *  Recipient list and subject are also displayed.
         *
        function openMailContent()
        {
            var template;
            var childScope = resources.$new(false,resources);

            if (resources.mailAlreadySent)
                template  = "<textarea ng-model='mailContent' readonly ng-change='valueChanged()' style='width:500px;height:450px;'></textarea>";
            else
               {
                resources.recipientsAsString = resources.recipients.join(" , ");
                template = "<table>";
                template += "  <tr><td>Destinataires</td></tr>";
                template += "  <tr><td>";
                template += "      <textarea readonly ng-model='recipientsAsString' style='width:500px;height:60px;'></textarea>";
                template += "  </td></tr>";
                template += "  <tr><td>";
                template += "  </td></tr>";
                template += "  <tr><td>Sujet</td></tr>";
                template += "  <tr><td>";
                template += "      <input ng-model='mailDesc.properties[\"subject\"]' disabled style='width:500px;'>";
                template += "  </td></tr>";
                template += "  <tr><td>Corps du message</td></tr>";
                template += "  <tr><td>";
                template += "      <textarea ng-model='mailContent' style='width:500px;height:350px;'></textarea>";
                template += "  </td></tr>";
                template += "</table>";
               }
            ngDialog.open({template:template,plain:true, scope:childScope,className: 'ngdialog-theme-plain width800'});
        };
*/

    /*******************************************
     *
     *
     *     Initialization of the scope
     *
     */
    function init(mailFieldName, datastoreName, scope, sentMailContent) {
      var deferred = $q.defer();
      var ctx = {};
      ctx.sendingMail = ctx.mailAlreadySent = false;
      ctx.mailFieldName = mailFieldName;
      ctx.datastoreName = datastoreName;
      ctx.scope = scope;
      ctx.sentMailContent = sentMailContent;
      ctx.id = contexts.length;
      contexts.push(ctx);

      getMailDescriptionFromDB(ctx, deferred);

      return deferred.promise;
    }

    return {
      init: init,
      sendMail: sendMail,
    };
  };

  GceSendMailServices.$inject = [
    'FeatureTypeFactory',
    'QueryFactory',
    'GlobalServices',
    '$q',
    'UsersFactory',
    'ngDialog',
    'FunctionFactory',
    'gaJsUtils',
  ];
  return GceSendMailServices;
});
