/**
 * Copyright since 2007 PrestaShop SA and Contributors
 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.md.
 * It is also available through the world-wide-web at this URL:
 * https://opensource.org/licenses/OSL-3.0
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to https://devdocs.prestashop.com/ for more information.
 *
 * @author    PrestaShop SA and Contributors <contact@prestashop.com>
 * @copyright Since 2007 PrestaShop SA and Contributors
 * @license   https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
 */

$(document).ready(function() {
  form.init();
  nav.init();
  featuresCollection.init();
  displayFormCategory.init();
  formCategory.init();
  stock.init();
  supplier.init();
  warehouseCombinations.init();
  customFieldCollection.init();
  virtualProduct.init();
  attachmentProduct.init();
  imagesProduct.init();
  priceCalculation.init();
  displayFieldsManager.refresh();
  displayFieldsManager.init(virtualProduct);
  seo.init();
  tags.init();
  rightSidebar.init();
  recommendedModules.init();
  BOEvent.emitEvent("Product Categories Management started", "CustomEvent");
  BOEvent.emitEvent("Product Default category Management started", "CustomEvent");
  BOEvent.emitEvent("Product Manufacturer Management started", "CustomEvent");
  BOEvent.emitEvent("Product Related Management started", "CustomEvent");
  BOEvent.emitEvent("Modal confirmation started", "CustomEvent");
  BOEvent.emitEvent("Product Combinations Management started", "CustomEvent");

  /** Type product fields display management */
  $('#form_step1_type_product').change(function() {
    displayFieldsManager.refresh();
  });

  // Validate price fields on input change
  $(".money-type input[type='text']").change(function validate() {
    var inputValue = priceCalculation.normalizePrice($(this).val());
    var parsedValue = truncateDecimals(inputValue, 6);

    $(this).val(parsedValue);
  });

  /** tooltips should be hidden when we move to another tab */
  $('#form-nav').on('click','.nav-item', function clearTooltipsAndPopovers() {
    $('[data-toggle="tooltip"]').tooltip('hide');
    $('[data-toggle="popover"]').popover('hide');
  });

  $('.summary-description-container a[data-toggle="tab"]').on('shown.bs.tab', resetEditor);
  form.switchLanguage($('#form_switch_language').val());
});

/**
 * Reset active tinyMce editor (triggered when switch language, or switching tabs)
 */
function resetEditor() {
  const languageEditorsSelector = '.summary-description-container .panel.active div.translation-field.active textarea.autoload_rte';
  $(languageEditorsSelector).each(function(index, textarea) {
    if (window.tinyMCE) {
      const editor = window.tinyMCE.get(textarea.id);
      if (editor) {
        //Reset content to force refresh of editor
        editor.setContent(editor.getContent());
      }
    }
  });
}

/**
 * Manage show or hide fields
 */
var displayFieldsManager = (function() {

  var typeProduct = $('#form_step1_type_product');
  var showVariationsSelector = $('#show_variations_selector');
  var combinationsBlock = $('#combinations');
  var managedVirtualProduct;

  return {
    'init': function (virtualProduct) {
      managedVirtualProduct = virtualProduct;

      /** Type product fields display management */
      $('#form_step1_type_product').change(function () {
        displayFieldsManager.refresh();
      });

      $('#form .form-input-title input').on('focus', function () {
        $(this).select();
      });

      this.initVisibilityRule();

      /** Tax rule dropdown shortcut */
      $('a#tax_rule_shortcut_opener').on('click', function () {
        // lazy instantiated
        var duplicate = $('#form_step2_id_tax_rules_group_shortcut');
        if (duplicate.length == 0) {
          var origin = $('select#form_step2_id_tax_rules_group');
          duplicate = origin.clone(false).attr('id', 'form_step2_id_tax_rules_group_shortcut');
          origin.on('change', function () {
            duplicate.val(origin.val()); // no change() here to avoid infinite loop.
          });
          duplicate.on('change', function () {
            origin.val(duplicate.val()).change();
          });
          duplicate.appendTo($('#tax_rule_shortcut'));
        }
        duplicate.parent().parent().show();

        return false;
      });
    },
    /**
     * When a product is available for order, its price should be visible,
     * whereas products unavailable for order can have their prices visible or hidden.
     */
    'initVisibilityRule': function () {
      var showPriceSelector = '.js-show-price';
      var availableForOrderSelector = '.js-available-for-order';

      var applyVisibilityRule = function applyVisibilityRule() {
        var $availableForOrder = $(availableForOrderSelector + ' input');
        var $showPrice = $(showPriceSelector + ' input');
        var $showPriceColumn = $(showPriceSelector);
        if ($availableForOrder.prop('checked')) {
          $showPrice.prop('checked', true);
          $showPriceColumn.addClass('hide');
        } else {
          $showPriceColumn.removeClass('hide');
        }
      };
      $(availableForOrderSelector + ' .checkbox').on('click', applyVisibilityRule);
      applyVisibilityRule();
    },
    'refresh': function () {
      this.checkAccessVariations();
      $('#virtual_product').hide();
      $('#form-nav a[href="#step3"]').text(translate_javascripts['Quantities']);

      /** product type switch */

      if (typeProduct.val() === '1') {
        $('#pack_stock_type, #js_form_step1_inputPackItems').show();
        $('#form-nav a[href="#step4"]').show();
        showVariationsSelector.hide();
        showVariationsSelector.find('input[value="0"]').attr('checked', true);
      } else {
        $('#virtual_product, #pack_stock_type, #js_form_step1_inputPackItems').hide();
        $('#form-nav a[href="#step4"]').show();

        if (typeProduct.val() === '2') {
          showVariationsSelector.hide();
          $('#virtual_product').show();
          $('#form-nav a[href="#step4"]').hide();
          showVariationsSelector.find('input[value="0"]').attr('checked', true);
          $('#form-nav a[href="#step3"]').text(translate_javascripts['Virtual product']);
        } else {
          showVariationsSelector.show();
          $('#form-nav a[href="#step3"]').text(translate_javascripts['Quantities']);
        }
      }

      // Switching from a product type to another which is not "Virtual product",
      // triggers the destruction of pre-existing virtual product
      var shouldDestroyVirtualProduct = typeProduct.val() !== '2';
      if (shouldDestroyVirtualProduct && managedVirtualProduct !== undefined) {
        managedVirtualProduct.destroy();
      }

      /** check quantity / combinations display */
      if (showVariationsSelector.find('input:checked').val() === '1' || $('#accordion_combinations tr:not(#loading-attribute)').length > 0) {
        combinationsBlock.show();

        $('#form-nav a[href="#step3"]').text(translate_javascripts['Combinations']);
        $('#product_qty_0_shortcut_div, #quantities').hide();
      } else {
        combinationsBlock.hide();
        $('#product_qty_0_shortcut_div, #quantities').show();
      }

      /** Tooltip for product type combinations */
      if ($('input[name="show_variations"][value="1"]:checked').length >= 1) {
        $('#product_type_combinations_shortcut').show();
      } else {
        $('#product_type_combinations_shortcut').hide();
      }
    },
    'getProductType': function () {
      switch (typeProduct.val()) {
        case '0':
          return 'standard';
          break;
        case '1':
          return 'pack';
          break;
        case '2':
          return 'virtual';
          break;
        default:
          return 'standard';
      }
    },
    /**
     * Product pack or virtual can't have variations
     * Warn e-merchant.
     * @param errorMessage
     */
    'checkAccessVariations': function () {
      if ((showVariationsSelector.find('input:checked').val() === '1' || $('#accordion_combinations tr:not(#loading-attribute)').length > 0) && (typeProduct.val() === '1' || typeProduct.val() === '2')) {
        var typeOfProduct = this.getProductType();
        var errorMessage = "You can't create " + typeOfProduct + " product with variations. Are you sure to disable variations ? they will all be deleted.";
        modalConfirmation.create(translate_javascripts[errorMessage], null, {
          onCancel: function () {
            typeProduct.val(0).change();
            /* else the radio bouton is not display even if checked attribute is true */
            $('#show_variations_selector input[value="1"]').click();
          },
          onContinue: function () {
            $.ajax({
              type: 'GET',
              url: $('#accordion_combinations').attr('data-action-delete-all').replace(/delete-all\/\d+/, 'delete-all/' + $('#form_id_product').val()),
              success: function () {
                $('#accordion_combinations .combination').remove();
                displayFieldsManager.refresh();
              },
              error: function (response) {
                showErrorMessage(jQuery.parseJSON(response.responseText).message);
              },
            });
          }
        }).show();
      }
    }
  }
})();

/**
 * Display category form management
 */
