var InputMask = function ( opts ) {
  if ( opts && opts.masked ) {
    // Make it easy to wrap this plugin and pass elements instead of a selector
    opts.masked = typeof opts.masked === string ? document.querySelectorAll( opts.masked ) : opts.masked;
  }

  if ( opts ) {
    this.opts = {
      masked: opts.masked || document.querySelectorAll( this.d.masked ),
      mNum: opts.mNum || this.d.mNum,
      mChar: opts.mChar || this.d.mChar,
      error: opts.onError || this.d.onError
    }
  } else {
    this.opts = this.d;
    this.opts.masked = document.querySelectorAll( this.opts.masked );
  }

  this.refresh( true );
};

var inputMask = {

  // Default Values
  d: {
    masked : '.masked',
    mNum : 'XdDmMyY9',
    mChar : '_',
    onError: function(){}
  },

  refresh: function(init) {
    var t, parentClass;

    if ( !init ) {
      this.opts.masked = document.querySelectorAll( this.opts.masked );
    }

    for(i = 0; i < this.opts.masked.length; i++) {
      t = this.opts.masked[i]
      parentClass = t.parentNode.getAttribute('class');

      if ( !parentClass || ( parentClass && parentClass.indexOf('shell') === -1 ) ) {
        this.createShell(t);
        this.activateMasking(t);
      }
    }
  },

  // replaces each masked t with a shall containing the t and it's mask.
  createShell : function (t) {
    var wrap = document.createElement('span'),
        mask = document.createElement('span'),
        emphasis = document.createElement('i'),
        tClass = t.getAttribute('class'),
        pTxt = t.getAttribute('placeholder'),
        placeholder = document.createTextNode(pTxt);

    t.setAttribute('maxlength', placeholder.length);
    t.setAttribute('data-placeholder', pTxt);
    t.removeAttribute('placeholder');


    if ( !tClass || ( tClass && tClass.indexOf('masked') === -1 ) ) {
      t.setAttribute( 'class', tClass + ' masked');
    }

    mask.setAttribute('aria-hidden', 'true');
    mask.setAttribute('id', t.getAttribute('id') + 'Mask');
    mask.appendChild(emphasis);
    mask.appendChild(placeholder);

    wrap.setAttribute('class', 'shell');
    wrap.appendChild(mask);
    t.parentNode.insertBefore( wrap, t );
    wrap.appendChild(t);
  },

  setValueOfMask : function (e) {
    var value = e.target.value,
        placeholder = e.target.getAttribute('data-placeholder');

    return "<i>" + value + "</i>" + placeholder.substr(value.length);
  },

  // add event listeners
  activateMasking : function (t) {
    var that = this;
    if (t.addEventListener) { // remove "if" after death of IE 8
      t.addEventListener('keyup', function(e) {
        that.handleValueChange.call(that,e);
      }, false);
    } else if (t.attachEvent) { // For IE 8
        t.attachEvent('onkeyup', function(e) {
        e.target = e.srcElement;
        that.handleValueChange.call(that, e);
      });
    }
  },

  handleValueChange : function (e) {
    var id = e.target.getAttribute('id');

    if(e.target.value == document.querySelector('#' + id + 'Mask i').innerHTML) {
      return; // Continue only if value hasn't changed
    }

    document.getElementById(id).value = this.handleCurrentValue(e);
    document.getElementById(id + 'Mask').innerHTML = this.setValueOfMask(e);

  },

  handleCurrentValue : function (e) {
    var isCharsetPresent = e.target.getAttribute('data-charset'),
        placeholder = isCharsetPresent || e.target.getAttribute('data-placeholder'),
        value = e.target.value, l = placeholder.length, newValue = '',
        i, j, isInt, isLetter, strippedValue;

    // strip special characters
    strippedValue = isCharsetPresent ? value.replace(/\W/g, "") : value.replace(/\D/g, "");

    for (i = 0, j = 0; i < l; i++) {
        isInt = !isNaN(parseInt(strippedValue[j]));
        isLetter = strippedValue[j] ? strippedValue[j].match(/[A-Z]/i) : false;
        matchesNumber = this.opts.mNum.indexOf(placeholder[i]) >= 0;
        matchesLetter = this.opts.mChar.indexOf(placeholder[i]) >= 0;
        if ((matchesNumber && isInt) || (isCharsetPresent && matchesLetter && isLetter)) {
                newValue += strippedValue[j++];
          } else if ((!isCharsetPresent && !isInt && matchesNumber) || (isCharsetPresent && ((matchesLetter && !isLetter) || (matchesNumber && !isInt)))) {
                //this.opts.onError( e ); // write your own error handling function
                return newValue;
        } else {
            newValue += placeholder[i];
        }
        // break if no characters left and the pattern is non-special character
        if (strippedValue[j] == undefined) {
          break;
        }
    }
    if (e.target.getAttribute('data-valid-example')) {
      return this.validateProgress(e, newValue);
    }
    return newValue;
  },

  validateProgress : function (e, value) {
    var validExample = e.target.getAttribute('data-valid-example'),
        pattern = new RegExp(e.target.getAttribute('pattern')),
        placeholder = e.target.getAttribute('data-placeholder'),
        l = value.length, testValue = '';

    //convert to months
    if (l == 1 && placeholder.toUpperCase().substr(0,2) == 'MM') {
      if(value > 1 && value < 10) {
        value = '0' + value;
      }
      return value;
    }
    // test the value, removing the last character, until what you have is a submatch
    for ( i = l; i >= 0; i--) {
      testValue = value + validExample.substr(value.length);
      if (pattern.test(testValue)) {
        return value;
      } else {
        value = value.substr(0, value.length-1);
      }
    }

    return value;
  }
};

for ( var property in inputMask ) {
  if (inputMask.hasOwnProperty(property)) {
    InputMask.prototype[ property ] = inputMask[ property ];
  }
}

//  Declaritive initalization
(function(){
  var scripts = document.getElementsByTagName('script'),
      script = scripts[ scripts.length - 1 ];
  if ( script.getAttribute('data-autoinit') ) {
    new InputMask();
  }
})();

export default InputMask;
