var digits = "0123456789";

var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"

var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

// whitespace characters
var whitespace = " \t\n\r";

// decimal point character differs by language and culture
var decimalPointDelimiter = ","

// CONSTANT STRING DECLARATIONS
// (grouped for ease of translation and localization)

var daysInMonth = new Array(12);
daysInMonth[1] = 31;
daysInMonth[2] = 29;   // must programmatically check this
daysInMonth[3] = 31;
daysInMonth[4] = 30;
daysInMonth[5] = 31;
daysInMonth[6] = 30;
daysInMonth[7] = 31;
daysInMonth[8] = 31;
daysInMonth[9] = 30;
daysInMonth[10] = 31;
daysInMonth[11] = 30;
daysInMonth[12] = 31;


// Check whether string s is empty.

function isEmpty(s)
{
	return (s == null || s.length == 0)
}


// Returns true if string s is empty or
// whitespace characters only.

function isWhitespace (s)
{

    // Is s empty?
    if (isEmpty(s)) return true;

    // Search through string's characters one by one
    // until we find a non-whitespace character.
    // When we do, return false; if we don't, return true.

    for (var i = 0; i < s.length; i++)
    {
        // Check that current character isn't whitespace.
        var c = s.charAt(i);

        if (whitespace.indexOf(c) == -1) return false;
    }

    // All characters are whitespace.
    return true;
}


// Returns true if character c is an English letter
// (A .. Z, a..z).
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.

function isLetter (c)
{   return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) )
}


// Returns true if character c is a digit
// (0 .. 9).

function isDigit (c)
{   return ((c >= "0") && (c <= "9"))
}


// Returns true if character c is a letter or digit.

function isLetterOrDigit (c)
{   return (isLetter(c) || isDigit(c))
}


// isInteger (STRING s)
//
// Returns true if all characters in string s are numbers.
//
// Accepts non-signed integers only. Does not accept floating
// point, exponential notation, etc.

function isInteger (s)
{

    if (isEmpty(s)) return false;

    // Search through string's characters one by one
    // until we find a non-numeric character.
    // When we do, return false; if we don't, return true.

    for (var i = 0; i < s.length; i++)
    {
        // Check that current character is number.
        var c = s.charAt(i);

        if (!isDigit(c)) return false;
    }

    // All characters are numbers.
    return true;
}


// isSignedInteger (STRING s)
//
// Returns true if all characters are numbers;
// first character is allowed to be + or - as well.
//
// Does not accept floating point, exponential notation, etc.

function isSignedInteger (s)
{
    if (isEmpty(s)) return false;

    else {
        var startPos = 0;

        // skip leading + or -
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;
        return (isInteger(s.substring(startPos, s.length)))
    }
}


// isPositiveInteger (STRING s)
//
// Returns true if string s is an integer > 0.

function isPositiveInteger (s)
{
    if (isEmpty(s)) return false;

    return (isSignedInteger(s) && Number (s) > 0);
}


// isNonnegativeInteger (STRING s)
//
// Returns true if string s is an integer >= 0.

function isNonnegativeInteger (s)
{
    if (isEmpty(s)) return false;

    return (isSignedInteger(s) && Number (s)>=0);
}


// isNegativeInteger (STRING s)
//
// Returns true if string s is an integer < 0.

function isNegativeInteger (s)
{
    if (isEmpty(s)) return false;

    return (isSignedInteger(s) && Number(s)<0);
}


// isNonpositiveInteger (STRING s)
//
// Returns true if string s is an integer <= 0.

function isNonpositiveInteger (s)
{
    if (isEmpty(s)) return false;

    return (isSignedInteger(s) && Number(s)<=0);
}


// isFloat (STRING s)
//
// True if string s is an unsigned floating point (real) number.
//
// Also returns true for unsigned integers. If you wish
// to distinguish between integers and floating point numbers,
// first call isInteger, then call isFloat.
//
// Does not accept exponential notation.

function isFloat (s)