var displayFormCategory = (function() {
  var parentElem = $('#add-categories');
  return {
    'init': function() {
      /** Click event on the add button */
      parentElem.find('a.open').on('click', function(e) {
        e.preventDefault();
        parentElem.find('#add-categories-content').removeClass('hide');
        $(this).hide();
      });
    }
  };
})();

/**
 * Form category management
 */
var formCategory = (function() {
  var elem = $('#form_step1_new_category');

  /** Send category form and it to nested categories */
  function send(form) {
    $.ajax({
      type: 'POST',
      url: elem.attr('data-action'),
      data: {
        'form[category][name]': $('#form_step1_new_category_name').val(),
        'form[category][id_parent]': $('#form_step1_new_category_id_parent').val(),
        'form[_token]': $('#form #form__token').val()
      },
      beforeSend: function() {
        $('button.submit', elem).attr('disabled', 'disabled');
        $('ul.text-danger', elem).remove();
        $('*.has-danger', elem).removeClass('has-danger');
        $('*.has-danger').removeClass('has-danger');
      },
      success: function(response) {
        //inject new category into category tree
        var html = '<li>' +
          '<div class="checkbox js-checkbox">' +
            '<label>' +
              '<input type="checkbox" name="form[step1][categories][tree][]" checked value="'+response.category.id+'"> ' +
                response.category.name[1] +
                '<input type="radio" value="'+response.category.id+'" name="ignore" class="default-category">' +
            '</label>' +
          '</div>' +
          '</li>';

        var parentElement = $('#form_step1_categories input[value='+response.category.id_parent+']').parent().parent();
        if(parentElement.next('ul').length === 0){
          html = '<ul>' + html + '</ul>';
          parentElement.append(html);
        } else {
          parentElement.next('ul').append(html);
        }

        //inject new category in parent category selector
        $('#form_step1_new_category_id_parent').append('<option value="' + response.category.id + '">' + response.category.name[1] + '</option>');

        // create label
        var tag = {
          'name': response.category.name[1],
          'id': response.category.id,
          'breadcrumb': ''
        };
        productCategoriesTags.createTag(tag);

        //hide the form
        form.hideBlock();
      },
      error: function(response) {
        $.each(jQuery.parseJSON(response.responseText), function(key, errors) {
          var html = '<ul class="list-unstyled text-danger">';
          $.each(errors, function(key, error) {
            html += '<li>' + error + '</li>';
          });
          html += '</ul>';

          $('#form_step1_new_' + key).parent().append(html);
          $('#form_step1_new_' + key).parent().addClass('has-danger');
        });
      },
      complete: function() {
        $('#form_step1_new_category button.submit').removeAttr('disabled');
      }
    });
  }

  return {
    'init': function() {
      var that = this;
      /** remove all categories from selector, except pre defined */
      $('#add-categories button.save').click(function(){
        send(that);
      });
      $('#add-categories button[type="reset"]').click(function(){
        that.hideBlock();
      });
    },
    'hideBlock': function() {
      $('#form_step1_new_category_name').val('');
      $('#add-category-button').show();
      $('#add-categories-content').addClass('hide');
    }
  };
})();

/**
 * Feature collection management
 */
var featuresCollection = (function() {

  var collectionHolder = $('.feature-collection');
  var maxCollectionChildren = collectionHolder.children('.row').length;

  /** Add a feature */
  function add() {
    var newForm = collectionHolder.attr('data-prototype').replace(/__name__/g, maxCollectionChildren);
    collectionHolder.append(newForm);
    maxCollectionChildren += 1;
    prestaShopUiKit.initSelects();
  }

  return {
    'init': function() {
      /** Click event on the add button */
      $('#features .add').on('click', function(e) {
        e.preventDefault();
        add();
        $('#features-content').removeClass('hide');
      });

      /** Click event on the remove button */
      $(document).on('click', '.feature-collection .delete', function(e) {
        e.preventDefault();
        var _this = $(this);

        modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
          onContinue: function() {
            _this.closest('.product-feature').remove();
          }
        }).show();
      });

      function replaceEndingIdFromUrl(url, newId)
      {
        return url.replace(/\/\d+(?!.*\/\d+)((?=\?.*))?/, '/' + newId);
      }

      /** On feature selector event change, refresh possible values list */
      $(document).on('change', '.feature-collection select.feature-selector', function(event) {
        var that = event.currentTarget;
        var $row = $($(that).parents('.row')[0]);
        var $selector = $row.find('.feature-value-selector');

        if('' !== $(this).val()) {
          $.ajax({
            url: replaceEndingIdFromUrl($(this).attr('data-action'), $(this).val()),
            success: function(response) {
              $selector.prop('disabled', response.length === 0);
              $selector.empty();
              $.each(response, function(index, elt) {
                // the placeholder shouldn't be posted.
                if ('0' == elt.id) {
                  elt.id = '';
                }
                $selector.append($('<option></option>').attr('value', elt.id).text(elt.value));
              });
            }
          });
        }
      });

      var $featuresContainer = $('#features-content');

      $featuresContainer.on('change', '.row select, .row input[type="text"]', function onChange(event){
        var that = event.currentTarget;
        var $row = $($(that).parents('.row')[0]);
        var $definedValueSelector = $row.find('.feature-value-selector');
        var $customValueSelector = $row.find('input[type=text]');

        // if feature has changed we need to reset values
        if ($(that).hasClass('feature-selector')) {
          $customValueSelector.val('');
          $definedValueSelector.val('');
        }
      });
    }
  };
})();

/**
 * Suppliers management
 */
var supplier = (function() {

  var supplierInputManage = function(input) {
    var supplierDefaultInput = $('#form_step6_suppliers input[name="form[step6][default_supplier]"][value=' + $(input).val() +']');
    if ($(input).is(':checked')) {
      supplierDefaultInput.prop('disabled', false).show();
    } else {
      supplierDefaultInput.prop('disabled', true).hide();
    }
  };

  return {
    'init': function() {
      /** On supplier select, hide or show the default supplier selector */
      var supplierInput = $('#form_step6_suppliers input[name="form[step6][suppliers][]"]');
      supplierInput.change(function() {
        supplierInputManage($(this));
        supplierCombinations.refresh();
      });

      //default display
      $('#form_step6_suppliers input[name="form[step6][suppliers][]"]').map(function() {
        supplierInputManage($(this));
      });
    }
  };
})();

/**
 * Supplier combination collection management
 */
var supplierCombinations = (function() {
  var id_product = $('#form_id_product').val();
  var collectionHolder = $('#supplier_combination_collection');

  return {
    'refresh': function() {
      var suppliers = $('#form_step6_suppliers input[name="form[step6][suppliers][]"]:checked').map(function() {
        return $(this).val();
      }).get();
      var url = collectionHolder.attr('data-url')
        .replace(
          /refresh-product-supplier-combination-form\/\d+\/\d+/,
          'refresh-product-supplier-combination-form/' + id_product + (suppliers.length > 0 ? '/' + suppliers.join('-') : '')
        );
      $.ajax({
        url: url,
        success: function(response) {
          collectionHolder.empty().append(response);
        }
      });
    }
  };
})();

/**
 * Quantities management
 */
var stock = (function() {
  return {
    'init': function() {
      /** Update qty_0 and shortcut qty_0 field on change */
      $('#form_step1_qty_0_shortcut, #form_step3_qty_0').on('change', function() {
        if ($(this).attr('id') === 'form_step1_qty_0_shortcut') {
          $('#form_step3_qty_0').val($(this).val());
        } else {
          $('#form_step1_qty_0_shortcut').val($(this).val());
        }
      });

      /** if GSA : Show depends_on_stock choice only if advanced_stock_management checked */
      $('#form_step3_advanced_stock_management').on('change', function(e) {
        if (e.target.checked) {
          $('#depends_on_stock_div').show();
        } else {
          $('#depends_on_stock_div').hide();
        }
        warehouseCombinations.refresh();
      });

      /** if GSA activation change on 'depend on stock', update quantities fields */
      $('#form_step3_depends_on_stock_0, #form_step3_depends_on_stock_1, #form_step3_advanced_stock_management').on('change', function(e) {
        displayFieldsManager.refresh();
        warehouseCombinations.refresh();
      });
      displayFieldsManager.refresh();
    }
  };
})();


/**
 * Navigation management
 */
var nav = (function() {
  return {
    'init': function() {
      /** Manage tabls hash routes */
      var hash = document.location.hash;
      var formNav = $("#form-nav");
      var prefix = 'tab-';
      if (hash) {
        formNav.find("a[href='" + hash.replace(prefix, '') + "']").tab('show');
      }

      formNav.find("a").on('shown.bs.tab', function(e) {
        if (e.target.hash) {
          window.location.hash = e.target.hash.replace('#', '#' + prefix);
        }
      });
    }
  };
})();

