<script>
// 共用函式
var fn = {
  config: {
    debug: <%= ConfigHelper.isDevelopment() %>,
    logger: console,
    confirmLeave: false,
  },
  key: KEY,
  log: function (...msg) {
    if (this.config.debug) this.config.logger.log(...msg);
  },
  group: function (group, cb) {
    if (this.config.debug) {
      this.config.logger.group(group);
      cb(this.config.logger.log);
      this.config.logger.groupEnd(group);
    }
  },
  uniq: function (array) {
    return array.filter(function(item, pos) {
        return a.indexOf(item) == pos;
    });
  },
  navScrollTo: function (hash) {
    if ($(hash).length > 0) {
      $('html, body').animate({
        scrollTop: $(hash).offset().top - 75,
      }, 600);
    }
  },
  getDate: function (date) {
    moment.locale(window.navigator.language);
    return moment(date.toString(), 'YYYY/MM/DD').format('YYYY/MM/DD');
  },
  unescape: function (string) {
    return string
      .replace(/&quot;/g, '"')
      .replace(/&amp;/g, '&')
      .replace(/&lt;;/g, '<')
      .replace(/&gt;/g, '>');
  },
  hasIn: function (obj, prop) {
    return _.hasIn(obj, prop);
  },
  htmlDecode: function (value){ 
    return $('<div/>').html(value).text(); 
  },
  transNewLineToBr: function (value) {
    return value.replace(/(?:\r\n|\r|\n)/g, '<br />');
  },
};

// 資料驗證器
fn.validator = function(data, rule) {
  var result = {
    isValid: true,
    errorFields: [],
  };
  for (var key in rule) {
    // this.log('key=>', key);
    var item = _.has(data, key) ? _.get(data, key) : null;
    var keyArray = MESSAGE.split('.');
    var length = keyArray.length;
    if (rule[key]) {
      rule[key].forEach(function(checkFunName) {
        fn.log('checkFunName=>', checkFunName)
        if (!fn.checkFuns[checkFunName](item)) {
          result.isValid = false;
          result.errorFields.push({
            key: key,
            error: checkFunName,
          });
          if (!result[key]) {
            result[key] = [];
            result[key].push(checkFunName);
          } else {
            result[key].push(checkFunName);
          }
        }
      });
    }
  }
  return result;
};

// 表單驗證器
fn.checkFuns = {
  'multi-chosen': function (e) {
    return true;
  },
  chosen: function (e) {
    return true;
  },
  json: function (e) {
    return true;
  },
  geometry: function (e) {
    return true;
  },
  rq: function (e) {
    var basicCheck = (is.existy(e) && e !== '');
    if (is.array(e)) {
      return basicCheck && e.length > 0;
    } else {
      return basicCheck;
    }
  },
  number: function (e) {
    return e ? is.number(parseFloat(e)) : true;
  },
  boolean: function (e) {
    return e ? is.boolean(e) : true;
  },
  string: function (e) {
    return e ? is.string(e) : true;
  },
  text: function (e) {
    return e ? is.string(e) : true;
  },
  length: function (e) {
    return e ? e.toString().length >= 8 : true;
  },
  email: function (e) {
    return e ? is.email(e) : true;
  },
  url: function (e) {
    return is.url(e);
  },
  date: function (e) {
    return moment(e)._isValid;
  },
  phone: function (e) {
    return /^[0-9\-]+$/.test(e);
  },
  notZero: function (e) {
    return e && (e.toString() !== (0).toString());
  },
};

// page handler
fn.page = {
  open: function (value) {
    window.location.hash = "#/" + value;
  },
  redirect: function (url) {
    return window.location.assign(url);
  },
  new: function (value) {
    var host = window.location.origin + '/#/';
    return window.open(host + value);
  },
  setTitle: function (value) {
    document.title = value;
  },
};

// get RanDom ID
fn.makeid = function() {
  var text = "";
  var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

  for (var i = 0; i < 10; i++)
      text += possible.charAt(Math.floor(Math.random() * possible.length));
  return text;
}

