﻿// function to format a string
// e. g.
// Format("20060220", "####-##-##");
// On screen: 2006-02-20
// Format("4210,3352", "### ### ##0.00 kr");
// On screen: 4 210,34 kr

formatMath = new FormatMath();
formatClass = new FormatClass();

// The heart of Format, the "public" method. Doesn't cut as default, right to left as default
function Format(sSrc, sFormat)
{
	Format(sSrc, sFormat, false, false);
}

// The heart of Format, the "public" method. Right to left as default
function Format(sSrc, sFormat, bCut)
{
	Format(sSrc, sFormat, bCut, false);
}

// The heart of Format, the "public" method
function Format(sSrc, sFormat, bCut, bLeftToRight)
{
	var sNewSrc = formatClass.CleanInputString(sSrc); // Clean the input string from wierd signs that we dont bother about anyway
	var iFormatIndex = sFormat.indexOf('.'); // The decimal position on the format string if there is one
	var iSourceIndex = sNewSrc.indexOf('.'); // The decimal position on the source string if there is one
	var sDecResult = "";
	var sResult = "";

	if ( iSourceIndex < 0 ) iSourceIndex = sNewSrc.length;
	if ( iFormatIndex < 0 )
	{
		iFormatIndex = sFormat.length;
	}
	else
	{
		// if not the comma is the last in the format
		if ( sFormat.length > iFormatIndex + 1 )
		{
			// if there is a required field or ( a non required field with decimals in source)
			if ( iFormatIndex < sFormat.lastIndexOf('0') || ( iFormatIndex < sFormat.lastIndexOf('#') && formatClass.GetDecimalsCount(sNewSrc) > 0 ) )
			{
				// Convert to float, round it and then convert back to string
				sNewSrc = String(formatMath.FloatRound(parseFloat(sNewSrc), formatClass.GetFormatDecimalPosCount(sFormat, formatClass.BOTH)));
				
				sResult += "," + formatClass.OperationFormat(sNewSrc, sFormat, iFormatIndex + 1, iSourceIndex + 1, sFormat.length, sNewSrc.length, true, true)
			}
		}
	}
	// If we have any required field or the source isnt zero
	if ( ! (formatClass.GetFormatNumberPosCount(sFormat, formatClass.REQUIRED) == 0 && parseInt(sNewSrc) == 0) )
		sResult = formatClass.OperationFormat(sNewSrc, sFormat, 0, 0, iFormatIndex, iSourceIndex, bLeftToRight, bCut) + sResult;

	// Get rid of the white spaces ahead and after the content
	sResult = formatClass.Trim(sResult);

	// If the source is negative, then the result should be also
	if ( sNewSrc.charAt(0) == '-' )
		sResult = '-' + sResult;

	return sResult;
}