/**
 * Warehouse combination collection management (ASM only)
 */
var warehouseCombinations = (function() {
  var id_product = $('#form_id_product').val();
  var collectionHolder = $('#warehouse_combination_collection');

  return {
    'init': function() {
      // toggle all button action
      $(document).on('click', 'div[id^="warehouse_combination_"] button.check_all_warehouse', function() {
        var checkboxes = $(this).closest('div[id^="warehouse_combination_"]').find('input[type="checkbox"][id$="_activated"]');
        checkboxes.prop('checked', checkboxes.filter(':checked').length === 0);
      });
      // location disablation depending on 'stored' checkbox
      $(document).on('change', 'div[id^="warehouse_combination_"] input[id^="form_step4_warehouse_combination_"][id$="_activated"]', function() {
        var checked = $(this).prop('checked');
        var location = $(this).closest('div.form-group').find('input[id^="form_step4_warehouse_combination_"][id$="_location"]');
        location.prop('disabled', !checked);
        if (!checked) {
          location.val('');
        }
      });
      this.locationDisabler();
    },
    'locationDisabler': function() {
      $('div[id^="warehouse_combination_"] input[id^="form_step4_warehouse_combination_"][id$="_activated"]', collectionHolder).each(function() {
        var checked = $(this).prop('checked');
        var location = $(this).closest('div.form-group').find('input[id^="form_step4_warehouse_combination_"][id$="_location"]');
        location.prop('disabled', !checked);
      });
    },
    'refresh': function() {
      var show = $('input#form_step3_advanced_stock_management:checked').length > 0;
      if (show) {
        var url = collectionHolder.attr('data-url').replace(/\/\d+(?=\?.*)/, '/' + id_product);
        $.ajax({
          url: url,
          success: function(response) {
            collectionHolder.empty().append(response);
            collectionHolder.show();
            warehouseCombinations.locationDisabler();
          }
        });
      } else {
        collectionHolder.hide();
      }
    }
  };
})();

/**
 * Form management
 */
var form = (function() {
  var elem = $('#form');

  function send(redirect, target, callBack) {
    // target value by default
    if (typeof(target) == 'undefined') {
      target = false;
    }
    seo.onSave();
    updateMissingTranslatedNames();

    var data = $('input, textarea, select', elem).not(':input[type=button], :input[type=submit], :input[type=reset]').serialize();

    if (target == '_blank' && redirect) {
      var openBlank = window.open('about:blank', target, '');
      openBlank.document.write(
        '<p style="text-align: center;">' +
        '<img src="' + document.location.origin + baseAdminDir + '/themes/default/img/spinner.gif">' +
        '</p>'
      );
    }

    $.ajax({
      type: 'POST',
      data: data,
      beforeSend: function() {
        $('#submit', elem).attr('disabled', 'disabled');
        $('.btn-submit', elem).attr('disabled', 'disabled');
        $('ul.text-danger').remove();
        $('*.has-danger').removeClass('has-danger');
        $('#form-nav li.has-error').removeClass('has-error');
        updateDisplayGlobalErrors(null);
      },
      success: function(response) {
        if (callBack) {
          callBack();
        }
        showSuccessMessage(translate_javascripts['Form update success']);
        //update the customization ids
        if (typeof response.customization_fields_ids != "undefined") {
          $.each(response.customization_fields_ids, function (k, v) {
            $("#form_step6_custom_fields_" + k + "_id_customization_field").val(v);
          });
        }

        $('.js-spinner').hide();

        if (!redirect) {
          return;
        }

        if (false === target) {
          window.location = redirect;

          return;
        }

        if ('_blank' !== target) {
          window.open(redirect, target);

          return;
        }

        openBlank.location = redirect;
      },
      error: function(response) {
        showErrorMessage(translate_javascripts['Form update errors']);

        if (target == '_blank' && redirect) {
          openBlank.close();
        }

        var tabsWithErrors = [];

        $.each(jQuery.parseJSON(response.responseText), function(key, errors) {
          tabsWithErrors.push(key);

          var html = '<ul class="list-unstyled text-danger">';
          $.each(errors, function(unusedKey, error) {
            html += '<li>' + error + '</li>';
          });
          html += '</ul>';

          if (0 === key.localeCompare('error')) {
            updateDisplayGlobalErrors(html);
          } else if (key.match(/^combination_.*/)) {
            $('#' + key).parent().addClass('has-danger').append(html);
          } else {
            $('#form_' + key).parent().addClass('has-danger').append(html);
          }

        });

        /** find first tab with error, then switch to it */
        tabsWithErrors.sort();
        $.each(tabsWithErrors, function(key, tabIndex) {
          if (0 === key) {
            $('#form-nav li a[href="#' + tabIndex.split('_')[0] + '"]').tab('show');
          }

          $('#form-nav li a[href="#' + tabIndex.split('_')[0] + '"]').parent().addClass('has-error');
        });

        if ($('div[class*="translation-label-"].has-danger').length > 0) {
          var regexLabel = 'translation-label-';

          var translationLabelClass = $.grep($('div[class*="translation-label-"].has-danger').first().attr('class').split(" "), function(v, i){
            return v.indexOf(regexLabel) === 0;
          }).join();

          if (translationLabelClass) {
            var selectValue = translationLabelClass.replace(regexLabel, '');

            if ($('#form_switch_language option[value="' + selectValue + '"]').length > 0) {
              $('#form_switch_language').val(selectValue).change();
            }
          }
        }

        /** scroll to 1st error */
        if ($('.has-danger').first().offset()) {
          $('html, body').animate({
            scrollTop: $('.has-danger').first().offset().top - $('nav.main-header').height()
          }, 500);
        }
      },
      complete: function() {
        $('#submit', elem).removeAttr('disabled');
        $('.btn-submit', elem).removeAttr('disabled');
      }
    });
  }

  function switchLanguage(isoCode) {
    $(`div.translations.tabbable > div > div.translation-field:not(.translation-label-${isoCode})`)
      .removeClass('show active');

    $(`div.translations.tabbable > div > div.translation-field.translation-label-${isoCode}`).addClass('show active');
    resetEditor();
  }

  function updateMissingTranslatedNames() {
    var namesDiv = $('#form_step1_names');
    var defaultLanguageValue = null;
    $("input[id^='form_step1_name_']", namesDiv).each(function(index) {
      var value = $(this).val();
      // The first language is ALWAYS the employee language
      if (0 === index) {
        defaultLanguageValue = value;
      } else if (0 === value.length) {
        $(this).val(defaultLanguageValue);
      }
    });
  }

  /**
   * Depending on the provided params, this method displays or hides
   * an error panel with the form errors not linked to a specific field.
   *
   * @param {string} content The HTML content to display
   */
  function updateDisplayGlobalErrors(content) {
    const target = $("#form_bubbling_errors");
    target.html('');
    if (content) {
      target.html(`<div class="alert alert-danger">${content}</div>`);
    }
  }

  return {
    'init': function() {
      /** prevent form submit on ENTER keypress */
      jwerty.key('enter', function(e) {
        e.preventDefault();
      });

      /** create keyboard event for save */
      jwerty.key('alt+shift+S', function(e) {
        e.preventDefault();
        send();
      });

      /** create keyboard event for save & duplicate */
      jwerty.key('alt+shift+D', function(e) {
        e.preventDefault();
        send($('.product-footer .duplicate').attr('data-redirect'));
      });

      /** create keyboard event for save & new */
      jwerty.key('alt+shift+P', function(e) {
        e.preventDefault();
        send($('.product-footer .new-product').attr('data-redirect'));
      });

      /** create keyboard event for save & go catalog */
      jwerty.key('alt+shift+Q', function(e) {
        e.preventDefault();
        send($('.product-footer .go-catalog').attr('data-redirect'));
      });

      /** create keyboard event for save & go preview */
      jwerty.key('alt+shift+V', function(e) {
          e.preventDefault();
          var productFooter = $('.product-footer .preview');
          send(productFooter.attr('data-redirect'), productFooter.attr('target'));
      });

      /** create keyboard event for save & active or desactive product*/
      jwerty.key('alt+shift+O', function(e) {
        e.preventDefault();
        var step1CheckBox = $('#form_step1_active');
        step1CheckBox.prop('checked', !step1CheckBox.is(':checked'));
      });

      elem.submit(function(event) {
        event.preventDefault();
        send();
      });

      elem.find('#form_switch_language').change(function(event) {
        event.preventDefault();
        switchLanguage(event.target.value);
      });

      /** on save with duplicate|new|preview */
      $('.btn-submit, .preview', elem).click(function(event) {
        event.preventDefault();
        send($(this).attr('data-redirect'), $(this).attr('target'));
      });

      $('.js-btn-save').on('click', function (event) {
        event.preventDefault();
        $('.js-spinner').css('display', 'inline-block');
        send($(this).attr('href'));
      });

      /** on active field change, send form */
      $('#form_step1_active', elem).on('change', function() {
        var active = $(this).prop('checked');
        $('.for-switch.online-title').toggle(active);
        $('.for-switch.offline-title').toggle(!active);
        // update link preview
        var previewButton = $('#product_form_preview_btn');
        var urlActive = previewButton.attr('data-redirect');
        var urlDeactive = previewButton.attr('data-url-deactive');
        previewButton.attr('data-redirect', urlDeactive);
        previewButton.attr('data-url-deactive', urlActive);
        // update product
        send();
      });

      /** on delete product */
      $('.product-footer .delete', elem).click(function(e) {
        e.preventDefault();
        var _this = $(this);
        modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
          onContinue: function() {
            window.location = _this.attr('href');
          }
        }).show();
      });

      $('#form-loading').fadeIn(function() {
      /** Create Bloodhound engine */
      var engine = new Bloodhound({
        datumTokenizer: function(d) {
          return Bloodhound.tokenizers.whitespace(d.label);
        },
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        prefetch: {
          url: $('#form_step3_attributes').attr('data-prefetch'),
          cache: false
        }
      });

      /** init input typeahead */
      $('#form_step3_attributes').tokenfield({
        typeahead: [{
          hint: false,
          cache: false
        }, {
          source: function(query, syncResults) {
            engine.search(query, function(suggestions) {
              syncResults(filter(suggestions));
            });
          },
          display: 'label'
        }],
        minWidth: '768px'
      });

      /** Filter suggestion with selected tokens */
      var filter = function(suggestions) {
        var selected = [];
        $('#attributes-generator input.attribute-generator').each(function() {
          selected.push($(this).val());
        });

        return $.grep(suggestions, function(suggestion) {
          return $.inArray(suggestion.value, selected) === -1 && $.inArray('group-' + suggestion.data.id_group, selected) === -1;
        });
      };

      /** On event "tokenfield:createtoken" : stop event if its not a typehead result */
      $('#form_step3_attributes').on('tokenfield:createtoken', function(e) {
        if (!e.attrs.data && e.handleObj.origType !== 'tokenfield:createtoken') {
          return false;
        }
      });

      /** On event "tokenfield:createdtoken" : store attributes in input when add a token */
      $('#form_step3_attributes').on('tokenfield:createdtoken', function(e) {
        if (e.attrs.data) {
          $('#attributes-generator').append('<input type="hidden" id="attribute-generator-' + e.attrs.value + '" class="attribute-generator" value="' + e.attrs.value + '" name="options[' + e.attrs.data.id_group + '][' + e.attrs.value + ']" />');
        } else if (e.handleObj.origType == 'tokenfield:createdtoken') {
          $('#attributes-generator').append('<input type="hidden" id="attribute-generator-' + $('.js-attribute-checkbox[data-value="'+e.attrs.value+'"]').data('value') + '" class="attribute-generator" value="' + $('.js-attribute-checkbox[data-value="'+e.attrs.value+'"]').data('value') + '" name="options[' + $('.js-attribute-checkbox[data-value="'+e.attrs.value+'"]').data('group-id') + '][' + $('.js-attribute-checkbox[data-value="'+e.attrs.value+'"]').data('value') + ']" />');
        }
      });

      /** On event "tokenfield:removedtoken" : remove stored attributes input when remove token */
      $('#form_step3_attributes').on('tokenfield:removedtoken', function(e) {
        $('#attribute-generator-' + e.attrs.value).remove();
      });
    });
    },
      'send': function(redirect, target, callBack) {
      send(redirect, target, callBack);
    },
      'switchLanguage': function(iso_code) {
      switchLanguage(iso_code);
    }
  };
})();


