var Wick = Wick || {};

Wick.InstallerValidation = {
  steps: {
    ['1']: {
      installationTypes: {
        required: true,
        callback: function (value) {
          var elementsToHide = ['gasSafeCard', 'gasSafeCert'];
          elementsToHide.forEach(function (field) {
            var wrapper = $('[name="'+ field +'"]');
            if (value.indexOf('kitchens') >= 0) {
              wrapper.closest('.installer_question-wrap').slideDown();
            } else {
              wrapper.closest('.installer_question-wrap').slideUp();
            }
          })
        }
      },
      installationsNumber_kitchen: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['kitchens'],
        required: true,
        possibleValues: [
          'kitchen_installer_application_6-10_completed',
          'kitchen_installer_application_11_or_more_completed'
        ],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Kitchen Installer any further at this time if you haven\'t completed at least 6 installations in the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you have met this criteria. Please deselect Kitchen to continue.'
        ]
      },
      canArrangePreviousWorks_kitchen: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['kitchens'],
        required: true,
        possibleValues: ['installer_application_kitchen_installation_viewings_yes'],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Kitchen Installer any further at this time if you are unable to arrange for 2 x viewings of your previous work over the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you can meet this criteria. Please deselect Kitchen to continue.'
        ]
      },
      gasSafeRegistration: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['kitchens'],
        required: true,
        possibleValues: ['gas_safe_kitchen_installer_application_yes_not_a_subcontractor', 'gas_safe_kitchen_installer_application_yes_subcontractor'],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Kitchen Installer at this this time if your business does not have Gas Safe qualified engineer.',
          'If this changes however, we look forward to receiving a further application from you in the future.'
        ]
      },
      hasSolidWorktopsExperience: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['kitchens'],
        required: true
      },
      installationsNumber_bathroom: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['bathrooms'],
        required: true,
        possibleValues: [
          'bathroom_installer_application_6-10_installations_completed',
          'bathroom_installer_application_11_or_more_installations_completed'
        ],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Bathroom Installer any further at this time if you haven\'t completed at least 6 installations in the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you have met this criteria. Please deselect Bathroom to continue.'
        ]
      },
      canArrangePreviousWorks_bathroom: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['bathrooms'],
        required: true,
        possibleValues: ['installer_application_bathroom_installation_viewings_yes'],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Bathroom Installer any further at this time if you are unable to arrange for 2 x viewings of your previous work over the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you can meet this criteria. Please deselect Bathroom to continue.'
        ]
      },
      installationsNumber_flooring: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['flooring'],
        required: true,
        possibleValues: [
          'flooring_installer_application_6-10_installations_completed',
          'flooring_installer_application_11_or_more_completed'
        ],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Flooring Installer any further at this time if you haven\'t completed at least 6 installations in the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you have met this criteria. Please deselect Flooring to continue.'
        ]
      },
      canArrangePreviousWorks_flooring: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['flooring'],
        required: true,
        possibleValues: ['installer_application_flooring_installation_viewings_yes'],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Flooring Installer any further at this time if you are unable to arrange for 2 x viewings of your previous work over the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you can meet this criteria. Please deselect Flooring to continue.'
        ]
      },
      flooringTypes: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['flooring'],
        required: true
      },
      installers_flooring: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['flooring'],
        required: true
      },
      installationsNumber_tiling: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['tiling'],
        required: true,
        possibleValues: [
          'tiling_installer_application_6-10_completed',
          'tiling_installer_application_11_or_more_completed'
        ],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Tiling Installer any further at this time if you haven\'t completed at least 6 installations in the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you have met this criteria. Please deselect Tiling to continue.'
        ]
      },
      canArrangePreviousWorks_tiling: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['tiling'],
        required: true,
        possibleValues: ['installer_application_tiling_installation_viewings_yes'],
        error: [
          'Unfortunately we can\'t progress your application to become a Wickes Approved Tiling Installer any further at this time if you are unable to arrange for 2 x viewings of your previous work over the last 12 months.',
          'You can however, apply to become Wickes Approved Installer for another installation type if you can meet this criteria. Please deselect Tiling to continue.'
        ]
      },
      tilingTypes: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['tiling'],
        required: true
      },
      installers_tiling: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['tiling'],
        required: true
      }
    },
    ['2']: {
      businessType: {
        required: true,
        callback:  function (value) {
          var incorporationWrapper = $('[name="hasCompanyIncorporationCertificate"]');
          var utrWrapper = $('[name="hasUtrNumber"]');
          if (value === 'sole_trader') {
            incorporationWrapper.closest('.installer_question-wrap').slideUp();
            utrWrapper.closest('.installer_question-wrap').slideDown();
          } else {
            incorporationWrapper.closest('.installer_question-wrap').slideDown();
            utrWrapper.closest('.installer_question-wrap').slideUp();
          }
        }
      },
      hasVatCertificate: {
        required: true,
        possibleValues: ['installer_application_vat_registered_yes', 'installer_application_vat_registered_no'],
        callback: function (value) {
          var elementsToHide = ['vatCertificate'];
          elementsToHide.forEach(function (field) {
            var wrapper = $('[name="'+ field +'"]');
            if (value === 'installer_application_vat_registered_yes') {
              wrapper.closest('.installer_question-wrap').slideDown();
            } else {
              wrapper.closest('.installer_question-wrap').slideUp();
            }
          })
        }
      },
      hasLiabilityInsurance: {
        required: true,
        possibleValues: ['installer_application_public_liability_yes'],
        error: ['Unfortunately we can\'t progress your application to become a Wickes Approved Installer at this this time if your business does not have public liability insurance of at least £2 million.', 'If this changes however, we look forward to receiving a further application from you in the future.']
      },
      liabilityInsurance: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      hasAsbestosAwarenessCertificate: {
        required: true,
        possibleValues: ['installer_application_completed_asbestos_awareness_course_yes', 'installer_application_completed_asbestos_awareness_course_no']
      },
      asbestosAwarenessCertificate: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      hasPartPCertificate: {
        required: true,
        possibleValues: ['installer_application_part_p_yes'],
        error: ['Unfortunately we can\'t progress your application to become a Wickes Approved Installer at this this time if your business does not have a Part P qualified electrician.', 'If this changes however, we look forward to receiving a further application from you in the future.']
      },
      partPCertificateFront: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      partPCertificateBack: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      gasSafeCert: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['kitchens'],
        required: true,
        possibleValues: ['gasSafeCert_yes', 'gasSafeCert_no']
      },
      gasSafeCertificate: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      gasSafeCard: {
        dependsOnInput: 'installationTypes',
        dependsOnValue: ['kitchens'],
        required: true,
        possibleValues: ['gasSafeCard_yes', 'gasSafeCard_no']
      },
      gasSafeCardFront: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      gasSafeCardBack: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      hasCompanyIncorporationCertificate: {
        dependsOnInput: 'businessType',
        dependsOnValue: ['partnership', 'ltd_company', 'ltd_liability_partnership'],
        required: true,
        possibleValues: ['installer_application_company_incorporation_cert_yes', 'installer_application_company_incorporation_cert_no'],
      },
      companyIncorporationCertificate: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      vat_registered_partner: {
        dependsOnInput: 'vat_registered_partner',
        dependsOnValue: ['installer_application_vat_registered_yes'],
        required: true,
        possibleValues: ['vat_registered_partner_yes', 'vat_registered_partner_no'],
      },
      vatCertificate: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      },
      hasUtrNumber: {
        dependsOnInput: 'businessType',
        dependsOnValue: ['sole_trader'],
        required: true,
        possibleValues: ['installer_application_utr_yes', 'installer_application_utr_no'],
      },
      utrNumberCopy: {
        required: false,
        regex: '^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]{2,5})?(\/.*)?$',
        error: ['Invalid image source.']
      }
    },
    ['3']: {
      title: {
        required: true,
        error: ['Please select a title']
      },
      firstName: {
        required: true,
        regex: "^[\\w ()\/&.,‘’`´'-]+$",
        maxLength: 255,
        error: ['Please enter a first name']
      },
      lastName: {
        required: true,
        regex: "^[\\w ()\/&.,‘’`´'-]+$",
        maxLength: 255,
        error: ['Please enter a surname']
      },
      email: {
        required: true,
        regex: '^[\\w\\+-]+(\\.[\\w-]+)*@([A-Za-z\\d]+([A-Za-z\\d-]+(\\.[A-Za-z\\d]+)*(\\.[A-Za-z]{2,}))|(?:(?:25[0-5]|2[0-4][\\d]|[01]?[\\d][\\d]?)\\.){3}(?:25[0-5]|2[0-4][\\d]|[01]?[\\d][\\d]?))$',
        maxLength: 255,
        error: ['Please enter a valid email address e.g. user@domain.co.uk\n']
      },
      mobileNumber: {
        required: true,
        regex: '^07{1}\\d{9}$|^07{1}\\d{3}\\s{1}\\d{6}$|^07{1}\\d{1}\\s{1}\\d{4}\\s{1}\\d{4}$|^07{1}\\d{2}\\s{1}\\d{3}\\s{1}\\d{4}$',
        error: ['Please enter a valid mobile number with no spaces e.g. 07700900000']
      },
      businessName: {
        required: true,
        regex: '^[A-Za-z0-9\\s&@£$€¥:;,.‘\'’`´\\"()\\[\\]{}<>!«»“?/\\\\=*#%+-]{1,100}$',
        error: ['Please enter a business name']
      },
      line1: {
        required: true,
        regex: '^[\\w ()\/&.,\'-]{1,255}$',
        error: ['Please enter address line 1'],
      },
      line2: {
        required: false,
        regex: '^[\\w ()\/&.,\'-]{0,255}$',
        error: ['Please enter address line 2'],
      },
      town: {
        required: true,
        regex: '^[\\w ()\/&.,\'-]{1,255}$',
        error: ['Please enter a town/city']
      },
      postCode: {
        required: true,
        regex: '^([A-Za-z]{1,2}[0-9]{1,2}[A-Za-z]?)\\s*([0-9][A-Za-z]{2})$',
        error: ['Please enter a valid postcode']
      },
      additionalInstallationTypes: {
        required: true,
        callback: function (value, changedElemValue) {
          if (changedElemValue === 'installer_application_other_works_none_of_the_above') {
            $('[name="additionalInstallationTypes"]:not([value="installer_application_other_works_none_of_the_above"])').prop('checked', false);
          } else {
            $('[name="additionalInstallationTypes"][value="installer_application_other_works_none_of_the_above"]').prop('checked', false);
          }
        }
      },
      preferences: {
        required: false
      },
      termsAgreement: {
        required: true
      },
    },
  },
  findRequirementsByName: function (elementName) {
    var step = $('[name="'+ elementName +'"]').closest('.installer-block').attr('data-step');
    return Wick.InstallerValidation.steps[step][elementName];
  },
  getValueByName: function (elementName) {
    var element = $('[name="'+ elementName +'"]');
    var type = element.attr("type");

    if (element.prop('tagName') === 'SELECT') {
      return element.val()
    }

    switch (type) {
      case 'radio':
        return $('[name="'+ elementName +'"]:checked').val();
      case 'checkbox':
        return $('[name="'+ elementName +'"]:checked').map(function(){
          return $(this).val();
        }).get();
      case 'file':
        return element.attr('data-value');
      default:
        return element.val().trim();
    }
  },
  isInputValueNotEmpty: function (value) {
    if (typeof value === 'string') return !!value;
    if (Array.isArray(value)) return value.length > 0;

    return false;
  },
  elemDependsCheck: function (dependentValue, requirements) {
    var isValueExist = Wick.InstallerValidation.isInputValueNotEmpty(dependentValue);
    if (isValueExist) {
      if (requirements.dependsOnValue) {
        if (typeof dependentValue === 'string' || Array.isArray(dependentValue)) {
          return Wick.InstallerValidation.elemPossibleValuesCheck(dependentValue, requirements.dependsOnValue);
        } else {
          return false;
        }
      }
    } else {
      return false;
    }

    return true;
  },
  elemRequiredCheck: function (value, requirements) {
    var isValueExist = Wick.InstallerValidation.isInputValueNotEmpty(value);
    if (requirements.required && !isValueExist) {
      return false;
    }

    return true;
  },
  elemPossibleValuesCheck: function (value, possibleValues) {
    if (Array.isArray(possibleValues) && possibleValues.length > 0) {
      if (typeof value === 'string') {
        if (possibleValues && possibleValues.indexOf(value) < 0) {
          return false;
        }
      }
      if (Array.isArray(value) && value.length > 0) {
        if (possibleValues) {
          var isValid = value
            .map(function (arrayValue) { return possibleValues.indexOf(arrayValue) >= 0 })
            .some(function (result) { return !!result });

          if (!isValid) {
            return false;
          }
        }
      }
    }
    return true;
  },
  elemRegexCheck: function (value, requirements) {
    if (requirements.regex && !RegExp(requirements.regex).test(value)) {
      return false;
    }

    return true;
  },
  elemMaxLengthCheck: function (value, requirements) {
    if (typeof value === 'string' && requirements.maxLength) {
      return value.length <= requirements.maxLength;
    }

    return true;
  },
  isElementValid: function (elementName) {
    var requirements = Wick.InstallerValidation.findRequirementsByName(elementName);
    var value = Wick.InstallerValidation.getValueByName(elementName);
    var error = requirements.error;

    if (value && typeof value === 'string') {
      value = value.trim();
    }

    if (requirements.required) {
      if (requirements.dependsOnInput) {
        var dependentValue = Wick.InstallerValidation.getValueByName(requirements.dependsOnInput);
        if (dependentValue) {
          if (requirements.dependsOnValue) {
            var elemDependsCheckResult = Wick.InstallerValidation.elemDependsCheck(dependentValue, requirements);
            if (elemDependsCheckResult) {
              var result = Wick.InstallerValidation.checkElementValidations(value, requirements);
              return { valid: result.valid, errorType: result.errorType, error  };
            }
          } else {
            var result = Wick.InstallerValidation.checkElementValidations(value, requirements);
            return { valid: result.valid, errorType: result.errorType, error  };
          }
        }
      } else {
        var result = Wick.InstallerValidation.checkElementValidations(value, requirements);
        return { valid: result.valid, errorType: result.errorType, error  };
      }
    } else {
      var isValueExist = Wick.InstallerValidation.isInputValueNotEmpty(value);
      if (isValueExist) {
        var result = Wick.InstallerValidation.checkElementValidations(value, requirements);
        return { valid: result.valid, errorType: result.errorType, error  };
      }
    }

    return { valid: true, error };
  },
  checkElementValidations: function (value, requirements) {
    var elemRequiredCheckResult = Wick.InstallerValidation.elemRequiredCheck(value, requirements);
    var elemPossibleValuesCheckResult = Wick.InstallerValidation.elemPossibleValuesCheck(value, requirements.possibleValues);
    var elemRegexCheckResult = Wick.InstallerValidation.elemRegexCheck(value, requirements);
    var elemMaxLengthCheckResult = Wick.InstallerValidation.elemMaxLengthCheck(value, requirements);

    if (!elemRequiredCheckResult) return { valid: false, errorType: 'required' };
    if (!elemPossibleValuesCheckResult || !elemRegexCheckResult || !elemMaxLengthCheckResult) return { valid: false, errorType: 'validation' };

    return { valid: true };
  },
  runElementCallback: function (elementName, changedElemValue) {
    var value = Wick.InstallerValidation.getValueByName(elementName);
    var requirements = Wick.InstallerValidation.findRequirementsByName(elementName);
    if (requirements.callback) {
      requirements.callback(value, changedElemValue);
    }
  },
  checkElement: function (elementName, onChange) {
    var result = Wick.InstallerValidation.isElementValid(elementName);
    if (result.valid) {
      if (onChange) {
        Wick.InstallerValidation.removeErrorNotificationFromElement(elementName);
        Wick.InstallerValidation.removeGlobalErrorNotification();
      }
      return result;
    }

    Wick.InstallerValidation.addErrorNotificationToElement(elementName, result.error, true);

    return result;
  },
  appendErrorMessage: function (wrapper, elementName, error) {
    var notification = '<div' +
      '            data-installer-input-name="' + elementName + '"' +
      '            class="form-row__error"' +
      '          >' + error.map(function (err) { return '<p>' + err + '</p>';}).join('') +
      '          </div>';
    wrapper.append(notification);
  },
  addErrorNotificationToElement: function (elementName, error, removePrevNotification) {
    if (!error) return;
    var element = $('[name="'+ elementName +'"]');
    var wrapper = element.closest('[data-form-field]');
    var prevNotification = wrapper.children('.form-row__error[data-installer-input-name="'+ elementName +'"]');
    if (prevNotification.length === 0) {
      Wick.InstallerValidation.appendErrorMessage(wrapper, elementName, error);
    } else {
      if (removePrevNotification) {
        prevNotification.remove();
        Wick.InstallerValidation.appendErrorMessage(wrapper, elementName, error);
      }
    }
  },
  removeErrorNotificationFromElement: function (elementName) {
    var element = $('[name="'+ elementName +'"]');
    var wrapper = element.closest('[data-form-field]');
    var error = wrapper.children('.installer_question-error_wrapper[data-installer-input-name="'+ elementName +'"]');
    var formError = wrapper.find('.form-row__error[data-installer-input-name="'+ elementName +'"]');
    error.remove();
    formError.remove();
  },
  removeAllErrorsFromStep: function (step) {
    var installerBlock = $('.installer-block[data-step="'+ step +'"]');
    installerBlock.find('.form-row__error').remove();
  },
  addGlobalErrorNotification: function (step, errorTypes) {
    var wrapper = $('.installer-step-errors');
    wrapper.attr('data-step', step);
    wrapper.attr('data-step-error', '');
    errorTypes.forEach(function (type) {
      wrapper.attr(`data-error-${type}`, '');
    });
  },
  removeGlobalErrorNotification: function () {
    var wrapper = $('.installer-step-errors');
    wrapper.removeAttr('data-step-error');
    wrapper.removeAttr('data-error-required');
    wrapper.removeAttr('data-error-validation');
  },
  validateStepForInstallerForm: function (step) {
    Wick.InstallerValidation.removeAllErrorsFromStep(step);

    var inputNames = Object.keys(Wick.InstallerValidation.steps[step]);
    var results = inputNames
      .map(function (elementName) {
        return {
          name: elementName,
          result: Wick.InstallerValidation.checkElement(elementName)
        };
      });
    var isStepInvalid = results.some(function (result) { return !result.result.valid; });
    var errorTypes = results.reduce(function (prev, next) {
      var result = next.result.errorType ? { [next.result.errorType]: true } : {};
      return Object.assign(
        prev,
        result
      )
    }, {});
    errorTypes = Object.keys(errorTypes);

    if (isStepInvalid) {
      var firstErrorField = results.find(function (result) { return !result.result.valid; });
      Wick.InstallerValidation.scrollToField(firstErrorField.name);
      Wick.InstallerValidation.addGlobalErrorNotification(step, errorTypes);
    }

    return !isStepInvalid;
  },
  scrollToField: function (name) {
    var element = $('[name="'+ name +'"]:first');
    var elementHeight = element.height();
    $([document.documentElement, document.body]).animate({
      scrollTop: element.offset().top - elementHeight
    }, 1500);
  },
  validateInstallerForm: function () {
    var isStepsValid = Wick.InstallerForm.steps
      .map(function (step) { return Wick.InstallerValidation.validateStepForInstallerForm(step); })
      .every(function (result) { return !!result; });

    return isStepsValid;
  },

  bindFormTextInputs: function () {
    $('.installer-container').on({
      input: function() {
        var elementName = $(this).attr('name');
        Wick.InstallerValidation.checkElement(elementName, true);
        Wick.InstallerValidation.runElementCallback(elementName);
      },
      change: function() {
        var elementName = $(this).attr('name');
        Wick.InstallerValidation.checkElement(elementName, true);
        Wick.InstallerValidation.runElementCallback(elementName);
      },
      keydown: function(e) {
        var keyCode = e.keyCode || e.which;

        if (+keyCode === 9) {
          var elementName = $(this).attr('name');
          Wick.InstallerValidation.checkElement(elementName, true);
          Wick.InstallerValidation.runElementCallback(elementName);
        }
      }
    }, 'input[type="text"]');

    // Need to be tested on android
    $(document).on('focus', '.installer-container input[type="text"]', function(){
      var userAgent = navigator.userAgent || navigator.vendor || window.opera;
      if (/android/i.test(userAgent)) {
        var boxheight =  $(window).height() - 60;
        $('main').append("<div id='blank' style='height:"+boxheight+"px;'"+"></div>");
        $('html, body').animate({scrollTop: $(this).offset().top - 100}, 500);
      }
    });

    $(document).on('focusout', '.installer-container input[type="text"]', function(){
      var userAgent = navigator.userAgent || navigator.vendor || window.opera;
      if (/android/i.test(userAgent)) {
        $('#blank').remove();
      }
    });
  },
  bindFormCheckboxInputs: function () {
    $('.installer-container input[type="radio"], input[type="checkbox"], select').on('change', function(event) {
      var elementName = $(this).attr('name');
      var changedElemValue = $(this)[0].value;
      Wick.InstallerValidation.checkElement(elementName, true);
      Wick.InstallerValidation.runElementCallback(elementName, changedElemValue);
    });
  },
};

