function CanonicalQty(sQty, bShowError)
	{		// returns valid qty or empty string if invalid
	var tq;
						// alert ('CanonicalQty activated with ' + sQty);
	if (""+sQty+"" == "") return 1;
	tq = sQty-0;
	if (isNaN(tq) || (tq <= 0) || (tq > 999))
		{
		if (bShowError) 
			{
			alert("Specify a numeric lot size from 1 to 998, or 999"); 
			return sQty; 
			}
		else return "invalid";
		}
	else return tq;
	}

function CanonicalStatus(sStatus)
	{		// returns valid status code
	if (sStatus == "C" || sStatus == "c") return "C";
	if (sStatus == "i" || sStatus == "I") return "I";
	if (sStatus == "CI" || sStatus == "cI") return "CI";
	if (sStatus == "Ci" || sStatus == "ci") return "CI";
	if (sStatus == "IC" || sStatus == "Ic") return "CI";
	if (sStatus == "iC" || sStatus == "ic") return "CI";
	return "";
	}

function CanonicalStatusExt(sStatus, bShowError)
	{		// returns valid status code, with error-checking
	var st = CanonicalStatus(sStatus);
	if (sStatus != "" && st == "")
		{
		if (bShowError) 
			{
			alert("Status must be C, I, CI or empty."); 
			return sStatus; 
			}
		else return "invalid";
		}
	else return st;
	}

function CanonicalPrice(sPrice, bShowError)
	{
							// alert ('CanonicalPrice activated with ' + sPrice);
	return DecodePrice(EncodePrice(sPrice, bShowError),bShowError);
	}

	
function CCEValidSingleUpdate()
	{	// used only by CCEEditSinglePrice.asp
					// alert ('CCEValidSingleUpdate activated!');	
	if (CanonicalPrice(document.SINGLE.txtPrce.value) == "invalid" ||
		CanonicalQty(document.SINGLE.txtQty.value) == "invalid") return false;
	document.SINGLE.txtPrce.value = CanonicalPrice(document.SINGLE.txtPrce.value);
	document.SINGLE.txtQty.value = CanonicalQty(document.SINGLE.txtQty.value);
	document.SINGLE.txtStatus.value = CanonicalStatus(document.SINGLE.txtStatus.value);
	return true;
	}


var PriceRangeBase = new Array( 0, 500, 2000, 5000, 10000, 50000, 100000, 500000, 1000000, 9950000);
var PriceMaxRanges = PriceRangeBase.length;
var PriceIncrValue = new Array(   1,   5,   10,   50,   100,   500,   1000,   5000,   10000);

function EncodePrice(vPrice, bShowError)
    {
    // Encode a price into a 2-char encoded price value.
    // Args:
    //   vPrice      price to encode, in one of these formats:
    //                   5-char string, number with optional "k"
    //                   Long dollar amount
    // function returns range index and #increments as a 2-digit base-1024 number
    // Method is as near the old C function as I could make it.
    // Method is as near the VB port of the old C function as I needed to make it.
	
    var nPrice, sStartChar, sEndChar, nCode0, nCode1, iRange, NumericPart, i;

    // Convert vPrice to a Long. Accommodate K as a thousands multiplier.
									//alert ("vPrice=" + vPrice);
	if (vPrice == "") return 128*1024;	// special case
									//alert ("IsInt=" + IsInt(vPrice, false));
    if (IsInt(vPrice, false))
		{  	// then-else order reversed from VB version
		nPrice = parseInt(vPrice);
		}
    else {	// may be a quote, or may have a "K" in it
        sStartChar = vPrice.charAt(0); sStartChar = sStartChar.toUpperCase();
        sEndChar =   vPrice.charAt(vPrice.length-1); sEndChar = sEndChar.toUpperCase();
									//alert ("sStart,sEnd=" + sStartChar + "/" + sEndChar);
		if (sStartChar == "Q")
			{	// quote
		    nPrice = -1;
									//alert("nPrice=" + nPrice);
			}
		else {	// identify start of the number part of the price
		    i = 0;
		    if (vPrice.charAt(0) == " ") i = 1;
		    if (vPrice.charAt(1) == " ") i = 2;
		    if (vPrice.charAt(2) == " ") i = 3;
		    if (vPrice.charAt(3) == " ") i = 4;

		    NumericPart = vPrice.substring(i,vPrice.length);	// includes possible K, but ParseInt ignores it
									//alert("NumericPart=" + NumericPart);
		    nPrice = parseInt(NumericPart);
									//alert("nPrice[1]=" + nPrice);
			if (isNaN(nPrice))
				{
				if (bShowError) alert("" + vPrice + " is not a valid price");
				return "invalid|" + vPrice; 
				}
		    if (sEndChar == "K") nPrice = 1000 * nPrice;
		    }
		}

    // Encode the price
    if (nPrice < 0)
		{    // Quote gets special coding
		nCode0 = 127;        // out-of-bounds range index
		nCode1 = 0;
		}
    else {   // Conventional price
        if (nPrice >= PriceRangeBase[PriceMaxRanges-1])
		    {
		    nPrice = PriceRangeBase[PriceMaxRanges-1];
		    nCode0 = PriceMaxRanges-2;
		    }
		else {
		    for (iRange=1; iRange<=PriceMaxRanges-1; ++iRange)
			if (nPrice < PriceRangeBase[iRange]) break;
	        nCode0 = iRange-1;
		    }	
									//alert("nCode0=" + nCode0);
        nCode1 = Math.floor(
			(nPrice-PriceRangeBase[nCode0] + Math.floor(PriceIncrValue[nCode0]/2))
                    / PriceIncrValue[nCode0]
			);
									//alert("nCode1=" + nCode1);
		// we can't convert to chr$(), so we'll just hold it as a 2-digit base-1024 number. VB code had:
        // nCode0 = &H40& Or (nCode0 * 4) Or ((nCode1 \ 64) And &H3&)
        // nCode1 = &H40& Or (nCode1 And &H3F&)
    	}
    // in this representation, upper part is range index, lower is #increments    
									//alert("return=" + (1024 * nCode0 + nCode1));
    return (1024 * nCode0 + nCode1);	// Chr$(nCode0) & Chr$(nCode1)
    }


function DecodePrice(sCode,bShowError)
    {
    // Decode a price from a 2-character encoded value
    // into a Long and into a displayable String.
    // Args:
    //   sCode       the 2-char price code
    //   sDisplay    price formatted for display
    // function returns the price as an integral numeric value (-1 for quotes)
    // Method is as near the old C function as I could make it.
    // Method is as near the VB port of the old C function as I could make it.

    var nPrice, sDisplay;
    var nCode0, nCode1;
    var iRange, iIncrements;

	if ((""+sCode).substring(0,7) == "invalid") 
		{
		if (bShowError) return sCode.slice(8); 
		else return "invalid";
		}
    // separate the two parts (range,increments)
    nCode0 = Math.floor(sCode / 1024);	// Asc(Mid$(sCode, 1, 1));
    nCode1 = sCode % 1024;		// Asc(Mid$(sCode, 2, 1))

    if (nCode0 == 128)
		{	// it's a nil price
		nPrice = 0;						// nPrice is unused just now
		sDisplay = "";
		}
	else if (nCode0 == 127)
        { 	// It's a Quote
        nPrice = -1;					// nPrice is unused just now
        sDisplay = "QUOTE";
		}
    else {	// Conventional price code
        iRange = nCode0;
        iIncrements = nCode1;
        nPrice = PriceRangeBase[iRange] + iIncrements * PriceIncrValue[iRange];
        sDisplay = nPrice + "";
		}
    return (sDisplay);
    }