/**
 * Custom field collection management
 */
var customFieldCollection = (function() {

  var collectionHolder = $('ul.customFieldCollection');
  var maxCollectionChildren = collectionHolder.children().length;

  /** Add a custom field */
  function add() {
    var newForm = collectionHolder.attr('data-prototype').replace(/__name__/g, maxCollectionChildren);
    maxCollectionChildren += 1;
    collectionHolder.append('<li>' + newForm + '</li>');
  }

  return {
    'init': function() {
      /** Click event on the add button */
      $('#custom_fields a.add').on('click', function(e) {
        e.preventDefault();
        add();
      });

      /** Click event on the remove button */
      $(document).on('click', 'ul.customFieldCollection .delete', function(e) {
        e.preventDefault();
        var _this = $(this);

        modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
          onContinue: function() {
            _this.parent().parent().parent().remove();
          }
        }).show();
      });
    }
  };
})();

/**
 * virtual product management
 */
var virtualProduct = (function() {
  var id_product = $('#form_id_product').val();

  var getOnDeleteVirtualProductFileHandler = function ($deleteButton) {
    return $.ajax({
      type: 'GET',
      url: $deleteButton.attr('href').replace(/\/\d+(?=\?.*)/, '/' + id_product),
      success: function () {
        $('#form_step3_virtual_product_file_input').removeClass('hide').addClass('show');
        $('#form_step3_virtual_product_file_details').removeClass('show').addClass('hide');
      }
    })
  };

  return {
    'init': function() {
      $(document).on('change', 'input[name="form[step3][virtual_product][is_virtual_file]"]', function() {
        if ($(this).val() === '1') {
          $('#virtual_product_content').show();
        } else {
          $('#virtual_product_content').hide();

          var url = $('#virtual_product').attr('data-action-remove').replace(/remove\/\d+/, 'remove/' + id_product);
          //delete virtual product
          $.ajax({
            type: 'GET',
            url: url,
            success: function() {
              //empty form
              $('#form_step3_virtual_product_file_input').removeClass('hide').addClass('show');
              $('#form_step3_virtual_product_file_details').removeClass('show').addClass('hide');
              $('#form_step3_virtual_product_name').val('');
              $('#form_step3_virtual_product_nb_downloadable').val(0);
              $('#form_step3_virtual_product_expiration_date').val('');
              $('#form_step3_virtual_product_nb_days').val(0);
            }
          });
        }
      });

      $('#form_step3_virtual_product_file').change(function(e) {
        if ($(this)[0].files !== undefined) {
          var files = $(this)[0].files;
          var name  = '';

          $.each(files, function(index, value) {
            name += value.name + ', ';
          });
          $('#form_step3_virtual_product_name').val(name.slice(0, -2));
        } else {
          // Internet Explorer 9 Compatibility
          var name = $(this).val().split(/[\\/]/);
          $('#form_step3_virtual_product_name').val(name[name.length - 1]);
        }
      });

      if ($('input[name="form[step3][virtual_product][is_virtual_file]"]:checked').val() === '1') {
        $('#virtual_product_content').show();
      } else {
        $('#virtual_product_content').hide();
      }

      /** delete attached file */
      $('#form_step3_virtual_product_file_details .delete').click(function(e) {
        e.preventDefault();
        var $deleteButton = $(this);

        modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
          onContinue: function() {
            getOnDeleteVirtualProductFileHandler($deleteButton);
          }
        }).show();
      });

      /** save virtual product */
      $('#form_step3_virtual_product_save').click(function() {
        var _this = $(this);
        var data = new FormData();

        if ($('#form_step3_virtual_product_file')[0].files[0]) {
          data.append('product_virtual[file]', $('#form_step3_virtual_product_file')[0].files[0]);
        }
        data.append('product_virtual[is_virtual_file]', $('input[name="form[step3][virtual_product][is_virtual_file]"]:checked').val());
        data.append('product_virtual[name]', $('#form_step3_virtual_product_name').val());
        data.append('product_virtual[nb_downloadable]', $('#form_step3_virtual_product_nb_downloadable').val());
        data.append('product_virtual[expiration_date]', $('#form_step3_virtual_product_expiration_date').val());
        data.append('product_virtual[nb_days]', $('#form_step3_virtual_product_nb_days').val());

        $.ajax({
          type: 'POST',
          url: $('#virtual_product').attr('data-action').replace(/save\/\d+/, 'save/' + id_product),
          data: data,
          contentType: false,
          processData: false,
          beforeSend: function() {
            _this.prop('disabled', 'disabled');
            $('ul.text-danger').remove();
            $('*.has-danger').removeClass('has-danger');
          },
          success: function(response) {
            showSuccessMessage(translate_javascripts['Form update success']);
            if (response.file_download_link) {
              $('#form_step3_virtual_product_file_details a.download').attr('href', response.file_download_link);
              $('#form_step3_virtual_product_file_input').removeClass('show').addClass('hide');
              $('#form_step3_virtual_product_file_details').removeClass('hide').addClass('show');
            }
          },
          error: function(response) {
            $.each(jQuery.parseJSON(response.responseText), function(key, errors) {
              var html = '<ul class="list-unstyled text-danger">';
              $.each(errors, function(key, error) {
                html += '<li>' + error + '</li>';
              });
              html += '</ul>';

              $('#form_step3_virtual_product_' + key).parent().append(html);
              $('#form_step3_virtual_product_' + key).parent().addClass('has-danger');
            });
          },
          complete: function() {
            _this.removeAttr('disabled');
          }
        });
      });
    },
    'destroy': function () {
      var fileDetailsSelector = '#form_step3_virtual_product_file_details';
      var fileAssociationExists = !$(fileDetailsSelector).hasClass('hide');

      if (fileAssociationExists) {
        var $deleteButton = $(fileDetailsSelector + ' .delete');
        getOnDeleteVirtualProductFileHandler($deleteButton);
      }

      var associatedFileCheckboxSelectorPrefix = '#form_step3_virtual_product_is_virtual_file_';
      $(associatedFileCheckboxSelectorPrefix + '0').prop('checked', false);
      $(associatedFileCheckboxSelectorPrefix + '1').prop('checked', true);

      $('#virtual_product_content input').val('');
    }
  }
})();

