var fi_currentValue;
function fi_doFormat(input)
{
	var cursorPosition = fi_getCaretPosition(input);
	var valueBefore = input.value;
	var lengthBefore = input.value.length;
  	var specialCharsBefore = fi_getSpecialCharsOnSides(input.value);
  	var number = fi_removeThousandSeparators(input.value);

  	if (input.value == '') {
		fi_currentValue="";
  		return;
  	}
  
  	input.value = fi_formatNumber(number.replace(fi_getCommaSeparator(), '.'));

	// if deleting the comma, delete it correctly
  if (fi_currentValue == input.value && fi_currentValue == valueBefore.substr(0, cursorPosition) + fi_getThousandSeparator() + valueBefore.substr(cursorPosition)) {
  	input.value = fi_formatNumber(fi_removeThousandSeparators(valueBefore.substr(0, cursorPosition-1) + valueBefore.substr(cursorPosition)));
    cursorPosition--;
  }
  
  // if entering comma for separation, leave it in there (as well support .000)
  var commaSeparator = fi_getCommaSeparator();
	if (valueBefore.endsWith(commaSeparator) || valueBefore.endsWith(commaSeparator+'0') || valueBefore.endsWith(commaSeparator+'00') || valueBefore.endsWith(commaSeparator+'000')) {
  	input.value = input.value + valueBefore.substring(valueBefore.indexOf(commaSeparator));
  }

  // move cursor correctly if thousand separator got added or removed
  var specialCharsAfter = fi_getSpecialCharsOnSides(input.value);
  if (specialCharsBefore[0] < specialCharsAfter[0]) {
		cursorPosition += specialCharsAfter[0] - specialCharsBefore[0];
  } else if (specialCharsBefore[0] > specialCharsAfter[0]) {
		cursorPosition -= specialCharsBefore[0] - specialCharsAfter[0];
  }
  fi_setCaretPosition(input, cursorPosition);
  
  fi_currentValue = input.value;
}

function fi_getSpecialCharsOnSides(x, cursorPosition) {
	var specialCharsLeft = x.substring(0, cursorPosition).replace(/[0-9]/g, '').length;
  var specialCharsRight = x.substring(cursorPosition).replace(/[0-9]/g, '').length;
  return [specialCharsLeft, specialCharsRight]
}

function fi_formatNumber(x) {
   return fi_getNumberFormat().format(x);
}

function fi_removeThousandSeparators(x) {
  return x.toString().replace(new RegExp(fi_escapeRegExp(fi_getThousandSeparator()), 'g'), "");
}

function fi_getThousandSeparator() {
  return fi_getNumberFormat().format('1000').replace(/[0-9]/g, '')[0];
}

function fi_getCommaSeparator() {
  return fi_getNumberFormat().format('0.01').replace(/[0-9]/g, '')[0];
}

function fi_getNumberFormat() {
	return new Intl.NumberFormat(['ban', 'id']);
}

/* From: http://stackoverflow.com/a/6969486/496992 */
function fi_escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

/*
** Returns the caret (cursor) position of the specified text field.
** Return value range is 0-oField.value.length.
** From: http://stackoverflow.com/a/2897229/496992
*/
function fi_getCaretPosition (oField) {
  // Initialize
  var iCaretPos = 0;

  // IE Support
  if (document.selection) {

    // Set focus on the element
    oField.focus();

    // To get cursor position, get empty selection range
    var oSel = document.selection.createRange();

    // Move selection start to 0 position
    oSel.moveStart('character', -oField.value.length);

    // The caret position is selection length
    iCaretPos = oSel.text.length;
  }

  // Firefox support
  else if (oField.selectionStart || oField.selectionStart == '0')
    iCaretPos = oField.selectionStart;

  // Return results
  return iCaretPos;
}

/* From: http://stackoverflow.com/a/512542/496992 */
function fi_setCaretPosition(elem, caretPos) {
    if(elem != null) {
        if(elem.createTextRange) {
            var range = elem.createTextRange();
            range.move('character', caretPos);
            range.select();
        }
        else {
            if(elem.selectionStart) {
                elem.focus();
                elem.setSelectionRange(caretPos, caretPos);
            }
            else
                elem.focus();
        }
    }
}