{
    var seenDecimalPoint = false;

    if (isEmpty(s)) return false;

    if (s == decimalPointDelimiter) return false;

    // Search through string's characters one by one
    // until we find a non-numeric character.
    // When we do, return false; if we don't, return true.

    for (var i = 0; i < s.length; i++)
    {
        // Check that current character is number.
        var c = s.charAt(i);

        if ((c == decimalPointDelimiter) && !seenDecimalPoint) seenDecimalPoint = true;
        else if (!isDigit(c)) return false;
    }

    // All characters are numbers.
    return true;
}


// isSignedFloat (STRING s)
//
// True if string s is a signed or unsigned floating point
// (real) number. First character is allowed to be + or -.
//
// Also returns true for unsigned integers. If you wish
// to distinguish between integers and floating point numbers,
// first call isSignedInteger, then call isSignedFloat.
//
// Does not accept exponential notation.

function isSignedFloat (s)
{
    if (isEmpty(s)) return false;

    else {
        var startPos = 0;

        // skip leading + or -
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;
        return (isFloat(s.substring(startPos, s.length)))
    }
}


// isAlphabetic (STRING s)
//
// Returns true if string s is English letters
// (A .. Z, a..z) only.

function isAlphabetic (s)
{

    if (isEmpty(s)) return false;

    // Search through string's characters one by one
    // until we find a non-alphabetic character.
    // When we do, return false; if we don't, return true.

    for (var i = 0; i < s.length; i++)
    {
        // Check that current character is letter.
        var c = s.charAt(i);

        if (!isLetter(c))
        return false;
    }

    // All characters are letters.
    return true;
}


// isAlphanumeric (STRING s)
//
// Returns true if string s is English letters
// (A .. Z, a..z) and numbers only.

function isAlphanumeric (s)
{

    if (isEmpty(s)) return false;

    // Search through string's characters one by one
    // until we find a non-alphanumeric character.
    // When we do, return false; if we don't, return true.

    for (var i = 0; i < s.length; i++)
    {
        // Check that current character is number or letter.
        var c = s.charAt(i);

        if (! (isLetter(c) || isDigit(c) ) )
        return false;
    }

    // All characters are numbers or letters.
    return true;
}


// isYear (STRING s)
//
// isYear returns true if string s is a valid
// Year number.  Must be 4 digits only.

function isYear (s)
{
	if (isEmpty(s)) return false;
    if (!isPositiveInteger(s)) return false;
    return (s.length==4);
}


// isIntegerInRange (STRING s, INTEGER a, INTEGER b)
//
// isIntegerInRange returns true if string s is an integer
// within the range of integer arguments a and b, inclusive.

function isIntegerInRange (s, a, b)
{
    if (isEmpty(s)) return false;

    // Catch non-integer strings to avoid creating a NaN below,
    // which isn't available on JavaScript 1.0 for Windows.
    if (!isInteger(s)) return false;

    // Now, explicitly change the type to integer via Number
    // so that the comparison code below will work both on
    // JavaScript 1.2 (which typechecks in equality comparisons)
    // and JavaScript 1.1 and before (which doesn't).
    var num = Number (s);
    return ((num >= a) && (num <= b));
}


// isMonth (STRING s)
//
// isMonth returns true if string s is a valid
// month number between 1 and 12.

function isMonth (s)
{
    if (isEmpty(s)) return false;
    return isIntegerInRange (Number(s), 1, 12);
}


// isDay (STRING s)
//
// isDay returns true if string s is a valid
// day number between 1 and 31.

function isDay (s)
{
    if (isEmpty(s)) return false;
    return isIntegerInRange (Number(s), 1, 31);
}


// daysInFebruary (INTEGER year)
//
// Given integer argument year,
// returns number of days in February of that year.

function daysInFebruary (year)
{   // February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (  ((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) ) ) ? 29 : 28 );
}


// isDate (STRING)
//
// isDate returns true if string argument forms a valid date (yyyy-mm-dd).

function isLeapYear (year) {
	return ((year % 400 == 0) || ((year % 4 == 0)&&(year % 100 != 0)));
}


