var kNoCanonicalCounterpart = 0;
var kCapitalLetter = 0;
var kSmallLetter = 1;
var kDigit = 2;
var kPunctuation = 3;
var kAlpha =  4;
var kCanonicalizeLettersOnly = true;
var kCananicalizeEverything = false;
var gDebugOutput = null;
var kDebugTraceLevelNone = 0;
var kDebugTraceLevelSuperDetail = 120;
var kDebugTraceLevelRealDetail = 100;
var kDebugTraceLevelAll = 80;
var kDebugTraceLevelMost = 60;
var kDebugTraceLevelFew = 40;
var kDebugTraceLevelRare = 20;
var gDebugTraceLevel = kDebugTraceLevelNone;

function DebugPrint(){
	var string = "";
	if (gDebugTraceLevel && gDebugOutput && DebugPrint.arguments && (DebugPrint.arguments.length > 1) && (DebugPrint.arguments[0] <= gDebugTraceLevel)){
		for(var index = 1; index < DebugPrint.arguments.length; index++){
			string += DebugPrint.arguments[index] + " ";
		}

	string += "<br>\n";
	gDebugOutput(string);
	}
}

function CSimilarityMap(){
	this.m_elements = "";
	this.m_canonicalCounterparts = "";
}

function SimilarityMap_Add(element, canonicalCounterpart){
	this.m_elements += element;
	this.m_canonicalCounterparts += canonicalCounterpart;
}

function SimilarityMap_Lookup(element){
	var canonicalCounterpart = kNoCanonicalCounterpart;
	var index = this.m_elements.indexOf(element);
	if (index >= 0){
		canonicalCounterpart = this.m_canonicalCounterparts.charAt(index);
	}
	else{
	}
	return canonicalCounterpart;
}

function SimilarityMap_GetCount(){
	return this.m_elements.length;
}

CSimilarityMap.prototype.Add = SimilarityMap_Add;
CSimilarityMap.prototype.Lookup = SimilarityMap_Lookup;
CSimilarityMap.prototype.GetCount = SimilarityMap_GetCount;

function CDictionaryEntry(length, wordList){
	this.m_length = length;
	this.m_wordList = wordList;
}

function DictionaryEntry_Lookup(strWord){
	var fFound = false;
	if (strWord.length == this.m_length){
		var nFirst = 0;
		var nLast = this.m_wordList.length - 1;
		while( nFirst <= nLast ){
			var nCurrent = Math.floor((nFirst + nLast)/2);
			if( strWord == this.m_wordList[nCurrent]){
				fFound = true;
				break;
			}
			else if ( strWord > this.m_wordList[nCurrent]){
				nLast = nCurrent - 1;
			}
			else{
				nFirst = nCurrent + 1;
			}
		}
	}

	return fFound;
}

CDictionaryEntry.prototype.Lookup = DictionaryEntry_Lookup;

function CDictionary(){
	this.m_entries = new Array()
	}

function Dictionary_Lookup(strWord){
	for (var index = 0; index < this.m_entries.length; index++){
		if (this.m_entries[index].Lookup(strWord)){
			return true;
		}
	}
}

function Dictionary_Add(length, wordList){
	var iL=this.m_entries.length;
	var cD=new CDictionaryEntry(length, wordList)
	this.m_entries[iL]=cD;
}

CDictionary.prototype.Lookup = Dictionary_Lookup;
CDictionary.prototype.Add = Dictionary_Add;
var gSimilarityMap = new CSimilarityMap();
var gDictionary = new CDictionary();

//Daqui pra baixo tudo é usado
function CharacterSetChecks(type, fResult){
	this.type = type;
	this.fResult = fResult;
}

function isctype(character, type, nDebugLevel){
	var fResult = false;
	switch(type){
		case kCapitalLetter:
		if((character >= 'A') && (character <= 'Z')){
			fResult = true;
		}
		break;
		case kSmallLetter:
		if ((character >= 'a') && (character <= 'z')){
			fResult = true;
		}
		break;
		case kDigit:
		if ((character >= '0') && (character <= '9')){
			fResult = true;
		}
		break;
		case kPunctuation:
		if ("!@#$%^&*()_+-='\";:[{]}\|.>,</?`~".indexOf(character) >= 0){
			fResult = true;
		}
		break;
		case kAlpha:
		if (isctype(character, kCapitalLetter) || isctype(character, kSmallLetter)){
			fResult = true;
		}
		break;
		default:
		break;
	}
	return fResult;
}

function CanonicalizeWord(strWord, similarityMap, fLettersOnly){
	var canonicalCounterpart = kNoCanonicalCounterpart;
	var strCanonicalizedWord = "";
	var nStringLength = 0;
	if ((strWord != null) && (strWord.length > 0)){
		strCanonicalizedWord = strWord;
		strCanonicalizedWord = strCanonicalizedWord.toLowerCase();
		if (similarityMap.GetCount() > 0){
			nStringLength = strCanonicalizedWord.length;
			for(var index = 0; index < nStringLength; index++){
				if (fLettersOnly && !isctype(strCanonicalizedWord.charAt(index), kSmallLetter, kDebugTraceLevelSuperDetail)){
					continue;
				}
				canonicalCounterpart = similarityMap.Lookup(strCanonicalizedWord.charAt(index));
				if (canonicalCounterpart != kNoCanonicalCounterpart){
					strCanonicalizedWord = strCanonicalizedWord.substring(0, index) + canonicalCounterpart +
					strCanonicalizedWord.substring(index + 1, nStringLength);
				}
			}
		}
	}
	return strCanonicalizedWord;
}