/**
 * attachment product management
 */
var attachmentProduct = (function() {
  var id_product = $('#form_id_product').val();

  return {
    'init': function() {
      var buttonSave = $('#form_step6_attachment_product_add');
      var buttonCancel = $('#form_step6_attachment_product_cancel');

      buttonCancel.click(function (){
        resetAttachmentForm();
      });

      function resetAttachmentForm() {
        $('#form_step6_attachment_product_file').val('');
        $('#form_step6_attachment_product_name').val('');
        $('#form_step6_attachment_product_description').val('');
      }

      function replaceEndingIdFromUrl(url, newId)
      {
        return url.replace(/\/\d+(?!.*\/\d+)((?=\?.*))?/, '/' + newId);
      }

      /** add attachment */
      $('#form_step6_attachment_product_add').click(function() {
        var _this = $(this);
        var data = new FormData();

        if ($('#form_step6_attachment_product_file')[0].files[0]) {
          data.append('product_attachment[file]', $('#form_step6_attachment_product_file')[0].files[0]);
        }
        data.append('product_attachment[name]', $('#form_step6_attachment_product_name').val());
        data.append('product_attachment[description]', $('#form_step6_attachment_product_description').val());

        $.ajax({
          type: 'POST',
          url: replaceEndingIdFromUrl($('#form_step6_attachment_product').attr('data-action'), id_product),
          data: data,
          contentType: false,
          processData: false,
          beforeSend: function() {
            buttonSave.prop('disabled', 'disabled');
            $('ul.text-danger').remove();
            $('*.has-danger').removeClass('has-danger');
          },
          success: function(response) {
            resetAttachmentForm();

            //inject new attachment in attachment list
            if (response.id) {
              var row = '<tr>\
                <td class="col-md-3"><input type="checkbox" name="form[step6][attachments][]" value="' + response.id + '" checked="checked"> ' + response.real_name + '</td>\
                <td class="col-md-6">' + response.file_name + '</td>\
                <td class="col-md-2">' + response.mime + '</td>\
              </tr>';

              $('#product-attachment-file tbody').append(row);
              $('.js-options-no-attachments').addClass('hide');
              $('.js-options-with-attachments').removeClass('hide');
            }
          },
          error: function(response) {
            $.each(jQuery.parseJSON(response.responseText), function(key, errors) {
              var html = '<ul class="list-unstyled text-danger">';
              $.each(errors, function(key, error) {
                html += '<li>' + error + '</li>';
              });
              html += '</ul>';

              $('#form_step6_attachment_product_' + key).parent().append(html);
              $('#form_step6_attachment_product_' + key).parent().addClass('has-danger');
            });
          },
          complete: function() {
            buttonSave.removeAttr('disabled');
          }
        });
      });
    }
  };
})();

/**
 * images product management
 */
var imagesProduct = (function() {
  var dropZoneElem = $('#product-images-dropzone');
  var expanderElem = $('#product-images-container .dropzone-expander');

  function checkDropzoneMode() {
      if (!dropZoneElem.find('.dz-preview:not(.openfilemanager)').length) {
        dropZoneElem.removeClass('dz-started');
        dropZoneElem.find('.dz-preview.openfilemanager').hide();
      }
      else {
          dropZoneElem.find('.dz-preview.openfilemanager').show();
      }
  };

  return {
    'toggleExpand': function() {
        if (expanderElem.hasClass('expand')) {
          dropZoneElem.css('height', 'auto');
          expanderElem.removeClass('expand').addClass('compress');
        } else {
          dropZoneElem.css('height', '');
          expanderElem.removeClass('compress').addClass('expand');
        }
    },
    'displayExpander': function() {
      expanderElem.show();
    },
    'hideExpander': function() {
      expanderElem.hide();
    },
    'shouldDisplayExpander': function () {
      var oldHeight = dropZoneElem.css('height');

      dropZoneElem.css('height', '');
      var closedHeight = dropZoneElem.outerHeight();
      var realHeight = dropZoneElem[0].scrollHeight;
      dropZoneElem.css('height', oldHeight);

      return (realHeight > closedHeight);
    },
    'updateExpander': function() {
      if (this.shouldDisplayExpander()) {
        this.displayExpander();
      }
    },
    'initExpander': function() {
      if (this.shouldDisplayExpander()) {
        this.displayExpander();
        expanderElem.addClass('expand');
      }

      var self = this;
      $(document).on('click', '#product-images-container .dropzone-expander', function() {
        self.toggleExpand();
      });
    },
    'init': function() {
      Dropzone.autoDiscover = false;
      var errorElem = $('#product-images-dropzone-error');

      //on click image, display custom form
      $(document).on('click', '#product-images-dropzone .dz-preview', function() {
        if (!$(this).attr('data-id')) {
          return;
        }
        formImagesProduct.form($(this).attr('data-id'));
      });

      var dropzoneOptions = {
        url: dropZoneElem.attr('url-upload'),
        paramName: 'form[file]',
        maxFilesize: dropZoneElem.attr('data-max-size'),
        addRemoveLinks: true,
        clickable: '.openfilemanager',
        thumbnailWidth: 250,
        thumbnailHeight: null,
        acceptedFiles: 'image/*',
        timeout: 0,
        dictRemoveFile: translate_javascripts['Delete'],
        dictFileTooBig: translate_javascripts['ToLargeFile'],
        dictCancelUpload: translate_javascripts['Delete'],
        sending: function(file, response) {
          checkDropzoneMode();
          expanderElem.addClass('expand').click();
          errorElem.html('');
        },
        queuecomplete: function() {
          checkDropzoneMode();
          dropZoneElem.sortable('enable');
          imagesProduct.updateExpander();
        },
        processing: function() {
          dropZoneElem.sortable('disable');
        },
        success: function(file, response) {
          //manage error on uploaded file
          if (response.error !== 0) {
            errorElem.append($('<p></p>').text(file.name + ': ' + response.error));
            this.removeFile(file);
            return;
          }

          //define id image to file preview
          $(file.previewElement).attr('data-id', response.id);
          $(file.previewElement).attr('url-update', response.url_update);
          $(file.previewElement).attr('url-delete', response.url_delete);
          $(file.previewElement).addClass('ui-sortable-handle');
          if (response.cover === 1) {
            imagesProduct.updateDisplayCover(response.id);
          }
        },
        error: function(file, response) {
          var message = '';
          if ($.type(response) === 'undefined') {
            return;
          } else if ($.type(response) === 'string') {
            message = response;
          } else if (response.message) {
            message = response.message;
          }

          if (message === '') {
            return;
          }

          //append new error
          errorElem.append($('<p></p>').text(file.name + ': ' + message));

          //remove uploaded item
          this.removeFile(file);
        },
        init: function() {
          //if already images uploaded, mask drop file message
          if (dropZoneElem.find('.dz-preview:not(.openfilemanager)').length) {
            dropZoneElem.addClass('dz-started');
          } else {
            dropZoneElem.find('.dz-preview.openfilemanager').hide();
          }

          //init sortable
          dropZoneElem.sortable({
            items: "div.dz-preview:not(.disabled)",
            opacity: 0.9,
            containment: 'parent',
            distance: 32,
            tolerance: 'pointer',
            cursorAt: {
              left: 64,
              top: 64
            },
            cancel: '.disabled',
            stop: function(event, ui) {
              var sort = {};
              $.each(dropZoneElem.find('.dz-preview:not(.disabled)'), function(index, value) {
                if (!$(value).attr('data-id')) {
                  sort = false;
                  return;
                }
                sort[$(value).attr('data-id')] = index + 1;
              });

              //if sortable ok, update it
              if (sort) {
                $.ajax({
                  type: 'POST',
                  url: dropZoneElem.attr('url-position'),
                  data: {
                    json: JSON.stringify(sort)
                  }
                });
              }
            },
            start: function(event, ui) {
              //init zindex
              dropZoneElem.find('.dz-preview').css('zIndex', 1);
              ui.item.css('zIndex', 10);
            }
          });

          dropZoneElem.disableSelection();
          imagesProduct.initExpander();
        }
      };

      dropZoneElem.dropzone(jQuery.extend(dropzoneOptions));
    },
    'updateDisplayCover': function(id_image) {
      $('#product-images-dropzone .dz-preview .iscover').remove();
      $('#product-images-dropzone .dz-preview[data-id="' + id_image + '"]')
        .append('<div class="iscover">' + translate_javascripts['Cover'] + '</div>');
    },
    'checkDropzoneMode': function() {
      checkDropzoneMode();
    },
    'getOlderImageId': function() {
      return Math.min.apply(Math,$('.dz-preview').map(function(){
        return $(this).data('id');
      }));
    }
  };
})();