// isDate (STRING)
function isDate (day, month, year)
{	
	if (month < 1 || month > 12) return false;

	var max = daysInMonth[month];
	if (month == 2)
	{
		if (isLeapYear(year))
		{
			max = 29;
		}
		else
		{
			max=28;
		}
	};

	if (day < 1 || day > max) return false;

	return true;
}


// isHour (STRING s)
//
// isHour returns true if string s is a valid
// hour number between 0 and 23.

function isHour (s) {
    if (isEmpty(s)) return false;
    return isIntegerInRange (s, 0, 23);
}

// isMinuteSecond (STRING s)
//
// isMinuteSecond returns true if string s is a valid
// minute or second number between 0 and 59.

function isMinuteSecond (s) {
    if (isEmpty(s)) return false;
    return isIntegerInRange (s, 0, 59);
}

// isTime (STRING)
//
// isTime returns true if string argument forms a valid time (HH:mm:ss).

function isTime (s)
{
	var time = s.split(':');

	if (time.length != 3)	return false;

	if (! (isHour(time[0]) && isMinuteSecond(time[1]) && isMinuteSecond(time[2]))) return false;

  return true;
}

function parseDate (s)
{
	if (!isDate(s))
		return null;

	var date = s.split('-');
	return new Date(Number(date[0]),Number(date[1])-1,Number(date[2]));
}

function isEmptyDate (date) {
	if (date == null) return true;
	date = date.substring(0,4) + date.substring(5,7) + date.substring(8,10);
	return date == '';
}

function isCodigoPostal (codPostal) {
	if (!codPostal.match(/^[0-9]{4,4}-[0-9]{3,3}$/)) return false;
	return true;
}

function isParte (parte) {
	if (!parte.match(/^[0-9]+\/[0-9]+$/)) return false;
	return true;
}

function isPermilagem (permil) {
	return isEuros(permil); // a formatação da permilagem é parecida à do euro
}

// ATENÇÃO: aceita 2 números depois do T, tal como T00
// retirada a possibilidade de ser p.ex T0+1
function isTipologia (tipologia) {
	if (tipologia.match(/^([Tt][0-9]{1,3}|[0-9]{1,4})$/)) return true;
//	if (tipologia.match(/^([Tt][0-9]{1,2}(\+[1-9])?|[1-9][0-9]{0,3})$/)) return true;
	return false;
}

function getRepeatedChar (c, size) {
	var str = "";
	for (var i = 0; i < size; i++) {
		str += c;
	}
	return str;
}

function getZeroString (size) {
	return getRepeatedChar('0', size);
}

function formatCasasDecimais (valor, casasDecimais) {
	valor = valor;
	var valorSize = isEmpty(valor) ? 0 : valor.length;
	var empty = getZeroString(casasDecimais - valorSize);
	return isEmpty(valor) ? empty : valor + empty;
}

// formatDecimal (STRING separator, STRING decimal, INTEGER inteiroSize, INTEGER precisao)
//
// formatDecimal returns decimal formatado

function formatDecimal (separador, valor, casasInteiras, casasDecimais) 
{
	if (isEmpty(valor)) return valor;
	if (isDecimal(separador, valor, casasInteiras, casasDecimais)) return valor;

	valor = valor;
	var pos = valor.indexOf(separador);
	if (pos == -1) return valor + separador + formatCasasDecimais("", casasDecimais);

	var inteiro = valor.substring(0, pos);
	var centimos = valor.substring(pos+1);
	return inteiro + separador + formatCasasDecimais(centimos, casasDecimais);
}

function isDecimal (separador, valor, casasInteiras, casasDecimais) {
	if (isEmpty(valor)) return false;
	var pattern = "[[0-9]{1,"+casasInteiras+"}"+separador+"[0-9]{"+casasDecimais+"}";

	return valor.match(pattern) == valor;
}

function isFormatableDecimal (separador, valor, casasInteiras, casasDecimais) {
	if (isEmpty(valor)) return false;
	var formated = formatDecimal(separador, valor, casasInteiras, casasDecimais);
	return isDecimal(separador, formated, casasInteiras, casasDecimais);
}