function FormatClass()
{
	// Parses a format string and a source string to create a result string
	this.OperationFormat = function OperationFormat(sSrc, sFormat, iFormatLowerPos, iSourceLowerPos, iFormatHighPos, iSourceHighPos, bLeftToRight, bCut)
	{
		var iFormatElementEnd, iSourceElementEnd, iFormatElement, iSourceElement;
		var sResult = "";
		
		if ( bLeftToRight )
		{
			iFormatElement = iFormatLowerPos;
			iSourceElement = iSourceLowerPos;
			iFormatElementEnd = iFormatHighPos;
			iSourceElementEnd = iSourceHighPos;
		}
		else
		{
			iFormatElement = iFormatHighPos - 1;
			iSourceElement = iSourceHighPos - 1;
			iFormatElementEnd = iFormatLowerPos;
			iSourceElementEnd = iSourceLowerPos;
		}

		// while we still have characters to process
		while ( this.Continue(bLeftToRight, iFormatElement, iFormatElementEnd) )
		{
			switch ( sFormat.charAt(iFormatElement) )
			{
				case '.': break;
				case '0':
				case '#':
				{
					iSourceElement = this.GetNextNumberPosition(sSrc, iSourceElement, iSourceElementEnd, bLeftToRight);
					// if GetNextNumberPosition returned a position, i. e. it found a number
					if ( iSourceElement >= 0 )
					{
						sResult = this.AddToResult(sResult, sSrc.charAt(iSourceElement), bLeftToRight);
						if ( bLeftToRight ) iSourceElement++;
						else iSourceElement--;
					}
					// else if the character we are processing is '0'
					else if ( sFormat.charAt(iFormatElement) == '0' )
					{
						// If no more numbers exists in the source, the '0' sign requires us to put a 0 in that field
						sResult = this.AddToResult(sResult, sFormat.charAt(iFormatElement), bLeftToRight);
						iSourceElement = iSourceElementEnd;
					}
					// Finally if we reached the last number					
					if ( iSourceElement < 0 )
					{
						// Setting values so that next time, this will fail. Letting us parse the format string without bother the source anymore
						if ( bLeftToRight ) iSourceElement = iSourceElementEnd + 1;
						else iSourceElement = iSourceElementEnd -1;
					}
					break;
				}
				default:
				{
					// All other characters in the format string we simply add to the result
					sResult = this.AddToResult(sResult, sFormat.charAt(iFormatElement), bLeftToRight);
				}
			}
			if ( bLeftToRight )
				iFormatElement++;
			else
				iFormatElement--;
		}
		// If we arent gonna cut, e.g. if we are processing decimals we dont want more decimals than the user described in the format string
		if ( !bCut )
		{
			iSourceElement = this.GetNextNumberPosition(sSrc, iSourceElement, iSourceElementEnd, bLeftToRight);
			while ( iSourceElement >= 0 )
			{
				if ( sResult.charAt(0) == '(' ) sResult = '(' + this.AddToResult(sResult.substr(1, sResult.length-1), sSrc.charAt(iSourceElement), bLeftToRight);
				else sResult = this.AddToResult(sResult, sSrc.charAt(iSourceElement), bLeftToRight);
				if ( bLeftToRight ) iSourceElement++;
				else iSourceElement--;
				iSourceElement = this.GetNextNumberPosition(sSrc, iSourceElement, iSourceElementEnd, bLeftToRight);
			}
		}
		return sResult;
	}
	
	// Adds the result on the start or end of the string, depending on which way we parse (specified by "bLeftToRight")
	this.AddToResult = function AddToResult(sResult, cChar, bLeftToRight)
	{
		if ( bLeftToRight )
			return sResult + cChar;
		else
			return cChar + sResult;
	}

	// Checks whether we are at the end of our parsing or not, returns true if we can continue, false if we are at the end.
	this.Continue = function Continue(bLeftToRight, iValue, iEndValue)
	{
		if ( bLeftToRight )
			return ( iValue < iEndValue );
		else
			return ( iValue >= iEndValue );
	}

	// Returns the position of the next number in the string
	this.GetNextNumberPosition = function GetNextNumberPosition(sSrc, iStartPos, iEndPos, bLeftToRight)
	{
		if ( this.Continue(bLeftToRight, iStartPos, iEndPos) )
		{
			var cChar;
			var iIncValue;
			if ( bLeftToRight ) iIncValue = 1;
			else iIncValue = -1;
			for ( var iPos = iStartPos; this.Continue(bLeftToRight, iPos, iEndPos); iPos += iIncValue )
			{
				cChar = sSrc.charAt(iPos);
				if ( cChar >= '0' && cChar <= '9' )
					return iPos;
			}
		}
		return -1;
	}

	// Returns the amount of decimals in a given string
	this.GetDecimalsCount = function GetDecimalsCount(sSrc)
	{
		var iCount = 0;
		var iStartPos = sSrc.indexOf('.');
		if ( iStartPos >= 0 )
		{
			for ( var iPos = iStartPos; iPos < sSrc.length; iPos++ )
			{
				iPos = this.GetNextNumberPosition(sSrc, iPos, sSrc.length, true);
				if ( iPos >= 0 )
					iCount++;
				else
					break;
			}
		}
		return iCount;
	}

	// Returns the number of integers in a given string
	this.GetNumbersCount = function GetNumbersCount(sSrc)
	{
		var iLimitPos = sSrc.indexOf('.');
		if ( iLimitPos < 0 ) iLimitPos = sSrc.length;

		var iCount = 0;
		for ( var iPos = 0; iPos < iLimitPos; iPos++ )
		{
			iPos = this.GetNextNumberPosition(sSrc, iPos, sSrc.length, true);
			if ( iPos >= 0 )
				iCount++;
			else
				break;
		}
		return iCount;
	}

	this.REQUIRED		= 0; // = check for '0' in the format string
	this.BOTH			= 1; // = check for '0' and '#' in the format string
	this.NON_REQUIRED	= 2; // = check for '#' in the format string
	// Gets the amount of positions reserved for integers in the format string, fields that are checked are those described by type
	this.GetFormatNumberPosCount = function GetFormatNumberPosCount(sFormat, iType)
	{
		var iLimitPos = sFormat.indexOf('.');
		if ( iLimitPos < 0 ) iLimitPos = sFormat.length;

		var iCount = 0;
		for ( var iPos = 0; iPos < iLimitPos; iPos++ )
		{
			switch ( iType )
			{
				case this.BOTH:
				{
					if ( sFormat.charAt(iPos) == '#' || sFormat.charAt(iPos) == '0' )
						iCount++;
					break;
				}
				case this.REQUIRED:
				{
					if ( sFormat.charAt(iPos) == '0' )
						iCount++;
					break;
				}
				case this.NON_REQUIRED:
				{
					if ( sFormat.charAt(iPos) == '#' )
						iCount++;
					break;
				}
			}
		}
		return iCount;
	}
	
	// Gets the amount of positions reserved for decimals in the format string, fields that are checked are those described by type
	this.GetFormatDecimalPosCount = function GetFormatDecimalPosCount(sFormat, iType)
	{
		var iCount = 0;
		var iStartPos = sFormat.indexOf('.');
		if ( iStartPos >= 0 )
		{
			for ( var iPos = iStartPos; iPos < sFormat.length; iPos++ )
			{
				switch ( iType )
				{
					case formatClass.BOTH:
					{
						if ( sFormat.charAt(iPos) == '#' || sFormat.charAt(iPos) == '0' )
							iCount++;
						break;
					}
					case formatClass.REQUIRED:
					{
						if ( sFormat.charAt(iPos) == '0' )
							iCount++;
						break;
					}
					case formatClass.NON_REQUIRED:
					{
						if ( sFormat.charAt(iPos) == '#' )
							iCount++;
						break;
					}
				}
			}
		}
		return iCount;
	}

	// Cleans up characters that arent supposed to be in the source string, also changes ',' to '.'
	this.CleanInputString = function CleanInputString(sSrc)
	{
		var sCleanedSource = "";
		var cChar;
		if ( sSrc.charAt(0) == '-' ) sCleanedSource += '-';
		for ( var iPos = 0; iPos < sSrc.length; iPos++ )
		{
			cChar = sSrc.charAt(iPos)
			if ( cChar == '.' ) sCleanedSource += '.';
			if ( cChar == ',' ) sCleanedSource += '.';
			if ( cChar >= '0' && cChar <= '9' ) sCleanedSource += cChar;
		}
		return sCleanedSource;
	}
	
	this.Trim = function Trim(str)
	{
		var iPos;
		var iCount = 0;
		for ( iPos = 0; iPos < str.length; iPos++ )
		{
			if ( str.charAt(iPos) == ' ' )
				iCount++;
			else
				break;
		}
		str = str.substr(iCount, str.length - iCount);
		iCount = 0;
		for ( iPos = str.length - 1; iPos >= 0; iPos++ )
		{
			if ( str.charAt(iPos) == ' ' )
				iCount++;
			else
				break;
		}
		str = str.substr(0, str.length - iCount);
		return str;
	}
}

function FormatMath()
{
	this.FloatRound = function FloatRound(fValue, iDecimals)
	{
		var fNewValue;
		var fDecTimesValue = parseFloat(Potense(10, iDecimals));
		fNewValue = Math.round(fValue * fDecTimesValue) / fDecTimesValue;
		return fNewValue;
	}

	this.Potense = function Potense(iValue, iPotense)
	{
		var iRes = iValue;
		for ( var iTime = 1; iTime < iPotense; iTime++ )
			iRes *= iValue;
		return iRes;
	}
}
if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();