$(document).ready(function () {
  Wick.InstallerValidation.bindFormTextInputs();
  Wick.InstallerValidation.bindFormCheckboxInputs();
});

// Polyfills
if (!Array.prototype.some) {
  Array.prototype.some = function(fun, thisArg) {
    'use strict';

    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }

    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    for (var i = 0; i < len; i++) {
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }

    return false;
  };
}

if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}

if (!Array.prototype.every) {
  Array.prototype.every = function(callbackfn, thisArg) {
    'use strict';
    var T, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    // 1. Let O be the result of calling ToObject passing the this
    //    value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get internal method
    //    of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (typeof callbackfn !== 'function' && Object.prototype.toString.call(callbackfn) !== '[object Function]') {
      throw new TypeError();
    }

    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
    if (arguments.length > 1) {
      T = thisArg;
    }

    // 6. Let k be 0.
    k = 0;

    // 7. Repeat, while k < len
    while (k < len) {

      var kValue;

      // a. Let Pk be ToString(k).
      //   This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty internal
      //    method of O with argument Pk.
      //   This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {
        var testResult;
        // i. Let kValue be the result of calling the Get internal method
        //    of O with argument Pk.
        kValue = O[k];

        // ii. Let testResult be the result of calling the Call internal method
        // of callbackfn with T as the this value if T is not undefined
        // else is the result of calling callbackfn
        // and argument list containing kValue, k, and O.
        if(T) testResult = callbackfn.call(T, kValue, k, O);
        else testResult = callbackfn(kValue,k,O)

        // iii. If ToBoolean(testResult) is false, return false.
        if (!testResult) {
          return false;
        }
      }
      k++;
    }
    return true;
  };
}

if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, 'reduce', {
    value: function(callback /*, initialValue*/) {
      if (this === null) {
        throw new TypeError( 'Array.prototype.reduce ' +
          'called on null or undefined' );
      }
      if (typeof callback !== 'function') {
        throw new TypeError( callback +
          ' is not a function');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // Steps 3, 4, 5, 6, 7
      var k = 0;
      var value;

      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++;
        }

        // 3. If len is 0 and initialValue is not present,
        //    throw a TypeError exception.
        if (k >= len) {
          throw new TypeError( 'Reduce of empty array ' +
            'with no initial value' );
        }
        value = o[k++];
      }

      // 8. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kPresent be ? HasProperty(O, Pk).
        // c. If kPresent is true, then
        //    i.  Let kValue be ? Get(O, Pk).
        //    ii. Let accumulator be ? Call(
        //          callbackfn, undefined,
        //          « accumulator, kValue, k, O »).
        if (k in o) {
          value = callback(value, o[k], k, o);
        }

        // d. Increase k by 1.
        k++;
      }

      // 9. Return accumulator.
      return value;
    }
  });
}