function isEuros (text) {
	if (text.length < 4) return false;
	var sep = text.charAt(text.length-3);
	if (sep != ',' && sep != '.') return false;
	var centims = text.substring(text.length - 2);
	if (!centims.match(/^\d\d$/)) return false;
	var euro = text.substring(0, text.length - 3);
	if (!euro.match(/^[0-9\,\.]+$/)) return false;
	return euro.replace(/\,/g,'.') == formatThousands(euro);
}

function formatEuros (text) {
	if (text.length == 0) return text;
	var pos = Math.max(text.lastIndexOf(','), text.lastIndexOf('.'));
	var centims = pos == -1 || pos == text.length - 1 ? '00' : text.substring(pos+1);
	if (centims.length == 1) centims = centims + '0';
	if (centims.length > 2) centims = String(Math.round(Number(centims.substring(0,2)+'.'+centims.substring(2))));
	var euro = pos == -1 ? text : euro = text.substring(0,pos);
	return formatThousands(euro)+','+centims;
}

function formatThousands (text) {
	text = text.replace(/\D/g,'');
	if (text.length <= 3) return text;
	var mod = (text.length - 1) % 3;
	if (mod == 0) return text.charAt(0) + '.' + formatThousands(text.substring(1));
	return text.charAt(0) + formatThousands(text.substring(1));
}

function getEuroCents (text) {
	if (text.length == 0) return text;
	return Number(text.replace(/\D/g,''));
}

function isSF(s) {
	return (s.length==4 && isPositiveInteger(s));
}

function isNumeroContribuinte(s) {

	if (s.length!=9 || !isPositiveInteger(s)) 
	{
		return false;
	}

	var soma,resto,digi;
    	var nif = new Array(9);
  	for (var i=0;i<9;i++) {
    	nif[i] = Number(s.substring(i,i+1));
  	}
  	for (var i=0,soma=0;i<8;i++) {
    	soma += nif[i]*(9-i);
  	}
  	resto = soma%11;
  	digi = 11-resto;
  	if (digi>9) digi=0;
  	return (digi==nif[8]);

}

function isNumeroContribuinteColectivo(s) {
	if (!isNumeroContribuinte(s)) return false;
  	if ((s.charAt(0)!='5')&&(s.charAt(0)!='6')&&(s.charAt(0)!='7')&&(s.charAt(0)!='9')) return false;
  	return true;
}

function isNumeroContribuinteSingular(s) {
	if (!isNumeroContribuinte(s)) return false;
  	if ((s.charAt(0)!='1')&&(s.charAt(0)!='2')&&(s.charAt(0)!='3')&&(s.charAt(0)!='4')) return false;
  	return true;
}

function isNumeroContribuinteNaoResidente(s) {
	if (!isNumeroContribuinte(s)) return false;
  	if ((s.charAt(0)!='9')||(s.charAt(1)!='8')) return false;
  	return true;
}


/* FUNCTIONS TO NOTIFY USER OF INPUT REQUIREMENTS OR MISTAKES. */


// Notify user that required field theField is empty.
// String s describes expected contents of theField.value.
// Put focus in theField and return false.

function warnEmpty (theField, s)
{
	alert(s);
	if (!theField.disabled && String(theField.type)!='hidden' && String(theField.type)!='undefined') {
		theField.focus();
	}
    return false;
}


// Notify user that contents of field theField are invalid.
// String s describes expected contents of theField.value.
// Put select theField, put focus in it, and return false.

function warnInvalid (theField, s)
{
   	alert(s);
	if (!theField.disabled && String(theField.type)!='hidden' && String(theField.type)!='undefined') 
	{
		theField.focus();
    		theField.select();
	}
	return false;
}

function asArray(obj) {
    var array = null;
    if (isFormField(obj)) {
        array = new Array(1);
        array[0] = obj;
    } else {
        array = obj;
    }
    return array;
}

function isFormField(obj) {
    return (typeof obj.name != 'undefined');
}