function IsLongEnough(strWord, nAtLeastThisLong){
	if ((strWord == null) || isNaN(nAtLeastThisLong)){
		return false;
	}
	else if (strWord.length < nAtLeastThisLong){
		return false;
	}
	return true;
}

function SpansEnoughCharacterSets(strWord, nAtLeastThisMany){
	var nCharSets = 0;
	var characterSetChecks = new Array(
	new CharacterSetChecks(kCapitalLetter, false),
	new CharacterSetChecks(kSmallLetter, false),
	new CharacterSetChecks(kDigit, false),
	new CharacterSetChecks(kPunctuation, false)
	);
	if ((strWord == null) || isNaN(nAtLeastThisMany)){
		return false;
	}
	for(var index = 0; index < strWord.length; index++){
		for(var nCharSet = 0; nCharSet < characterSetChecks.length;nCharSet++){
			if (!characterSetChecks[nCharSet].fResult && isctype(strWord.charAt(index), characterSetChecks[nCharSet].type, kDebugTraceLevelAll)){
				characterSetChecks[nCharSet].fResult = true;
				break;
			}
		}
	}
	for(var nCharSet = 0; nCharSet < characterSetChecks.length;nCharSet++){
		if (characterSetChecks[nCharSet].fResult){
			nCharSets++;
		}	
	}
	if (nCharSets < nAtLeastThisMany){
		return false;
	}
	return true;
}

function FoundInDictionary(strWord, similarityMap, dictionary){
	var strCanonicalizedWord = "";
	if((strWord == null) || (similarityMap == null) || (dictionary == null)){
		return true;
	}
	strCanonicalizedWord = CanonicalizeWord(strWord, similarityMap, kCanonicalizeLettersOnly);
	if (dictionary.Lookup(strCanonicalizedWord)){
		return true;
	}
	return false;
}

function IsCloseVariationOfAWordInDictionary(strWord, threshold, similarityMap, dictionary){
	var strCanonicalizedWord = "";
	var nMinimumMeaningfulMatchLength = 0;
	if((strWord == null) || isNaN(threshold) || (similarityMap == null) || (dictionary == null)){
		return true;
	}
	strCanonicalizedWord = CanonicalizeWord(strWord, similarityMap, kCananicalizeEverything);
	nMinimumMeaningfulMatchLength = Math.floor((threshold) * strCanonicalizedWord.length);
	for (var nSubStringLength = strCanonicalizedWord.length; nSubStringLength >= nMinimumMeaningfulMatchLength; nSubStringLength--){
		for(var nSubStringStart = 0; (nSubStringStart + nMinimumMeaningfulMatchLength) < strCanonicalizedWord.length; nSubStringStart++){
			var strSubWord = strCanonicalizedWord.substr(nSubStringStart, nSubStringLength);
			if (dictionary.Lookup(strSubWord)){
				return true;
			}
		}
	}
	return false;
}

function ClientSideStrongPassword(){
	return (IsLongEnough(ClientSideStrongPassword.arguments[0], "8") && SpansEnoughCharacterSets(ClientSideStrongPassword.arguments[0], "3") && (!(IsCloseVariationOfAWordInDictionary(ClientSideStrongPassword.arguments[0], "0.6", ClientSideStrongPassword.arguments[1], ClientSideStrongPassword.arguments[2]))));
}

function ClientSideMediumPassword(){
	return (IsLongEnough(ClientSideMediumPassword.arguments[0], "8") && SpansEnoughCharacterSets(ClientSideMediumPassword.arguments[0], "2") && (!(FoundInDictionary(ClientSideMediumPassword.arguments[0], ClientSideMediumPassword.arguments[1], ClientSideMediumPassword.arguments[2]))));
}

function ClientSideWeakPassword(){
	return (IsLongEnough(ClientSideWeakPassword.arguments[0], "1") || (!(IsLongEnough(ClientSideWeakPassword.arguments[0], "0"))));
}

function GEId(sID){
	return document.getElementById(sID);
}

function EvalPwdStrength(sP){
	
	if(ClientSideStrongPassword(sP,gSimilarityMap,gDictionary)){
		
		DispPwdStrength(3,'pwdChkCon3');
	}
	else if(ClientSideMediumPassword(sP,gSimilarityMap,gDictionary)){
		
		DispPwdStrength(2,'pwdChkCon2');
	}
	else if(ClientSideWeakPassword(sP,gSimilarityMap,gDictionary)){
		
		DispPwdStrength(1,'pwdChkCon1');
	}
	else{
		DispPwdStrength(0,'pwdChkCon0');
	}
}

function DispPwdStrength(iN,sHL)
{ 
	var sHCR="pwdChkCon0";

	for(var i=1;i<4;i++)
	{		
		if(i==iN)
		{ 
			sHCR=sHL;
		}
		else
		{
			sHCR="pwdChkCon0";
		}
		
		GEId("idSM"+i).className = sHCR;
	}
}