// query wapper
fn.api = {
  lastfilter: {},
  paramWrapper: function (value) {
    fn.log('paramWrapper value=>', value);
    return value.toString().replace(/,/g, '+');
  },
  queryWrapper: function (value, addQuery) {
    if (value.endsWith('?')) {
      return (value + '' + addQuery);
    } else if (value.length === 0) {
      return ('?' + addQuery);
    } else {
      return (value + '&' + addQuery);
    }
  },
  getQueryUrl: function ({
    tableName,
    apiPath,
    source,
  }) {
    var query = '';
    var t = tableName || '';
    var o = source.filter || {};
    var p = source.paging;
    fn.log('getQueryUrl source.filter=>', o);
    fn.log('getQueryUrl source.paging=>', p);
    // fn.log('getQueryUrl tableName=>', t)
    // fn.log('getQueryUrl filter=>', filter)

    // status 參數要在最前且重設頁數
    if (o.status) {
      var newQuery = 'status=' + fn.api.paramWrapper(o.status);
      query = fn.api.queryWrapper(query, newQuery);
    } 
    if (o.lang) {
      var newQuery = 'lang=' + fn.api.paramWrapper(o.langCode);
      query = this.queryWrapper(query, lang);
    }
    if (o.searchText) {
      var newQuery = 'search=' + fn.api.paramWrapper(o.searchText);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (p.perPage && p.perPage !== 10) {
      var newQuery = 'perPage' + t + '=' + fn.api.paramWrapper(p.perPage);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (p.curPage && p.curPage !== 1) {
      var newQuery = 'curPage' + t + '=' + fn.api.paramWrapper(p.curPage);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.type) {
      var newQuery = 'type=' + fn.api.paramWrapper(o.type);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.whom) {
      var newQuery = 'whom=' + fn.api.paramWrapper(o.whom);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.active) {
      var newQuery = 'active=' + fn.api.paramWrapper(o.active);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.category) {
      var newQuery = 'category=' + fn.api.paramWrapper(o.category);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.fields && o.fields.length > 0) {
      var newQuery = 'fields=' + fn.api.paramWrapper(
        encodeURIComponent(JSON.stringify(o.fields))
      );
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.sort) {
      var newQuery = 'sort=' + fn.api.paramWrapper(o.sort);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.sortBy) {
      var newQuery = 'sort=' + fn.api.paramWrapper(o.sortBy.sort);
      newQuery += '&by=' + fn.api.paramWrapper(o.sortBy.by);
      query = fn.api.queryWrapper(query, newQuery);
    }
    if (o.search) {
      if (o.search.keyword) {
        var newQuery = 'search=' + fn.api.paramWrapper(o.search.keyword);
        query = fn.api.queryWrapper(query, newQuery);
      }
    }
    var apiUrl = apiPath + query;
    // fn.log('apiPath=>', apiPath);
    // fn.log('query=>', query);

    // add api request to history
    var queryUrl = window.location.href.split('?')[0] + query;
    window.history.pushState(null, null, queryUrl);
    return apiUrl;
  },
  fetch: function (method, apiUrl, success, error, body) {
    var config = {
      type: method,
      url: apiUrl,
      success: success,
      error: error,
    };
    if (body) {
      config.dataType = 'json';
      config.data = body ? { data: body } : null;
      delete body._fields;
    }
    return $.ajax(config);
  },
  uploadFile: function (file, objectKey, public, success, error) {
    $.ajax({
      type: 'get',
      url: '/api/admin/s3/put?objectKey=' + objectKey + (public ? '&alc=public-read' : ''),
      success: function(callback) {
        fn.log(callback);
        $.ajax({
          type: 'PUT',
          url: callback.data.url,
          contentType: 'binary/octet-stream',
          processData: false,
          data: file,
          success: success,
          error: error
        });
      },
      error: error
    });
  }
}

fn.toast = {
  vue: typeof app !== 'undefined' ? app : new Vue(),
  duration : 3000,
  theme: 'primary',
  position: 'bottom-right',
  className: '',
  containerClass: '',
  show: function (text) {
    var msg = text || MESSAGE.msg_wrong_format; 
    return this.vue.$toasted.show(msg, { 
      theme: this.theme, 
      position: this.position,
      duration : this.duration,
    });
  },
  info: function (text) {
    var msg = text || MESSAGE.msg_wrong_format; 
    return this.vue.$toasted.info(msg, { 
      theme: this.theme, 
      position: this.position,
      duration : this.duration,
    });
  },
  success: function (text) {
    var msg = text || MESSAGE.msg_wrong_format; 
    return this.vue.$toasted.success(msg, { 
      theme: this.theme, 
      position: this.position,
      duration : this.duration,
    });
  },
  error: function (text) {
    var msg = text || MESSAGE.msg_wrong_format; 
    return this.vue.$toasted.error(msg, { 
      theme: this.theme, 
      position: this.position,
      duration : this.duration,
    });
  },
};

// 自訂快捷 sweet alert 樣式
fn.swal = {
  close: function () {
    if (swal) return swal.close();
    console.info('SweetAlert not exists.');
  },
  loading: function () {
    if (swal.isVisible()) { swal.close(); }
    return swal({
      title: 'Loading...',
      allowOutsideClick: false,
      showConfirmButton: false,
      // animation: false,
      // customClass: 'animated tada',
      onOpen: function () {
        swal.showLoading();
        // force custom style
        $('.swal2-container .swal2-shown').css('z-index', 9005);
        $('.swal2-actions.swal2-loading').css('margin-top', '0px');
      },
    });
  },
  error: function ({ text, html, title, type, color, mode, cb }) {
    if (swal.isVisible()) { swal.close(); }
    var c = {
      type: 'error',
      title: MESSAGE.msg_notice,
      // confirmButtonColor: config.loadSpinner.company.color,
      confirmButtonText: MESSAGE.msg_yes,
      confirmButtonClass: 'btn btn-danger',
      buttonsStyling: true,
      showCancelButton: false,
      allowOutsideClick: false,
    };
    if (mode && mode === 'user') {
      // c.confirmButtonColor = config.loadSpinner.user.color;
    }
    if (type) c.type = type;
    if (text) c.text = text;
    if (html) c.html = html;
    if (title) c.title = title;
    // if (color) c.confirmButtonColor = color;
    if (cb) {
      return swal(c).then(function () { cb ? cb() : null }.bind(this));
    }
    return swal(c);
  },
  ok: function ({ text, html, title, type, color, mode }) {
    if (swal.isVisible()) { swal.close(); }
    var c = {
      type: 'info',
      title: MESSAGE.msg_notice,
      // confirmButtonColor: config.loadSpinner.company.color,
      confirmButtonText: MESSAGE.msg_yes,
      confirmButtonClass: 'btn btn-success',
      buttonsStyling: true,
      showCancelButton: false,
      allowOutsideClick: false,
    };
    if (mode && mode === 'user') {
      // c.confirmButtonColor = config.loadSpinner.user.color;
    }
    if (type) c.type = type;
    if (text) c.text = text;
    if (html) c.html = html;
    if (title) c.title = title;
    // if (color) c.confirmButtonColor = color;
    return swal(c);
  },
  confirm: function ({ text, html, title, type, cbYes, cbNo, mode, textYes, textNo }) {
    if (swal.isVisible()) { swal.close(); }
    var c = {
      type: 'info',
      title: MESSAGE.msg_notice,
      confirmButtonText: MESSAGE.msg_yes,
      cancelButtonText: MESSAGE.msg_cancel,
      // confirmButtonColor: config.loadSpinner.company.color,
      // cancelButtonColor: config.loadSpinner.user.color,
      confirmButtonClass: 'btn btn-success',
      cancelButtonClass: 'btn btn-danger',
      buttonsStyling: true,
      showCancelButton: true,
      allowOutsideClick: false,
    };
    if (text) c.text = text;
    if (type) c.type = type;
    if (html) c.html = html;
    if (title) c.title = title;
    if (textYes) c.confirmButtonText = textYes;
    if (textNo) c.cancelButtonText = textNo;
    return swal(c).then(
      function (d) {
        if (d.dismiss === 'cancel') {
          cbNo ? cbNo() : null;
        } else {
          cbYes ? cbYes() : null;
        }
      }.bind(this),
      function (d) { if (d === 'cancel') {
        cbNo ? cbNo() : null;
      }}
    );
  },
  then: function ({ html, text, title, type, cb, mode, force }) {
    if (swal.isVisible()) { swal.close(); }
    var c = {
      type: 'warning',
      title: MESSAGE.msg_notice,
      confirmButtonText: MESSAGE.msg_yes,
      // confirmButtonColor: config.loadSpinner.company.color,
      confirmButtonClass: 'btn btn-success',
      buttonsStyling: true,
      showCancelButton: false,
      allowOutsideClick: false,
    };
    if (type) c.type = type;
    if (html) c.html = html;
    if (text) c.text = text;
    if (title) c.title = title;
    if (force) {
      c.allowOutsideClick = false;
      c.allowEscapeKey = false;
    }
    return swal(c).then(
      function () {
        cb ? cb() : null;
      }.bind(this),
      function (d) {},
    );
  },
  timer: function ({ timer, html, text, title, type, mode, cb }) {
    if (swal.isVisible()) { swal.close(); }
    var c = {
      timer: timer,
      type: 'success',
      title: MESSAGE.msg_notice,
      confirmButtonText: MESSAGE.msg_yes,
      // confirmButtonColor: config.loadSpinner.company.color,
      confirmButtonClass: 'btn btn-success',
      buttonsStyling: true,
      showCancelButton: false,
      allowOutsideClick: false,
      onOpen: function () {
        swal.showLoading();
      },
    };
    if (mode && mode === 'user') {
      // c.confirmButtonColor = config.loadSpinner.user.color;
    }
    if (type) c.type = type;
    if (html) c.html = html;
    if (text) c.text = text;
    if (title) c.title = title;
    return swal(c).then(
      function () {},
      function (d) {
        if (d === 'timer') { return cb ? cb() : false; }
      }.bind(this),
    );
  },
};

// 預先綁定 ajax 事件
fn.bindAjaxEvent = function (cb) {

  $(".loading-wrapper").addClass('active');

  // 預設的 ajaxSend hanlder
  $(document).ajaxSend(function(event, jqXHR, settings) {
    this.group('[ajaxSend]', function (log) {
      log('event=>', event);
      log('jqXHR=>', jqXHR);
      log('settings=>', settings);
    });
    if (typeof app !== 'undefined') {
      var url = settings.url;
      if (url.indexOf('/api') > -1) {
        // fn.swal.loading();
        $(".loading-wrapper").addClass('active');
      }
    }
  }.bind(this));

  // 預設的 ajaxSuccess hanlder
  $(document).ajaxSuccess(function(event, jqXHR, settings) {
    // if (jqXHR.status === 200) {
    // } else {
    // }
  }.bind(this));

  // 預設的 ajaxComplete hanlder
  $(document).ajaxComplete(function(event, jqXHR, settings) {
    this.group('[ajaxComplete]', function (log) {
      log('event=>', event);
      log('jqXHR=>', jqXHR);
      log('settings=>', settings);
    });
    var url = settings.url;
    window.setTimeout(function () {
      fn.log('ajax success so close loading');
      // fn.swal.close();
      $(".loading-wrapper").removeClass('active');
    }, 500);
    $('[data-toggle="tooltip"]')
      .tooltip('destroy')
      .tooltip();
  }.bind(this));

  // 預設的 ajaxError hanlder
  $(document).ajaxError(function (event, jqXHR, settings) {
    var msg = jqXHR.responseJSON ?
      jqXHR.responseJSON.message : jqXHR.statusText;
    switch (jqXHR.status) {
      case 500:
        return fn.swal.then({
          type: 'error',
          html: MESSAGE.msg_500 + '<br>(' + msg + ')',
        });
      case 404:
        return fn.swal.then({
          type: 'warning',
          text:  MESSAGE.msg_404,
          cb: function () {
          },
        });
      case 403:
        return fn.swal.then({
          type: 'warning',
          text:  MESSAGE.msg_login_timeout + '(' + msg + ')',
          cb: function () {
            var pathname = window.location.pathname;
            if (!pathname.endsWith('/')) {
              pathname = pathname + '/';
            }
            return fn.page.redirect(window.location.origin + pathname + 'login');
          },
        }); 
      case 400: 
        return fn.swal.then({
          type: 'error',
          html: MESSAGE.msg_400 + '<br>(' + msg + ')',
        });
      default:
        fn.log('jqXHR=>', jqXHR);
        var msg = jqXHR.responseText;
        if (jqXHR && jqXHR.responseJSON && jqXHR.responseJSON.message) {
          msg = MESSAGE.msg_server_error + '(' + jqXHR.responseJSON.message + ')';
        }
        return fn.swal.then({
          type: 'error',
          text: msg,
        });
    }
  }.bind(this));
  if (typeof cb === 'function') cb();
};

// pre-binding onbeforeunload event, to show a loading view.
if (!window.onbeforeunload) {
  window.onbeforeunload = function () {
    if (fn.config.confirmLeave) {
      return true;
    }
    if (typeof fn === 'object') {
      // fn.swal.loading();
      $(".loading-wrapper").addClass('active');
    }
  };
}

// extra binding jquery on show/hide event
if ($) {
  (function ($) {
    $.each(['show', 'hide'], function (i, ev) {
      var el = $.fn[ev];
      $.fn[ev] = function () {
        this.trigger(ev);
        return el.apply(this, arguments);
      };
    });
  })(jQuery);
}

// key-value-pair
var KEY = {
  // message
  msg_500: "<%= __('fn.500') %>",
  msg_404: "<%= __('fn.404') %>",
  msg_400: "<%= __('fn.400') %>",
  msg_notice: "<%= __('fn.swal.label.notice') %>",
  msg_wrong_format: "<%= __('fn.swal.dialog.wrong_format') %>",
  msg_success: "<%=  __('fn.swal.dialog.success') %>",
  msg_file_too_large: "<%=  __('fn.swal.upload.file_too_large') %>",
  msg_file_not_image: "<%=  __('fn.swal.upload.file_not_image') %>",
  msg_delete_confirm: "<%= __('fn.swal.action.delete_confirm') %>",
  msg_text: "<%= __('fn.swal.action.recovery_confirm') %>",
  msg_yes: "<%= __('fn.swal.action.yes') %>",
  msg_cancel: "<%= __('fn.swal.action.cancel') %>",
  msg_server_error: "<%= __('fn.swal.submit.server_failure') %>",
  msg_network_failure: "<%= __('fn.swal.submit.network_failure') %>",
  msg_login_timeout: "<%= __('fn.warning.login.timeout') %>",
  msg_ensure_title: "<%= __('fn.swal.ensure') %>",
  msg_confirm_leave_before_save: '仍有編輯中的資料尚未儲存，確定離開嗎？',
};

</script>