function setSelected (field, value) {
	for (var i = 0; i < field.options.length; i++) {
		var opt = field.options[i];
		if (opt.value == value) {
			opt.selected = true;
			break;
		}
	}
	if (field.options[0].length > 0) field.options[0].selected = true;
}

function isTelefone (value) 
{
	if (value == '') return true;
	if (value.length != 9) return false;
	if (!isPositiveInteger(value)) return false;
	var ch = value.charAt(0);
	//fixos e telemoveis
	if (ch != '2' && ch != '9') return false;
	return true;
}



function isEmail(s) 
{	
	if (isEmpty(s)) {return true;};

	if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(s)) {return (true);};
	
	return (false);
}


function ForceEntry(oField, strAlert)
{
	//if (!oField) {return false;};
	var strFieldValue = new String(oField.value);
	
	if (isWhitespace(strFieldValue)) 
	{
		return warnInvalid(oField, strAlert);
	}
	return true;
}

function ForceContribuinte (oField, strAlert) 
{
	var strFieldValue = new String(oField.value);
	
	if (isWhitespace(strFieldValue)) {return true;};

	if (!isNumeroContribuinte(strFieldValue)) 
	{
		return warnInvalid(oField, strAlert);
	}


	return true;
}


function ForceTelefone (oField) 
{
	var strFieldValue = new String(oField.value);
	
	if (isWhitespace(strFieldValue)) {return true;};

	if (!isTelefone(strFieldValue)) 
	{
		return warnInvalid(oField, "O Telefone indicado é inválido");
	}
	return true;
}


function ForceRange(oField, min, max, strAlert) 
{

	var strFieldValue = oField.value;

	if (isWhitespace(strFieldValue)) {return true;};

	if (eval(strFieldValue) < min || eval(strFieldValue) > max) 
	{
   		return warnInvalid(oField, strAlert);
	}
	return true;
}

function ForceMaxLength (oField, intMaxLength, strAlert)
{
	//if (!oField) {return false;};
	var strFieldValue = new String(oField.value);
	
	if (isWhitespace(strFieldValue)) {return true;};
	
	var intTam = strFieldValue.length
	if (eval(intTam) > eval(intMaxLength))
	{
		return warnInvalid(oField, strAlert);
	}
	
	return true;
}

function ForceEmail(oField, strAlert)
{

	//if (!oField) {return false;};
	var strFieldValue = new String(oField.value);

	if (isWhitespace(strFieldValue)) {return true;};
	
	if (!isEmail(strFieldValue)) 
	{
		return warnInvalid(oField, strAlert);
	}
	
	return true;
}


function ForceDate(oField)
{

	//if (!oField) {return false;};
	var strFieldValue = new String(oField.value);

	if (isWhitespace(strFieldValue)) {return true;};

	var res= /^(\d{1,2})[-]{1}(\d{1,2})[-]{1}(\d{4})$/.test(strFieldValue);

	//1.Valida para o formato DD/MM/YYYY	
	if (!res)
	{
		return warnInvalid(oField, 'Escreva uma data no formato "dd-mm-yyyy"!');
	};
	
	
	//2.Valida os valores da data individualmente
	var intFirstSep = strFieldValue.indexOf('-');
	var intLastSep = strFieldValue.lastIndexOf('-');
	var strDay = strFieldValue.substring(0,intFirstSep);
	var strMonth = strFieldValue.substring(intFirstSep + 1, intLastSep);
	var strYear = strFieldValue.substring(intLastSep + 1);

	if (!isDay(strDay)){return warnInvalid(oField, 'Indique um dia com um valor v\xE1lido!');};
	if (!isMonth(strMonth)){return warnInvalid(oField, 'Indique um m\xEAs com um valor v\xE1lido!');};
	if (!isYear(strYear)){return warnInvalid(oField, 'Indique um ano com um valor v\xE1lido!');};


	//3.Valida o valor da data para o mês em questão
 	if (!isDate(strDay, strMonth, strYear))
	{
		return warnInvalid(oField, 'Indique um dia com um valor v\xE1lido para o respectivo m\xEAs e ano!');
	}
	
	return true;
}