var formImagesProduct = (function() {
  var dropZoneElem = $('#product-images-dropzone');
  var formZoneElem = $('#product-images-form-container');

  formZoneElem.magnificPopup({
    delegate: 'a.open-image',
    type: 'image'
  });

  function toggleColDropzone(enlarge) {
      var smallCol = "col-md-8";
      var largeCol = "col-md-12";
      if (true === enlarge) {
          dropZoneElem.removeClass(smallCol).addClass(largeCol);
      } else {
          dropZoneElem.removeClass(largeCol).addClass(smallCol);
      }
  }

  return {
    'form': function(id) {
      dropZoneElem.find(".dz-preview.active").removeClass("active");
      dropZoneElem.find(".dz-preview[data-id='"+id+"']").addClass("active");
      if(imagesProduct.shouldDisplayExpander() == false){
        dropZoneElem.css('height','auto');
      }
      $.ajax({
        url: dropZoneElem.find(".dz-preview[data-id='"+id+"']").attr('url-update'),
        success: function(response) {
          formZoneElem.find('#product-images-form').html(response);
          form.switchLanguage($('#form_switch_language').val());
        },
        complete: function() {
          toggleColDropzone(false);
          formZoneElem.show();
        }
      });
    },
    'send': function(id) {
      $.ajax({
        type: 'POST',
        url: dropZoneElem.find(".dz-preview[data-id='"+id+"']").attr('url-update'),
        data: formZoneElem.find('textarea, input').serialize(),
        beforeSend: function() {
          formZoneElem.find('.actions button').prop('disabled', 'disabled');
          formZoneElem.find('ul.text-danger').remove();
          formZoneElem.find('*.has-danger').removeClass('has-danger');
        },
        success: function() {
          if (formZoneElem.find('#form_image_cover:checked').length) {
            imagesProduct.updateDisplayCover(id);
          }
        },
        error: function(response) {
          if (response && response.responseText) {
            $.each(jQuery.parseJSON(response.responseText), function(key, errors) {
              var html = '<ul class="list-unstyled text-danger">';
              $.each(errors, function(key, error) {
                html += '<li>' + error + '</li>';
              });
              html += '</ul>';

              $('#form_image_' + key).parent().append(html);
              $('#form_image_' + key).parent().addClass('has-danger');
            });
          }
        },
        complete: function() {
          formZoneElem.find('.actions button').removeAttr('disabled');
        }
      });
    },
    'delete': function(id) {
      modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
        onContinue: function() {
          $.ajax({
            url: dropZoneElem.find('.dz-preview[data-id="' + id + '"]').attr('url-delete'),
            complete: function() {
              formZoneElem.find('.close').click();
              var wasCover = !!dropZoneElem.find('.dz-preview[data-id="' + id + '"] .iscover').length;
              dropZoneElem.find('.dz-preview[data-id="' + id + '"]').remove();
              $('.images .product-combination-image [value=' + id + ']').parent().remove();
              imagesProduct.checkDropzoneMode();
              if (true === wasCover) {
                // The controller will choose the oldest image as the new cover.
                imagesProduct.updateDisplayCover(imagesProduct.getOlderImageId());
              }
            }
          });
        }
      }).show();
    },
    'close': function() {
      toggleColDropzone(true);
      dropZoneElem.css('height','');
      formZoneElem.find('#product-images-form').html('');
      formZoneElem.hide();
      dropZoneElem.find(".dz-preview.active").removeClass("active");
    }
  };
})();

/**
 * Price calculation
 */
var priceCalculation = (function() {
  var priceHTElem = $('#form_step2_price');
  var priceHTShortcutElem = $('#form_step1_price_shortcut');
  var priceTTCElem = $('#form_step2_price_ttc');
  var priceTTCShorcutElem = $('#form_step1_price_ttc_shortcut');
  var ecoTaxElem = $('#form_step2_ecotax');
  var taxElem = $('#form_step2_id_tax_rules_group');
  var reTaxElem = $('#step2_id_tax_rules_group_rendered');
  var displayPricePrecision = priceHTElem.attr('data-display-price-precision');
  var ecoTaxRate = Number(ecoTaxElem.attr('data-eco-tax-rate'));
  if (isNaN(ecoTaxRate)) {
    ecoTaxRate = 0;
  } else {
    ecoTaxRate = ecoTaxRate / 100;
  }

  /**
   * Add taxes to a price
   * @param {Number} price - Price without tax
   * @param {Number[]} rates - Rates to apply
   * @param {Number} computationMethod The computation calculate method
   */
  function addTaxes(price, rates, computationMethod) {
    var price_with_taxes = price;

    var i = 0;
    if (computationMethod === '0') {
      for (i in rates) {
        price_with_taxes *= (1.00 + parseFloat(rates[i]) / 100.00);
        break;
      }
    } else if (computationMethod === '1') {
      var rate = 0;
      for (i in rates) {
        rate += rates[i];
      }
      price_with_taxes *= (1.00 + parseFloat(rate) / 100.00);
    } else if (computationMethod === '2') {
      for (i in rates) {
        price_with_taxes *= (1.00 + parseFloat(rates[i]) / 100.00);
      }
    }

    return price_with_taxes;
  }

  /**
   * Remove taxes from a price
   * @param {Number} price - Price with tax
   * @param {Number[]} rates - Rates to apply
   * @param {Number} computationMethod - The computation method
   */
  function removeTaxes(price, rates, computationMethod) {
    var i = 0;
    if (computationMethod === '0') {
      for (i in rates) {
        price /= (1 + rates[i] / 100);
        break;
      }
    } else if (computationMethod === '1') {
      var rate = 0;
      for (i in rates) {
        rate += rates[i];
      }
      price /= (1 + rate / 100);
    } else if (computationMethod === '2') {
      for (i in rates) {
        price /= (1 + rates[i] / 100);
      }
    }

    return price;
  }

  /**
   * @return {Number}
   */
  function getEcotaxTaxIncluded() {
    var ecoTax = Tools.parseFloatFromString(ecoTaxElem.val());

    if (isNaN(ecoTax)) {
      ecoTax = 0;
    }

    if (ecoTax === 0) {
      return ecoTax;
    }
    return ps_round(ecoTax, displayPricePrecision);
  }

  function getEcotaxTaxExcluded() {
    var ecoTax = Tools.parseFloatFromString(ecoTaxElem.val());

    if (isNaN(ecoTax) || ecoTax === 0) {
      return 0;
    }

    return ps_round(ecoTax / (1 + ecoTaxRate), displayPricePrecision);
  }

  return {

    getProductBasePrice: function() {
      return Tools.parseFloatFromString(priceHTElem.val());
    },

    getDisplayPricePrecision: function() {
      return displayPricePrecision;
    },

    init: function () {
      /** on update tax recalculate tax include price */
      taxElem.change(function() {
        if (reTaxElem.val() !== taxElem.val()) {
          reTaxElem.val(taxElem.val()).trigger('change');
        }

        priceCalculation.taxInclude();
        priceTTCElem.change();
      });

      reTaxElem.change(function() {
        taxElem.val(reTaxElem.val()).trigger('change');
      });

      /** update without tax price and shortcut price field on change */
      $('#form_step1_price_shortcut, #form_step2_price').keyup(function() {
        var price = priceCalculation.normalizePrice($(this).val());

        if ($(this).attr('id') === 'form_step1_price_shortcut') {
          $('#form_step2_price').val(price).change();
        } else {
          $('#form_step1_price_shortcut').val(price).change();
        }

        priceCalculation.taxInclude();
      });

      /** update HT price and shortcut price field on change */
      $('#form_step1_price_ttc_shortcut, #form_step2_price_ttc').keyup(function() {
        var price = priceCalculation.normalizePrice($(this).val());

        if ($(this).attr('id') === 'form_step1_price_ttc_shortcut') {
          $('#form_step2_price_ttc').val(price).change();
        } else {
          $('#form_step1_price_ttc_shortcut').val(price).change();
        }

        priceCalculation.taxExclude();
      });

      /** on price change, update final retails prices */
      $('#form_step2_price, #form_step2_price_ttc').change(function() {
        var taxExcludedPrice = priceCalculation.normalizePrice($('#form_step2_price').val());
        var taxIncludedPrice = priceCalculation.normalizePrice($('#form_step2_price_ttc').val());

        formatCurrencyCldr(taxExcludedPrice, function(result) {
          $('#final_retail_price_te').text(result);
        });
        formatCurrencyCldr(taxIncludedPrice, function(result) {
          $('#final_retail_price_ti').text(result);
        });
      });

      /** update HT price and shortcut price field on change */
      $('#form_step2_ecotax').keyup(function() {
        priceCalculation.taxExclude();
      });

      /** combinations : update TTC price field on HT change */
      $(document).on('blur', '.combination-form .attribute_priceTE', function() {
        priceCalculation.impactTaxInclude($(this));
        priceCalculation.impactFinalPrice($(this));
      });
      /** combinations : update HT price field on TTC change */
      $(document).on('blur', '.combination-form .attribute_priceTI', function() {
        priceCalculation.impactTaxExclude($(this));
        priceCalculation.impactFinalPrice($(this));
      });
      /** combinations : update price fields on ecotax change */
      $(document).on('blur', '.combination-form .attribute_ecotaxTi', function() {
        priceCalculation.impactPricesForEcotax($(this));
        priceCalculation.impactFinalPrice($(this));
      });

      /** combinations : update wholesale price, unity and price TE field on blur */
      $(document).on('blur','.combination-form .attribute_wholesale_price,.combination-form .attribute_unity,.combination-form .attribute_priceTE', function(){
        $(this).val(priceCalculation.normalizePrice($(this).val()));
      });

      priceCalculation.taxInclude();

      $('#form_step2_price, #form_step2_price_ttc').change();
    },

    /**
     * Converts a price string into a number
     * @param {String} price
     * @return {Number}
     */
    normalizePrice: function (price) {
      return Tools.parseFloatFromString(price, true);
    },

    /**
     * Adds taxes to a price
     * @param {Number} price Price without taxes
     * @return {Number} Price with added taxes
     */
    addCurrentTax: function (price) {
      var rates = this.getRates();
      var computation_method = taxElem.find('option:selected').attr('data-computation-method');
      var priceWithTaxes = Number(ps_round(addTaxes(price, rates, computation_method), displayPricePrecision));
      var ecotaxIncluded = Number(getEcotaxTaxIncluded());

      return priceWithTaxes + ecotaxIncluded;
    },

    /**
     * Calculates the price with taxes and updates the elements containing it
     */
    taxInclude: function () {
      var newPrice = truncateDecimals(this.addCurrentTax(this.normalizePrice(priceHTElem.val())), displayPricePrecision);

      priceTTCElem.val(newPrice).change();
      priceTTCShorcutElem.val(newPrice).change();
    },

    /**
     * Removes taxes from a price
     * @param {Number} price Price with taxes
     * @return {Number} Price without taxes
     */
    removeCurrentTax: function (price) {
      var rates = this.getRates();
      var computation_method = taxElem.find('option:selected').attr('data-computation-method');

      return ps_round(removeTaxes(ps_round(price - getEcotaxTaxIncluded(), displayPricePrecision), rates, computation_method), displayPricePrecision);
    },

    /**
     * Calculates the price without taxes and updates the elements containing it
     */
    taxExclude: function () {
      var newPrice = truncateDecimals(this.removeCurrentTax(this.normalizePrice(priceTTCElem.val())), displayPricePrecision);

      priceHTElem.val(newPrice).change();
      priceHTShortcutElem.val(newPrice).change();
    },

    /**
     * Calculates and displays the impact on price (including tax) for a combination
     * @param {jQuery} obj
     */
    impactTaxInclude: function (obj) {
      var impactPriceTE = this.getImpactTEInputValue(obj);
      var impactPriceTI = this.computePriceTaxIncluded(impactPriceTE);

      this.updateImpactTIInput(impactPriceTI, obj);
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {jQuery}
     */
    getImpactTIInput: function(obj) {
      return obj.closest('div[id^="combination_form_"]').find('input.attribute_priceTI');
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {Number}
     */
    getImpactTIInputValue: function(obj) {
      var impactPriceTIInput = this.getImpactTIInput(obj);

      return Tools.parseFloatFromString(impactPriceTIInput.val());
    },

    /**
     * Computes the impact price tax included and update the related input
     *
     * @param {Number} impactPriceTI
     * @param {jQuery} obj
     */
    updateImpactTIInput: function(impactPriceTI, obj) {
      var impactPriceTIInput = this.getImpactTIInput(obj);
      impactPriceTIInput
        .val(impactPriceTI)
        .trigger('change')
      ;
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {jQuery}
     */
    getImpactTEInput: function(obj) {
      return obj.closest('div[id^="combination_form_"]').find('input.attribute_priceTE');;
    },

    /**
     * @param {jQuery} obj
     *
     * @returns {Number}
     */
    getImpactTEInputValue: function(obj) {
      var impactPriceTEInput = this.getImpactTEInput(obj);

      return Number(Tools.parseFloatFromString(impactPriceTEInput.val()));
    },

    /**
     * Updates the impact price tax excluded field, then update the impact tax included field accordingly
     *
     * @param {Number} impactPriceTE
     * @param {jQuery} obj
     */
    updateImpactTEInput: function(impactPriceTE, obj) {
      var impactPriceTEInput = this.getImpactTEInput(obj);
      impactPriceTEInput
        .val(impactPriceTE)
        .trigger('change')
      ;

      var impactPriceTI = this.computePriceTaxIncluded(impactPriceTE);
      this.updateImpactTIInput(impactPriceTI, obj);
    },

    /**
     * @param {Number} priceTE
     *
     * @returns {Number}
     */
    computePriceTaxIncluded(priceTE) {
      var priceTI = 0;
      if (!isNaN(priceTE) && priceTE !== 0) {
        var rates = this.getRates();
        var computation_method = taxElem.find('option:selected').attr('data-computation-method');
        priceTI = ps_round(addTaxes(priceTE, rates, computation_method), displayPricePrecision);
      }

      return priceTI;
    },

    /**
     * @param {Number} priceTI
     *
     * @returns {Number}
     */
    computePriceTaxExcluded(priceTI) {
      var priceTE = 0;
      if (!isNaN(priceTI) && priceTI !== 0) {
        var rates = this.getRates();
        var computation_method = taxElem.find('option:selected').attr('data-computation-method');
        priceTE = ps_round(removeTaxes(priceTI, rates, computation_method), displayPricePrecision);
      }

      return priceTE;
    },

    /**
     * Calculates and displays the final price for a combination
     * @param {jQuery} obj
     */
    impactFinalPrice: function (obj) {
      this.impactFinalPriceTaxExcluded(obj);
      this.impactFinalPriceTaxIncluded(obj);
    },

    /**
     * @param {jQuery} obj
     */
    impactFinalPriceTaxExcluded(obj) {
      var combinationForm = obj.closest('div[id^="combination_form_"]');

      var impactPriceTE = this.getImpactTEInputValue(obj);
      var ecotaxTE = this.getCombinationEcotaxTaxExcluded(obj);
      // If no ecotax for combination use the product's one
      if (ecotaxTE <= 0) {
        ecotaxTE = getEcotaxTaxExcluded();
      }

      var finalPriceContainer = combinationForm.find('.final-price');
      var productPriceTE = priceCalculation.getProductBasePrice();
      var finalPriceTE = productPriceTE + impactPriceTE + ecotaxTE;
      finalPriceTE = ps_round(finalPriceTE, displayPricePrecision);

      finalPriceContainer.html(finalPriceTE);
      finalPriceContainer.data('price', finalPriceTE);
    },

    /**
     * @param {jQuery} obj
     */
    impactFinalPriceTaxIncluded(obj) {
      var combinationForm = obj.closest('div[id^="combination_form_"]');

      var impactPriceTE = this.getImpactTEInputValue(obj);
      var ecotaxTI = this.getCombinationEcotaxTaxIncluded(obj);
      // If no ecotax for combination use the product's one
      if (ecotaxTI <= 0) {
        ecotaxTI = getEcotaxTaxIncluded();
      }

      var finalPriceTIContainer = combinationForm.find('.final-price-tax-included');
      var productPriceTE = priceCalculation.getProductBasePrice();
      var finalPriceTI = this.computePriceTaxIncluded(productPriceTE + impactPriceTE) + ecotaxTI;
      finalPriceTI = ps_round(finalPriceTI, displayPricePrecision);

      finalPriceTIContainer.html(finalPriceTI);
      finalPriceTIContainer.data('price', finalPriceTI);
    },

    /**
     * Calculates the impact on price so that the change on ecotax doesn't affect the final price
     * @param {jQuery} obj
     */
    impactPricesForEcotax: function (obj) {
      var finalPriceTIContainer = obj.closest('div[id^="combination_form_"]').find('.final-price-tax-included');
      var currentFinalPriceTI = Number(finalPriceTIContainer.data('price'));
      var productPrice = priceCalculation.getProductBasePrice();
      var productPriceTI = this.computePriceTaxIncluded(productPrice);
      var ecotaxTI = this.getCombinationEcotaxTaxIncluded(obj);
      // If no ecotax for combination use the product's one
      if (ecotaxTI <= 0) {
        ecotaxTI = getEcotaxTaxIncluded();
      }

      // Compute impact price tax excluded then update the price tax included
      var impactPriceTI = currentFinalPriceTI - ecotaxTI - productPriceTI;
      impactPriceTI = ps_round(impactPriceTI, displayPricePrecision);
      var impactPriceTE = this.computePriceTaxExcluded(impactPriceTI);

      this.updateImpactTEInput(impactPriceTE, obj);
    },

    /**
     * Calculates and displays the impact on price (excluding tax) for a combination
     * @param {jQuery} obj
     */
    impactTaxExclude: function (obj) {
      var impactPriceTI = this.getImpactTIInputValue(obj);
      var impactPriceTE = this.computePriceTaxExcluded(impactPriceTI);

      this.updateImpactTEInput(impactPriceTE, obj);
    },

    /**
     * @param {jQuery} obj
     *
     * @return {Number}
     */
    getCombinationEcotaxTaxExcluded(obj) {
      var ecoTaxTI = priceCalculation.getCombinationEcotaxTaxIncluded(obj);
      if (ecoTaxTI === 0) {
        return 0;
      }

      return ps_round(ecoTaxTI / (1 + ecoTaxRate), displayPricePrecision);
    },

    /**
     * @param {jQuery} obj
     *
     * @return {Number}
     */
    getCombinationEcotaxTaxIncluded(obj) {
      var ecotaxTIInput = obj.closest('div[id^="combination_form_"]').find('input.attribute_ecotaxTi');

      var ecoTaxTI = Tools.parseFloatFromString(ecotaxTIInput.val());
      if (isNaN(ecoTaxTI)) {
        ecoTaxTI = 0;
      }

      return ecoTaxTI;
    },

    /**
     * @param {int} attributeId
     * @returns {Number}
     */
    getCombinationEcotaxTaxIncludedById(attributeId) {
      var formFinalPriceLabel = $('#combination_form_' + attributeId).find('span.final-price');

      return priceCalculation.getCombinationEcotaxTaxIncluded(formFinalPriceLabel);
    },

    /**
     * @param {int} attributeId
     *
     * @returns {Number}
     */
    getCombinationFinalPriceTaxExcludedById(attributeId) {
      var combinationForm = $('#combination_form_' + attributeId);
      var formFinalPriceLabel = combinationForm.find('span.final-price');
      var combinationEcotaxTE = priceCalculation.getCombinationEcotaxTaxExcluded(formFinalPriceLabel);
      if (combinationEcotaxTE <= 0) {
        combinationEcotaxTE = priceCalculation.getProductEcotaxTaxExcluded();
      }

      var impactPriceTEInput = combinationForm.find('.attribute_priceTE');
      var impactPriceTE = Tools.parseFloatFromString(impactPriceTEInput.val());

      // Compute final price and update field
      var productPrice = priceCalculation.getProductBasePrice();
      var finalPrice = productPrice + combinationEcotaxTE + impactPriceTE;
      finalPrice = ps_round(finalPrice, displayPricePrecision);

      return finalPrice;
    },

    /**
     * @return {Number}
     */
    getProductEcotaxTaxExcluded: function() {
      var ecoTax = priceCalculation.getProductEcotaxTaxIncluded();
      if (ecoTax === 0) {
        return ecoTax;
      }

      return ps_round(ecoTax / (1 + ecoTaxRate), displayPricePrecision);
    },

    /**
     * @return {Number}
     */
    getProductEcotaxTaxIncluded: function() {
      var ecoTaxElem = $('#form_step2_ecotax');
      var ecoTax = Tools.parseFloatFromString(ecoTaxElem.val());

      if (isNaN(ecoTax)) {
        ecoTax = 0;
      }

      return ecoTax;
    },

    /**
     * Returns the tax rates that apply
     * @return {Number[]}
     */
    getRates: function () {
      return taxElem
        .find('option:selected')
        .attr('data-rates')
        .split(',')
        .map(function(rate) {
          return Tools.parseFloatFromString(rate, true);
        });
    }
  };
})();

/**
 * Manage seo
 */
var seo = (function() {
  var redirectTypeElem = $('#form_step5_redirect_type');
  var productRedirect = $('#id-product-redirected');

  /** Hide or show the input product selector */
  function hideShowRedirectToProduct() {
    if ('404' === redirectTypeElem.val()) {
      $('#id-product-redirected').hide();
    } else {
      updateRemoteUrl();
      $('#id-product-redirected').show();
    }
  }

  function updateRemoteUrl() {
    switch(redirectTypeElem.val()) {
      case '301-category':
      case '302-category':
        productRedirect.find('label').html(redirectTypeElem.attr('data-labelcategory'));
        productRedirect.find('input').attr('placeholder', redirectTypeElem.attr('data-placeholdercategory'));
        productRedirect.find('.typeahead-hint').text(redirectTypeElem.attr('data-hintcategory'));
        break;
      default:
        productRedirect.find('label').html(redirectTypeElem.attr('data-labelproduct'));
        productRedirect.find('input').attr('placeholder', redirectTypeElem.attr('data-placeholderproduct'));
        productRedirect.find('.typeahead-hint').text('');
    }

    productRedirect.find('.autocomplete-search').attr('data-remoteurl', redirectTypeElem.find('option:selected').data('remoteurl'));
    productRedirect.find('.autocomplete-search').trigger('buildTypeahead');
  }

  /** Update friendly URL */
  var updateFriendlyUrl = function(elem) {
      /** Attr name equals "form[step1][name][1]".
       * We need in this string the second integer */
      var id_lang = elem.attr('name').match(/\d+/g)[1];
      $('#form_step5_link_rewrite_' + id_lang).val(str2url(elem.val(), 'UTF-8'));
  };

  return {
    'init': function() {

      hideShowRedirectToProduct();
      updateRemoteUrl();

      /** On redirect type select change */
      redirectTypeElem.change(function() {
        productRedirect.find('#form_step5_id_type_redirected-data').html('');
        hideShowRedirectToProduct();
      });

      /** On product title change, update friendly URL*/
      $('#form_step1_names.friendly-url-force-update input').keyup(function() {
        updateFriendlyUrl($(this));
      });

      /** Reset all languages title to friendly url*/
      $('#seo-url-regenerate').click(function() {
        $.each($('#form_step1_names input'), function() {
          updateFriendlyUrl($(this));
        });
      });
    },
    'onSave': function() {
        // check all friendly URLs have been filled. If not, fill them.
        $('input[id^="form_step5_link_rewrite_"]', "#form_step5_link_rewrite").each(function(){
            var elem = $(this);
            if (0 === elem.val().length) {
                var id_lang = elem.attr('name').match(/\d+/g)[1];
                updateFriendlyUrl($('#form_step1_name_' + id_lang));
            }
        });
    }
  };
})();

/**
 * Tags management
 */
var tags = (function() {
  return {
    'init': function() {
      $('#form_step6_tags .tokenfield').tokenfield({
        minWidth: '768px'
      });
    }
  };
})();

var recommendedModules = (function() {
  return {
    'init': function() {
      this.moduleActionMenuLinkSelectors = 'button.module_action_menu_install, button.module_action_menu_enable, ' +
        'button.module_action_menu_uninstall, button.module_action_menu_disable, button.module_action_menu_reset, button.module_action_menu_update';
      $(this.moduleActionMenuLinkSelectors).on('module_card_action_event', this.saveProduct);
    },
    'saveProduct': function(event, action) {
      form.send();
    }
  };
})();
