// categoryitem.js
//
// Declares objects which encapsulate a hierarchical tree of generic
// product categories and items and any corresponding supplier items.
//
// NOTES:
//
// (1) Hierarchical tree will consist of ALL ProductCategoryItem
//     table entries for the desired range (typically the entire tree).
//
// (2) Hierarchical tree will include extra rows for ALL AccountItem
//     entries for the desired suppliers.
//
// (3) Each AccountItem entry will include an array with any certifications
//     specific to that item.
//

// Miscellaneous global support vars and functions.

var g_bSortAscending = true;

function compare(a,b) {
	return (a == b) ? 0 : ((a < b) ? -1 : 1);
}


var filterNameMask          = 0x01;
var filterCategoryItemMask  = 0x02;
var filterDistanceMask      = 0x04;
var filterCertificationMask = 0x08;
var filterSupplierMask      = 0x10;
var filterScheduleMask      = 0x20;
var filterTermsMask         = 0x40;


//-------------------------------------------------------------------/
// CategoryItem array object and methods.
//-------------------------------------------------------------------/

function CategoryItemArray() { 
	this.CIArr = new Array();

	this.bSortByItem = false;
	this.bSortByItemAscending = false;
	
	this.bSortBySupplier = false;
	this.bSortBySupplierAscending = false;
	
	this.bSortByDistance = false;
	this.bSortByDistanceAscending = false;
	
	this.bSortByPrice = false;
	this.bSortByPriceAscending = false;
	
	this.bSortByAvailability = false;
	this.bSortByAvailabilityAscending = false;
	
}

CategoryItemArray.prototype.toString = function(delim1,delim2) {
	var str = "";
	
	for (var i = 0; i < this.CIArr.length; i++) {
		str += delim1 + "[" + i + "]" + this.CIArr[i].toString(delim2);
	}
	
	return str;
}

CategoryItemArray.prototype.getLength = function() {
	return this.CIArr.length;
}

CategoryItemArray.prototype.addCategoryItem = function(
	parentId,parentName,
        catItemId,catItemName,catItemDesc,catItemRetired,
        catItemLevel,catItemOrder,catItemShow,
	acctId,acctName,acctDist,acctLat,acctLong,
        acctItemId,acctItemStatus,acctItemDesc,acctItemSKU,
        acctItemPrice,acctItemMarkup, acctItemRoundup, acctItemOverride, acctItemHide,
        acctItemUnit,acctItemPackage,acctItemCustomPackage,acctItemMinQty,acctItemUnitsPerPackage,
        acctItemOpenAvailability,acctItemUnitsAvailable,acctItemCertIds,acctItemCertNames,
        orderQuantity,orderAllowSeconds,orderAltSuppliers,orderSchedule) { 
	//
	// ALWAYS adds new entry to the END of the categories and items array
	//
	this.CIArr[this.CIArr.length] = new CategoryItem(
            this.CIArr.length,
            parentId,parentName,
            catItemId,catItemName,catItemDesc,catItemRetired,
            catItemLevel,catItemOrder,catItemShow,
            acctId,acctName,acctDist,acctLat,acctLong,
            acctItemId,acctItemStatus,acctItemDesc,acctItemSKU,
            acctItemPrice,acctItemMarkup,acctItemRoundup,acctItemOverride,acctItemHide,
            acctItemUnit,acctItemPackage,acctItemCustomPackage,acctItemMinQty,acctItemUnitsPerPackage,
            acctItemOpenAvailability,acctItemUnitsAvailable,acctItemCertIds,acctItemCertNames,
            orderQuantity,orderAllowSeconds,orderAltSuppliers,orderSchedule);

	return this.CIArr.length - 1;
}


CategoryItemArray.prototype.setDistanceTo = function(toLat,toLong,useKm) {
    //
    // function distanceCosineLaw() defined in supplier.js
    //
    // NOTE that this function is identical to its counterpart in supplier.js
    // but tailored to act on the CIArr array and item acctDistance, acctLat,
    // and acctLong. ONLY use this function and acctDistance, acctLat, acctLong
    // when the suppliers javascript array and supplier equivalents are not
    // available. NOTE that we still set acctDistance for account items in
    // CategoryItemArray so that they may be sorted by distance.
    //
    try {
        if (toLat < 1000.0 && toLong < 1000.0) {
            //alert("CategoryItemArray.setDistanceTo("+toLat+","+toLong+","+useKm+") ..."); // debug
            for (var i = 0; i < this.CIArr.length; i++) {
                if (this.CIArr[i].acctLat < 1000.0 && this.CIArr[i].acctLong < 1000.0) {
                    //alert("CategoryItemArray.setDistanceTo() ["+i+"]("+this.CIArr[i].latitude+","+this.CIArr[i].longitude+") ..."); // deubg
                    this.CIArr[i].acctDistance = 
                        Math.round(
                            distanceCosineLaw(this.CIArr[i].acctLat,this.CIArr[i].acctLong,toLat,toLong,useKm) );
                }
            }
        }
    } 
    catch(err) {
        alert("ERROR: "+err.toString()+"\nCategoryItemArray.setDistanceTo("+toLat+","+toLong+","+useKm+") ..."); // deubg
    }
}

CategoryItemArray.prototype.moveCategoryItem = function(itemid,newparentid,newsiblingid) {
    //
    // Do javascript array equivalent of calling db function omd_ParentCategoryItemMove.
    //
    // NOTE that we DO NOT fix up catItemOrder whereas the db function does (and must)
    // reset ProductCategoryItem.CategoryItemOrder for items moved and may even re-order
    // the entire table. Instead, the array indexes act as the ordering and the list
    // should always be rendered in array index order.
    //
    //alert("moveCategoryItem("+itemid+","+newparentid+","+newsiblingid+") ..."); // debug
    //
    // Get source and destination array indexes for the move.
    //
    var srcIdxFrom = (itemid == 0 ? -1 : this.getCategoryItemIndex(itemid));
    if (srcIdxFrom < 0 || this.CIArr.length <= srcIdxFrom) {
        alert("moveCategoryItem("+itemid+","+newparentid+","+newsiblingid+")\nERROR srcIdxFrom="+srcIdxFrom+" out of range!");
        return;
    }

    var dstParentIdx = (newparentid == 0 ? -1 : this.getCategoryItemIndex(newparentid));
    if (this.CIArr.length <= dstParentIdx) {
        alert("moveCategoryItem("+itemid+","+newparentid+","+newsiblingid+")\nERROR dstParentIdx="+dstParentIdx+" out of range!");
        return;
    }

    var dstSiblingIdx = (newsiblingid == 0 ? -1 : this.getCategoryItemIndex(newsiblingid));
    if (this.CIArr.length <= dstSiblingIdx) {
        alert("moveCategoryItem("+itemid+","+newparentid+","+newsiblingid+")\nERROR dstSiblingIdx="+dstSiblingIdx+" out of range!");
        return;
    }

    // Get count of items to move. We initialize the loop control parameters
    // to begin with the item being moved and with a level MUCH greater than
    // that of the item being moved so we enter the loop at least once and
    // count the item being moved first. NOTE that the loop's ending source
    // index is EXCLUSIVE meaning that that item is not included in the move
    // which is why it is suffixed with ...ToEx instead of ...Thru.
    //
    var srcIdxToEx = srcIdxFrom;
    var item = this.getCategoryItemByIndex(srcIdxFrom);
    var srcLevel = item.getCategoryItemLevel();

    if (srcLevel < 1) {
        alert("moveCategoryItem("+itemid+","+newparentid+","+newsiblingid+") ERROR srcLevel="+srcLevel+" < 1");
        return;
    }

    var level = 100000; // init to some large number

    while (srcIdxToEx < this.CIArr.length && srcLevel < level) {
        srcIdxToEx++;
        if ( srcIdxToEx < this.CIArr.length ) {
            item = this.getCategoryItemByIndex(srcIdxToEx);
            level = item.getCategoryItemLevel();
        }
    }

    // Now gather the destination particulars.
    //
    var dstIdx = (dstSiblingIdx < 0 ? dstParentIdx : dstSiblingIdx);

    var dstLevel = (dstSiblingIdx < 0 
                      ? this.getCategoryItemByIndex(dstParentIdx).getCategoryItemLevel() + 1
                      : this.getCategoryItemByIndex(dstSiblingIdx).getCategoryItemLevel());


    if (dstLevel < 1) {
        alert("moveCategoryItem("+itemid+","+newparentid+","+newsiblingid+") ERROR dstLevel="+dstLevel+" < 1");
        return;
    }

    // If inserting beneath a sibling, make sure the insertion is happening
    // beyond any children the sibling may have.
    if (dstSiblingIdx >= 0) {
        while (++dstIdx < this.CIArr.length && dstLevel < this.CIArr[dstIdx].catItemLevel) {}
        --dstIdx; // bring it back to the index to insert after
    }


    // Prepare to make the move. The assumption is that the destination is NOT contained
    // within the source range of items. Anotherwords, there is NO OVERLAP. The move is
    // done completely using the original indexes to extract and concat the different
    // original array slices in the order desired and is done differently depending
    // on whether dstIdx < srcIdx or srcIdx < dstIdx.

    // FIRST test for overlap.
    if (srcIdxFrom <= dstIdx && dstIdx < srcIdxToEx) {
        if (dstSiblingIdx >= 0 && dstSiblingIdx != dstIdx && (dstSiblingIdx < srcIdxFrom || srcIdxToEx <= dstSiblingIdx)) {
            //
            // SPECIAL CASE: source and destinations overlap AFTER moving dstIdx above
            // but original dstSiblingIdx DOES NOT overlap so must be moving child to be
            // its own parent's sibling...reset dstIdx to original dstSiblingIdx and proceed.
            //
            dstIdx = dstSiblingIdx;
        }
        else {
            alert("moveCategoryItem("+itemid+","+newparentid+","+newsiblingid+")\nERROR dstIdx="+dstIdx+" overlaps source range\nsrcIdxFrom="+srcIdxFrom+" srcIdxToEx="+srcIdxToEx);
            return;
        }
    }

    // Adjust levels in the range to be moved as needed.
    if (srcLevel != dstLevel) {
        var deltaLevel = dstLevel - srcLevel;
        for (var i = srcIdxFrom; i < srcIdxToEx; i++) {
            this.CIArr[i].catItemLevel += deltaLevel;
        }
    }

    // Set the new parent for the item being moved.
    this.CIArr[srcIdxFrom].parentId = 
        (dstSiblingIdx < 0 ? newparentid : this.CIArr[dstSiblingIdx].parentId);

    // Make the move.
    if (srcIdxFrom < dstIdx) {
        this.CIArr = this.CIArr.slice(0,srcIdxFrom).concat(
                     this.CIArr.slice(srcIdxToEx,dstIdx+1),
                     this.CIArr.slice(srcIdxFrom,srcIdxToEx),
                     this.CIArr.slice(dstIdx+1));
    }
    else { // dstIdx < srcIdxFrom
        this.CIArr = this.CIArr.slice(0,dstIdx+1).concat(
                     this.CIArr.slice(srcIdxFrom,srcIdxToEx),
                     this.CIArr.slice(dstIdx+1,srcIdxFrom),
                     this.CIArr.slice(srcIdxToEx));
    }

    return;
}


CategoryItemArray.prototype.getCategoryItemByUniqueIndex = function(index) {

    // Unique index is the array index at the time the entry was added to the
    // array versus the array index at any given time and does not change if 
    // the array gets sorted or modified in some way.
    
    if (0 <= index && index < this.CIArr.length) {
        for (var i = 0; i < this.CIArr.length; i++) {
            if (this.CIArr[i].index == index) {
                    return this.CIArr[i];
            }
        }
    }

    return null;
}

CategoryItemArray.prototype.getCategoryItemIndexByUniqueIndex = function(index) {

    // Unique index is the array index at the time the entry was added to the
    // array versus the array index at any given time and does not change if 
    // the array gets sorted or modified in some way.
    
    if (0 <= index && index < this.CIArr.length) {
        for (var i = 0; i < this.CIArr.length; i++) {
            if (this.CIArr[i].index == index) {
                    return i;
            }
        }
    }

    return i;
}

CategoryItemArray.prototype.getCategoryItem = function(index) {
    // return reference to the item current at that array position
    if (0 <= index && index < this.CIArr.length)
        return this.CIArr[index];
    else
        return null;
}

CategoryItemArray.prototype.getCategoryItemByIndex = function(index) {
	return this.getCategoryItem(index);
}

CategoryItemArray.prototype.getCategoryItemById = function(id) {
	for (var i = 0; i < this.CIArr.length; i++) {
		if (this.CIArr[i].catItemId == id) {
			return this.CIArr[i];
		}
	}
	
	return null;
}

CategoryItemArray.prototype.getCategoryItemIndex = function(id) {
	for (var i = 0; i < this.CIArr.length; i++) {
		if (this.CIArr[i].catItemId == id) {
			return i;
		}
	}
	
	return i;
}

CategoryItemArray.prototype.getCategoryItemByItemName = function(name) {
	for (var i = 0; i < this.CIArr.length; i++) {
		if (this.CIArr[i].catItemName == name) {
			return this.CIArr[i];
		}
	}
	
	return null;
}

CategoryItemArray.prototype.getCategoryItemByAccountItemId = function(id) {
	for (var i = 0; i < this.CIArr.length; i++) {
		if (this.CIArr[i].acctItemId == id) {
			return this.CIArr[i];
		}
	}
	
	return null;
}

CategoryItemArray.prototype.getCategoryItemIndexByAccountItemId = function(id) {
	for (var i = 0; i < this.CIArr.length; i++) {
		if (this.CIArr[i].acctItemId == id) {
			return i;
		}
	}
	
	return i;
}

CategoryItemArray.prototype.getCategoryItemId = function(index) {
	if (0 <= index && index < this.CIArr.length)
		return this.CIArr[index].getId();
	else
		return null;
}

CategoryItemArray.prototype.getCategoryItemParent = function(index) {
	if (0 <= index && index < this.CIArr.length)
		return this.CIArr[index].getParentId();		
	else
		return null;
}

CategoryItemArray.prototype.getNextSiblingOrElder = function(index) {
    //
    // Given a beginning item index in the array, return the index of the next
    // item which is the next sibling or "elder" of the item (meaning same or
    // lessor level). 
    //
    if (0 <= index && index < this.CIArr.length - 2) {
        var idx = index;
        var level = this.CIArr[idx].catItemLevel;
        while (++idx < this.CIArr.length - 1 && level < this.CIArr[idx].catItemLevel) {}
        return idx;
    }

    return null;
}

CategoryItemArray.prototype.getAddSiblingInsertAfterIndex = function(siblingIdx) {
    //
    // Given a target item index in the array under which you wish to add
    // a sibling, return the index of the item under (after) which you will
    // actually add the new sibling item. 
    //
    // If target item has no children, will return the target item index.
    //
    // If target item has children, will return the index of the last
    // item following the target item with level > target item level.
    //
    var idx = siblingIdx;
    var level = this.CIArr[idx].catItemLevel;
    while (++idx < this.CIArr.length && level < this.CIArr[idx].catItemLevel) {}
    return --idx;
}

CategoryItemArray.prototype.getAddSiblingInsertAfterItem = function(siblingId) {
    //
    // See getAddSiblingInsertUnderIndex(siblingIdx) for description
    // of what this function does. This function returns an item
    // reference instead of an item index.
    //

    // Get target item index.
    var siblingIdx = 0;
    while (siblingIdx < this.CIArr.length && this.CIArr[siblingIdx].catItemId != siblingId) { 
        ++siblingIdx; 
    }

    // Get insert after item index and return reference to that item.
    var insertIdx;
    if (siblingIdx < this.CIArr.length) {
        insertIdx = this.getAddSiblingInsertAfterIndex(siblingIdx);
        return this.CIArr[insertIdx];
    }
    
    return null;
}

CategoryItemArray.prototype.getNextSibling = function(index) {
	if (0 <= index && index < this.CIArr.length) {
		for (var i = index + 1; i < this.CIArr.length; i++) {
			if (this.CIArr[index].getCategoryItemLevel() == this.CIArr[i].getCategoryItemLevel()) {
				return this.CIArr[i];
			}
		}
	}
	else
		return null;
}

CategoryItemArray.prototype.getNextSiblingIndex = function(index) {
    if (0 <= index && index < this.CIArr.length) {
        for (var i = index + 1; i < this.CIArr.length; i++) {
            if (this.CIArr[index].getCategoryItemLevel() == this.CIArr[i].getCategoryItemLevel()) {
                return i;
            }
        }
    }
    else
        return null;
}

CategoryItemArray.prototype.getNextSiblingOrder = function(index) {
    if (0 <= index && index < this.CIArr.length) {
        for (var i = index + 1; i < this.CIArr.length; i++) {
            if (this.CIArr[index].getCategoryItemLevel() >= this.CIArr[i].getCategoryItemLevel()) {
                return this.CIArr[i].getCategoryItemOrder();
            }
        }

        // This node doesn't have a sibling. Return the largest possible number,
        // so further processing goes all the way to the end.

        return Number.MAX_VALUE;
    }
    else
        return null;
}

CategoryItemArray.prototype.haveCategoryItemChildren = function(pid) {
    // determine if CategoryItem has any immediate children,
    // retired or otherwise
    for (var i = 0; i < this.CIArr.length; i++) {
        if (this.CIArr[i].parentId == pid) {
                return true;
        }
    }

    return false;
}

CategoryItemArray.prototype.haveCategoryItemChildrenNotRetired = function(pid) {
    // determine if CategoryItem has any immediate children
    // that are not retired
    for (var i = 0; i < this.CIArr.length; i++) {
        if (this.CIArr[i].parentId == pid && !this.CIArr[i].isRetired()) {
                return true;
        }
    }

    return false;
}

CategoryItemArray.prototype.getMinCategoryItemOrder = function() {
    if (this.CIArr.length > 0)
        return this.CIArr[0].getCategoryItemOrder();
    else
        return 0;
}

CategoryItemArray.prototype.getMaxCategoryItemOrder = function() {
    if (this.CIArr.length > 0)
        return this.CIArr[this.CIArr.length - 1].getCategoryItemOrder();
    else
        return 0;
}


CategoryItemArray.prototype.getParentCategoryPathIds = function(index,delim) {
    var strIds = "";
    var iParent = 0;
    var idxParent = 0;

    if (0 <= index && index < this.CIArr.length) {
        iParent = this.CIArr[index].getParentId();
        strIds = this.CIArr[index].getCategoryItemId();

        while (iParent != null && iParent != 0 && this.getCategoryItemById(iParent) != null) {
            idxParent = this.getCategoryItemIndex(iParent);
            strIds = (this.CIArr[idxParent].getCategoryItemId() + delim + strIds);
            iParent = this.CIArr[idxParent].getParentId();
        }
    }

    //alert("getParentCategoryPathIds(index="+index+",delim='"+delim+"')\nids="+strIds); // debug

    return strIds;
}


CategoryItemArray.prototype.getCategoryItemPath = function(id,delim) {
    var strPath = "";

    var catItem = this.getCategoryItemById(id);

    while (catItem != null) {
        if (strPath.length > 0) {
            strPath = delim + strPath;
        }
        strPath = catItem.getCategoryItemName() + strPath;
        catItem = this.getCategoryItemById(catItem.getParentId());
    }

    //alert("getCategoryItemShowPath("+id+","+delim+")\npath="+strPath); // debug

    return strPath;
}


CategoryItemArray.prototype.getCategoryItemShowPath = function(id,delim) {
    var strPath = "";

    var catItem = this.getCategoryItemById(id);

    while (catItem != null) {
        if (catItem.showCategory()) {
            if (strPath.length > 0) {
                strPath = delim + strPath;
            }
            strPath = catItem.getCategoryItemName() + strPath;
        }
        catItem = this.getCategoryItemById(catItem.getParentId());
    }

    //alert("getCategoryItemShowPath("+id+","+delim+")\npath="+strPath); // debug

    return strPath;
}


CategoryItemArray.prototype.isSupplierItem = function(index) {
	if (0 <= index && index < this.CIArr.length)
		return this.CIArr[index].isSupplierItem();
	else
		return false;
}


CategoryItemArray.prototype.getSubtotal = function() {
    var sumPriceQty = 0;
    for (var index = 0; index < this.CIArr.length; index++) {
        var price = this.CIArr[index].acctItemPrice;
        var qty = this.CIArr[index].orderQuantity;
        if (price > 0 && qty > 0) {
            sumPriceQty += Math.round(price * qty); // round to precision
        }
    }

    var delim = "."; // fraction delimiter will eventually come from system localization
    var precision = 2; // precision (number of decimals) will eventually come from Currency table
    var divisor = Math.pow(10,precision);

    var subtotal = String(sumPriceQty / divisor);

    if (subtotal.lastIndexOf(delim) < 0) {
        var fraction = "";
        while (fraction.length < precision) fraction += "0";
        subtotal += delim + fraction;
    }
    else {
        var fraction = String(sumPriceQty % divisor);
        while (fraction.length < precision) fraction = "0" + fraction;
        subtotal = subtotal.substring(0,subtotal.lastIndexOf(delim)) + delim + fraction;
    }

    return subtotal;
}




// Array filtering methods

CategoryItemArray.prototype.clearFilters = function () {
    for (var i = 0; i < this.CIArr.length; i++) {
        this.CIArr[i].filterMask = 0;
    }
}


CategoryItemArray.prototype.filterByName = function (name) {
    var lcName = String(name).toLowerCase();
    for (var i = 0; i < this.CIArr.length; i++) {
        if ( lcName.length == 0 || 
            this.CIArr[i].parentFullPath.toLowerCase().indexOf(lcName) >= 0 ||
            this.CIArr[i].catItemName.toLowerCase().indexOf(lcName) >= 0 ) {
            this.CIArr[i].filterMask &= (filterNameMask ^ 0xFF);
        }
        else {
            this.CIArr[i].filterMask |= filterNameMask;
        }
    }

    return;
}

CategoryItemArray.prototype.filterByCategoryItem = function (id,lo,hi) {
    //
    // id=0 => ALL
    // lo = low CategoryOrder inclusive
    // hi = high CategoryOrder exclusive
    //
    for (var i = 0; i < this.CIArr.length; i++) {
        if (id == 0 || (lo <= this.CIArr[i].catItemOrder && this.CIArr[i].catItemOrder < hi))
            this.CIArr[i].filterMask &= (filterCategoryItemMask ^ 0xFF);
        else 
            this.CIArr[i].filterMask |= filterCategoryItemMask;
    }

    return;
}

CategoryItemArray.prototype.filterByDistance = function (distance) {
    //
    // assumes distance argument is an integer
    //
    for (var i = 0; i < this.CIArr.length; i++) {
        if (distance == 0 || this.CIArr[i].acctDistance <= parseInt(distance,10))
            this.CIArr[i].filterMask &= (filterDistanceMask ^ 0xFF);
        else
            this.CIArr[i].filterMask |= filterDistanceMask;
    }

    return;
}

CategoryItemArray.prototype.filterByCertification = function (list) {
    //
    // assumes list is comma delimited list of certification Id integers
    //
    var arrList = String(list).split(",");

    for (var i = 0; i < this.CIArr.length; i++) {
        var bShow = (list.length == 0);

        for (var j = 0; j < arrList.length && !bShow; j++) {
            bShow = this.CIArr[i].hasItemCertificationId(arrList[j]);
        }

        if (bShow)
            this.CIArr[i].filterMask &= (filterCertificationMask ^ 0xFF);
        else
            this.CIArr[i].filterMask |= filterCertificationMask;
    }

    return;
}

CategoryItemArray.prototype.filterBySupplier = function (list) {
    //
    // assumes list is comma delimited list of supplier Id integers
    //
    var arrList = String(list).split(",");

    for (var i = 0; i < this.CIArr.length; i++) {
        var bShow = (list.length == 0);

        for (var j = 0; j < arrList.length && !bShow; j++) {
            bShow = (this.CIArr[i].acctId == parseInt(arrList[j],10));
        }

        if (bShow)
            this.CIArr[i].filterMask &= (filterSupplierMask ^ 0xFF);
        else
            this.CIArr[i].filterMask |= filterSupplierMask;
    }

    return;
}

CategoryItemArray.prototype.filterBySchedule = function (list) {
}

CategoryItemArray.prototype.filterByTerms = function (list) {
    //
    // assumes list is comma delimited list of supplier Id integers
    //
    var arrList = String(list).split(",");

    for (var i = 0; i < this.CIArr.length; i++) {
        var bShow = false;

        for (var j = 0; j < arrList.length && !bShow; j++) {
            bShow = (this.CIArr[i].acctId == parseInt(arrList[j],10));
        }
        
        if (bShow)
            this.CIArr[i].filterMask &= (filterTermsMask ^ 0xFF);
        else
            this.CIArr[i].filterMask |= filterTermsMask;
    }

    return;
}

CategoryItemArray.prototype.filterByMinimumOrderAndPaymentTerms = function(moid,ptid) {
    //
    // assumes must match both to show where moid==0 or ptid==0 means show all
    //
    for (var i = 0; i < this.CIArr.length; i++) {
        var bShowMO = (moid == 0 || moid <= this.CIArr[i].minimumOrder);
        var bShowPT = (ptid == 0 || ptid >= this.CIArr[i].paymentTerms);
        if (bShowMO && bShowPT)
            this.CIArr[i].filterMask &= (filterTermsMask ^ 0xFF);
        else
            this.CIArr[i].filterMask |= filterTermsMask;
    }

    return;
}



// Array sorting methods

CategoryItemArray.prototype.isSortedAscending = function () {
	if (this.bSortByItem)
		return this.bSortByItemAscending;
	else if (this.bSortBySupplier)
		return this.bSortBySupplierAscending;
	else if (this.bSortByDistance)
		return this.bSortByDistanceAscending;
	else if (this.bSortByPrice)
		return this.bSortByPriceAscending;
	else if (this.bSortByAvailability)
		return this.bSortByAvailabilityAscending;
	else
		return false;
}

CategoryItemArray.prototype.isSortedByItem = function () {
	return this.bSortByItem;
}

CategoryItemArray.prototype.isSortedBySupplier = function () {
	return this.bSortBySupplier;
}

CategoryItemArray.prototype.isSortedByDistance = function () {
	return this.bSortByDistance;
}

CategoryItemArray.prototype.isSortedByPrice = function () {
	return this.bSortByPrice;
}

CategoryItemArray.prototype.isSortedByAvailability = function () {
	return this.bSortByAvailability;
}


// Item sort (by parent category name and then item name)

CategoryItemArray.prototype.sortByItem = function() {
    this.bSortBySupplier = false;
    this.bSortBySupplierAscending = false;
    this.bSortByDistance = false;
    this.bSortByDistanceAscending = false;
    this.bSortByPrice = false;
    this.bSortByPriceAscending = false;
    this.bSortByAvailability = false;
    this.bSortByAvailabilityAscending = false;

    this.bSortByItem = true;
    this.bSortByItemAscending = !this.bSortByItemAscending;

    g_bSortAscending = this.bSortByItemAscending;
    this.CIArr.sort(this.byParentItemNames);
}

CategoryItemArray.prototype.byParentItemNames = function(itemA, itemB) {
    // sort by parentName+itemName or just by itemName if no parentName
    var fullItemA = (String(itemA.parentName).length > 0 ? itemA.parentName + ": " : "") + itemA.catItemName;
    var fullItemB = (String(itemB.parentName).length > 0 ? itemB.parentName + ": " : "") + itemB.catItemName;
    var result = compare(fullItemA.toLowerCase(),fullItemB.toLowerCase());

    // if parent and item names match, then sort by account name (ALWAYS ascending)
    if (result == 0) { // if category and item matches, sort by supplier but ALWAYS ascending
        if (g_bSortAscending)
            result = compare(itemA.acctName.toLowerCase(),itemB.acctName.toLowerCase());
        else
            result = compare(itemB.acctName.toLowerCase(),itemA.acctName.toLowerCase());
    }

    return (g_bSortAscending ? result : (0-result)) ;
}

// Supplier sort

CategoryItemArray.prototype.sortBySupplier = function() {
    this.bSortByItem = false;
    this.bSortByItemAscending = false;
    this.bSortByDistance = false;
    this.bSortByDistanceAscending = false;
    this.bSortByPrice = false;
    this.bSortByPriceAscending = false;
    this.bSortByAvailability = false;
    this.bSortByAvailabilityAscending = false;

    this.bSortBySupplier = true;
    this.bSortBySupplierAscending = !this.bSortBySupplierAscending;

    g_bSortAscending = this.bSortBySupplierAscending;
    this.CIArr.sort(this.bySupplier);
}

CategoryItemArray.prototype.bySupplier = function(itemA, itemB) {
    var result = compare(itemA.acctName.toLowerCase(),itemB.acctName.toLowerCase());
    if (result == 0) { // if supplier matches, sort by category but ALWAYS ascending
        if (g_bSortAscending)
            result = compare(itemA.parentName.toLowerCase(),itemB.parentName.toLowerCase());
        else
            result = compare(itemB.parentName.toLowerCase(),itemA.parentName.toLowerCase());
    }
    if (result == 0) { // if category matches, sort by item but ALWAYS ascending
        if (g_bSortAscending)
            result = compare(itemA.catItemName.toLowerCase(),itemB.catItemName.toLowerCase());
        else
            result = compare(itemB.catItemName.toLowerCase(),itemA.catItemName.toLowerCase());
    }
    return (g_bSortAscending ? result : (0-result)) ;
}

// Distance sort

CategoryItemArray.prototype.sortByDistance = function() {
    this.bSortByItem = false;
    this.bSortByItemAscending = false;
    this.bSortBySupplier = false;
    this.bSortBySupplierAscending = false;
    this.bSortByPrice = false;
    this.bSortByPriceAscending = false;
    this.bSortByAvailability = false;
    this.bSortByAvailabilityAscending = false;

    this.bSortByDistance = true;
    this.bSortByDistanceAscending = !this.bSortByDistanceAscending;

    g_bSortAscending = this.bSortByDistanceAscending;
    this.CIArr.sort(this.byDistance);
}

CategoryItemArray.prototype.byDistance = function(itemA, itemB) {
    if (g_bSortAscending)
        return compare(itemA.acctDistance,itemB.acctDistance);
    else
        return compare(itemB.acctDistance,itemA.acctDistance);
}

// Price sort

CategoryItemArray.prototype.sortByPrice = function() {
    this.bSortByItem = false;
    this.bSortByItemAscending = false;
    this.bSortBySupplier = false;
    this.bSortBySupplierAscending = false;
    this.bSortByDistance = false;
    this.bSortByDistanceAscending = false;
    this.bSortByAvailability = false;
    this.bSortByAvailabilityAscending = false;

    this.bSortByPrice = true;
    this.bSortByPriceAscending = !this.bSortByPriceAscending;

    g_bSortAscending = this.bSortByPriceAscending;
    this.CIArr.sort(this.byPrice);
}

CategoryItemArray.prototype.byPrice = function(itemA, itemB) {
    if (g_bSortAscending)
        return compare(itemA.acctItemPrice,itemB.acctItemPrice);
    else
        return compare(itemB.acctItemPrice,itemA.acctItemPrice);
}

// Availability sort

CategoryItemArray.prototype.sortByAvailability = function() {
    this.bSortByItem = false;
    this.bSortByItemAscending = false;
    this.bSortBySupplier = false;
    this.bSortBySupplierAscending = false;
    this.bSortByDistance = false;
    this.bSortByDistanceAscending = false;
    this.bSortByPrice = false;
    this.bSortByPriceAscending = false;

    this.bSortByAvailability = true;
    this.bSortByAvailabilityAscending = !this.bSortByAvailabilityAscending;

    g_bSortAscending = this.bSortByAvailabilityAscending;
    this.CIArr.sort(this.byAvailability);
}

CategoryItemArray.prototype.byAvailability = function(itemA, itemB) {
    if (g_bSortAscending)
        return compare(itemA.acctItemUnitsAvailable,itemB.acctItemUnitsAvailable);
    else
        return compare(itemB.acctItemUnitsAvailable,itemA.acctItemUnitsAvailable);
}


//-------------------------------------------------------------------/
// CategoryItem object and methods.
//-------------------------------------------------------------------/

function CategoryItem(
        index,
	parentId,parentName,
        catItemId,catItemName,catItemDesc,catItemRetired,
        catItemLevel,catItemOrder,catItemShow,
	acctId,acctName,acctDist,acctLat,acctLong,
        acctItemId,acctItemStatus,acctItemDesc,acctItemSKU,
        acctItemPrice,acctItemMarkup,acctItemRoundup,acctItemOverride,acctItemHide,
        acctItemUnit,acctItemPackage,acctItemCustomPackage,acctItemMinQty,acctItemUnitsPerPackage,
        acctItemOpenAvailability,acctItemUnitsAvailable,acctItemCertIds,acctItemCertNames,
        orderQuantity,orderAllowSeconds,orderAltSuppliers,orderSchedule) 
{
        this.index = parseInt(index);                   // simple local array index

        this.isexpanded = true;                        // boolean flag for display state

        this.isdeleted = false;                         // boolean flag to mark an item deleted

        this.filterMask = 0;

        this.parentName = String(parentName);
        this.parentFullPath = "";

	this.parentId = parseInt(parentId);             // ProductCategoryItem fields
	this.catItemId = parseInt(catItemId);
	this.catItemName = String(catItemName);
	this.catItemDesc = String(catItemDesc);
	this.catItemRetired = parseInt(catItemRetired);
	this.catItemLevel = parseInt(catItemLevel);
	this.catItemOrder = parseInt(catItemOrder);
        this.catItemShow = parseInt(catItemShow);
	
	this.acctId = parseInt(acctId);                 // AccountAddress fields
	this.acctName = String(acctName);
	this.acctDistance = parseInt(acctDist,10);      // (truncate distance real to integer)
	this.acctLatitude = parseFloat(acctLat);
	this.acctLongitude = parseFloat(acctLong);

	this.acctItemId = parseInt(acctItemId);         // AccountItem fields
        this.acctItemStatus = parseInt(acctItemStatus);
	this.acctItemDesc = String(acctItemDesc);
        this.acctItemSKU = String(acctItemSKU);

        this.acctItemPrice = parseInt(acctItemPrice,10);
        if (isNaN(this.acctItemPrice)) this.acctItemPrice = 0;

        this.acctItemMarkup = parseInt(acctItemMarkup,10);
        if (isNaN(this.acctItemMarkup)) this.acctItemMarkup = 0;

        this.acctItemRoundup = parseInt(acctItemRoundup,10);
        if (isNaN(this.acctItemRoundup)) this.acctItemRoundup = 0;

        // NOTE: if acctItemOverride is zero to begin with, then set to -1
        // so we can detect when it is changed to 0 to clear an override value.
        //
        this.acctItemOverride = parseInt(acctItemOverride,10);
        if (isNaN(this.acctItemOverride)) this.acctItemOverride = 0;
        if (this.acctItemOverride == 0) this.acctItemOverride = -1;

        // NOTE: if acctItemHide is zero to begin with, then set to -1
        // so we can detect when it is changed to 0 to clear an item hide.
        //
        this.acctItemHide = parseInt(acctItemHide,10);
        if (isNaN(this.acctItemHide)) this.acctItemHide = 0;
        if (this.acctItemHide == 0) this.acctItemHide = -1;

        this.acctItemUnit = parseInt(acctItemUnit,10);
        if (isNaN(this.acctItemUnit)) this.acctItemUnit = 5;

        this.acctItemPackage = parseInt(acctItemPackage,10);
        if (isNaN(this.acctItemPackage)) this.acctItemPackage = 5;

        this.acctItemCustomPackage = String(acctItemCustomPackage); // CustomUnitPackage

        this.acctItemMinQty = parseFloat(acctItemMinQty);
        if (isNaN(this.acctItemMinQty)) this.acctItemMinQty = 1.0;

        this.acctItemUnitsPerPackage = parseInt(acctItemUnitsPerPackage,10);
        if (isNaN(this.acctItemUnitsPerPackage)) this.acctItemUnitsPerPackage = 100;

        this.acctItemOpenAvailability = parseInt(acctItemOpenAvailability);
        if (isNaN(this.acctItemOpenAvailability)) this.acctItemOpenAvailability = 0;

        this.acctItemUnitsAvailable = parseInt(acctItemUnitsAvailable);
        if (isNaN(this.acctItemUnitsAvailable)) this.acctItemUnitsAvailable = 0;

        this.acctItemCertIds = String(acctItemCertIds);
        this.acctItemCertNames = String(acctItemCertNames);

        this.orderQuantity = parseFloat(orderQuantity);
        if (isNaN(this.orderQuantity)) this.orderQuantity = 0.0;

        this.orderAllowSeconds = parseInt(orderAllowSeconds);
        if (isNaN(this.orderAllowSeconds)) this.orderAllowSeconds = 0;

        this.orderAltSuppliers = parseInt(orderAltSuppliers);
        if (isNaN(this.orderAltSuppliers)) this.orderAltSuppliers = 0;

        this.orderSchedule = String(orderSchedule);

        this.left = 0;
        this.top = 0;
}

CategoryItem.prototype.toString = function(delim) {
	var str = "";
	
	str += "\n" + delim + "filterMask=" + this.filterMask;

	str += "\n" + delim + "parentId=" + this.parentId;
	str += "\n" + delim + "parentName=" + this.parentName;

	str += "\n" + delim + "catItemId=" + this.catItemId;
	str += "\n" + delim + "catItemName=" + this.catItemName;
	str += "\n" + delim + "catItemDesc=" + this.catItemDesc;
	str += "\n" + delim + "catItemRetired=" + this.catItemRetired;
	str += "\n" + delim + "catItemLevel=" + this.catItemLevel;
	str += "\n" + delim + "catItemOrder=" + this.catItemOrder;
	str += "\n" + delim + "catItemOrder=" + this.catItemShow;
	
	str += "\n" + delim + "acctId=" + this.acctId;
	str += "\n" + delim + "acctName=" + this.acctName;
	str += "\n" + delim + "acctDistance=" + this.acctDistance;
	str += "\n" + delim + "acctLatitude=" + this.acctLatitude;
	str += "\n" + delim + "acctLongitude=" + this.acctLongitude;
	
	str += "\n" + delim + "acctItemId=" + this.acctItemId;
	str += "\n" + delim + "acctItemStatus=" + this.acctItemStatus;
	str += "\n" + delim + "acctItemDesc=" + this.acctItemDesc;
	str += "\n" + delim + "acctItemSKU=" + this.acctItemSKU;

	str += "\n" + delim + "acctItemPrice=" + this.acctItemPrice;
	str += "\n" + delim + "acctItemMarkup=" + this.acctItemMarkup;
	str += "\n" + delim + "acctItemRoundup=" + this.acctItemRoundup;
	str += "\n" + delim + "acctItemOverride=" + this.acctItemOverride;
	str += "\n" + delim + "acctItemHide=" + this.acctItemHide;

	str += "\n" + delim + "acctItemUnit=" + this.acctItemUnit;
	str += "\n" + delim + "acctItemPackage=" + this.acctItemPackage;
	str += "\n" + delim + "acctItemCustomPackage=" + this.acctItemCustomPackage;
	str += "\n" + delim + "acctItemMinQty=" + this.acctItemMinQty;
	str += "\n" + delim + "acctItemUnitsPerPackage=" + this.acctItemUnitsPerPackage;
	
	str += "\n" + delim + "acctItemOpenAvailability=" + this.acctItemOpenAvailability;
	str += "\n" + delim + "acctItemUnitsAvailable=" + this.acctItemUnitsAvailable;
	str += "\n" + delim + "acctItemCertIds=" + this.acctItemCertIds;
	str += "\n" + delim + "acctItemCertNames=" + this.acctItemCertNames;
	
	return str;
}

CategoryItem.prototype.isExpanded = function() {
    return this.isexpanded;
}

CategoryItem.prototype.setExpanded = function(bxpnd) {
    return this.isexpanded = bxpnd;
}

CategoryItem.prototype.isDeleted = function() {
    return this.isdeleted;
}

CategoryItem.prototype.clrDeleted = function() {
    return this.isdeleted = false;
}

CategoryItem.prototype.setDeleted = function(bDelete) {
    return this.isdeleted = Boolean(bDelete);
}

CategoryItem.prototype.isFiltered = function() {
    return (this.filterMask > 0);
}

CategoryItem.prototype.notFiltered = function() {
    return (this.filterMask == 0);
}

CategoryItem.prototype.isAccountItem = function() {
	return (this.acctItemId != 0);
}

CategoryItem.prototype.getUniqueIndex = function() {
	return this.index;
}

CategoryItem.prototype.getParentId = function() {
	return this.parentId;
}

CategoryItem.prototype.setParentId = function(id) {
    this.parentId = id;
}

CategoryItem.prototype.getParentName = function() {
	return this.parentName;
}

CategoryItem.prototype.setParentName = function( name ) {
    this.parentName = String(name);
}

CategoryItem.prototype.getParentFullPath = function() {
	return this.parentFullPath;
}

CategoryItem.prototype.setParentFullPath = function( name ) {
    this.parentFullPath = String(name);
}

CategoryItem.prototype.getCategoryItemId = function() {
	return this.catItemId;
}

CategoryItem.prototype.getCategoryItemName = function() {
	return this.catItemName;
}

CategoryItem.prototype.getCategoryItemDescription = function() {
	return this.catItemDesc;
}

CategoryItem.prototype.getCategoryItemRetired = function() {
	return this.catItemRetired;
}

CategoryItem.prototype.isRetired = function() {
	return (this.catItemRetired != 0);
}

CategoryItem.prototype.getCategoryItemLevel = function() {
	return this.catItemLevel;
}

CategoryItem.prototype.getCategoryItemOrder = function() {
	return this.catItemOrder;
}

CategoryItem.prototype.getCategoryItemShow = function() {
	return this.catItemShow;
}

CategoryItem.prototype.showCategory = function() {
	return (this.catItemShow != 0);
}

CategoryItem.prototype.getAccountId = function() {
	return this.acctId;
}

CategoryItem.prototype.getAccountName = function() {
	return this.acctName;
}

CategoryItem.prototype.setAccountDistance = function(distance) {
	this.acctDistance = parseInt(distance);
        if (isNaN(this.acctDistance)) this.acctDistance = -1;
}

CategoryItem.prototype.getAccountDistance = function() {
        return this.acctDistance;
}

CategoryItem.prototype.getAccountLatitude = function() {
	return this.acctLatitude;
}

CategoryItem.prototype.getAccountLongitude = function() {
	return this.acctLongitude;
}

CategoryItem.prototype.getItemId = function() {
	return this.acctItemId;
}

CategoryItem.prototype.getItemStatus = function() {
	return this.acctItemStatus;
}

CategoryItem.prototype.getItemDescription = function() {
	return this.acctItemDesc;
}

CategoryItem.prototype.getItemSKU = function() {
	return this.acctItemSKU;
}

CategoryItem.prototype.getItemPrice = function() {
    var delim = "."; // fraction delimiter will eventually come from system localization
    var precision = 2; // precision (number of decimals) will eventually come from Currency table
    var divisor = Math.pow(10,precision);

    var price = String(this.acctItemPrice / divisor);

    if (price.lastIndexOf(delim) < 0) {
        var fraction = "";
        while (fraction.length < precision) fraction += "0";
        price += delim + fraction;
    }
    else {
        var fraction = String(this.acctItemPrice % divisor);
        while (fraction.length < precision) fraction = "0" + fraction;
        price = price.substring(0,price.lastIndexOf(delim)) + delim + fraction;
    }

    return price;
}

CategoryItem.prototype.getItemMarkupPrice = function() {
    var delim = "."; // fraction delimiter will eventually come from system localization
    var precision = 2; // precision (number of decimals) will eventually come from Currency table
    var divisor = Math.pow(10,precision);

    // Per item markup is a percentage markup, so return the multiple one must use
    // to apply to the price to set the marked up price.
    //
    var intMarkup = parseInt(Math.round( parseFloat(1.0 + (this.acctItemMarkup / 100)) * (this.acctItemPrice)));
    var markup = String(intMarkup / divisor);

    if (markup.lastIndexOf(delim) < 0) {
        var fraction = "";
        while (fraction.length < precision) fraction += "0";
        markup += delim + fraction;
    }
    else {
        var fraction = String(intMarkup % divisor);
        while (fraction.length < precision) fraction = "0" + fraction;
        markup = markup.substring(0,markup.lastIndexOf(delim)) + delim + fraction;
    }

    return markup;
}


CategoryItem.prototype.getItemRoundupPrice = function() {
    var delim = "."; // fraction delimiter will eventually come from system localization
    var precision = 2; // precision (number of decimals) will eventually come from Currency table

    var markup = this.getItemMarkupPrice();

    if ( (Math.round(markup*100) % this.acctItemRoundup) != 0 && !isNaN(Math.round(markup*100) % this.acctItemRoundup) && ( this.acctItemPrice != Math.round(markup*100) ) ) {

        if ( markup < Math.round(markup * Math.round(100/this.acctItemRoundup)) / Math.round(100/this.acctItemRoundup) ) {
            markup = Math.round(markup * Math.round(100/this.acctItemRoundup)) / Math.round(100/this.acctItemRoundup) ;
        } else {
            markup = (Math.round(markup * (100/this.acctItemRoundup)) + 1) / (100/this.acctItemRoundup);
        }

        markup += ''; // convert to string;

        if (markup.lastIndexOf(delim) < 0) {
            var fraction = "";
            while (fraction.length < precision) fraction += "0";
            markup += delim + fraction;
        } else {
            if ( markup.length - markup.lastIndexOf(delim) < 3 ) {
                markup += '0';
            }
        }
    }

    return markup;
}


CategoryItem.prototype.setItemOverride = function(fltOverride) {
    var precision = 2; // precision (number of decimals) will eventually come from Currency table

    // normalize what was entered, to eliminate surrounding whitespace and trailing garbage,
    var f_ovrd = isNaN(parseFloat(fltOverride)) ? 0 : parseFloat(fltOverride);
    this.acctItemOverride = Math.round(f_ovrd * Math.pow(10,precision));
}

CategoryItem.prototype.getItemOverride = function() {
    var delim = "."; // fraction delimiter will eventually come from system localization
    var precision = 2; // precision (number of decimals) will eventually come from Currency table
    var divisor = Math.pow(10,precision);

    var override = String(this.acctItemOverride / divisor);

    if (override <= 0) {
        // do not do any formatting if <= 0, just return 0
        // note that -1 means it was originally 0 and remains unchanged
        return 0;
    }
    else if (override.lastIndexOf(delim) < 0) {
        var fraction = "";
        while (fraction.length < precision) fraction += "0";
        override += delim + fraction;
    }
    else {
        var fraction = String(this.acctItemOverride % divisor);
        while (fraction.length < precision) fraction = "0" + fraction;
        override = override.substring(0,override.lastIndexOf(delim)) + delim + fraction;
    }

    return override;
}


CategoryItem.prototype.getSubtotal = function() {
    var delim = "."; // fraction delimiter will eventually come from system localization
    var precision = 2; // precision (number of decimals) will eventually come from Currency table
    var divisor = Math.pow(10,precision);

    // round price*qty to stay within precision
    var subtotal = String(Math.round(this.acctItemPrice * this.orderQuantity) / divisor);

    if (subtotal.lastIndexOf(delim) < 0) {
        var fraction = "";
        while (fraction.length < precision) fraction += "0";
        subtotal += delim + fraction;
    }
    else {
        // round price*qty to stay within precision
        var fraction = String(Math.round(this.acctItemPrice * this.orderQuantity) % divisor);
        while (fraction.length < precision) fraction = "0" + fraction;
        subtotal = subtotal.substring(0,subtotal.lastIndexOf(delim)) + delim + fraction;
    }

    return subtotal;
}

CategoryItem.prototype.getItemHide = function() {
    return (this.acctItemHide <= 0 ? 0 : 1); // -1 represents unchecked and not changed
}

CategoryItem.prototype.notHidden = function() {
    return (this.acctItemHide <= 0);
}

CategoryItem.prototype.getItemUnit = function() {
    return this.acctItemUnit;
}

CategoryItem.prototype.getItemPackage = function() {
    return this.acctItemPackage;
}

CategoryItem.prototype.getItemCustomPackage = function() {
    return this.acctItemCustomPackage;
}

CategoryItem.prototype.getItemMinimumQuantity = function() {
    return this.acctItemMinQty;
}

CategoryItem.prototype.getItemUnitsPerPackage = function() {
    //
    // Note that the following calculation is very similar to the currency calculations
    // above with the exception that the decimals do not get padded out any further
    // than necessary and we do not need to build up the decimal portion at all.
    //
    var precision = 2; // precision (number of decimals) set abitrarily, see task #1905
    var divisor = Math.pow(10,precision);

    return String(this.acctItemUnitsPerPackage / divisor);
}

CategoryItem.prototype.getItemOpenAvailability = function() {
	return this.acctItemOpenAvailability;
}

CategoryItem.prototype.getItemUnitsAvailable = function() {
	return this.acctItemUnitsAvailable;
}

CategoryItem.prototype.getItemCertificationIds = function() {
	return this.acctItemCertIds;
}

CategoryItem.prototype.hasItemCertificationId = function(id) {
    var arrIds = String(this.acctItemCertIds).split(",");
    for (var i = 0; i < arrIds.length; i++) {
        if (arrIds[i] == id) {
            return true;
        }
    }
    return false;
}

CategoryItem.prototype.getItemCertificationNames = function() {
	return this.acctItemCertNames;
}

CategoryItem.prototype.setOrderQuantity = function(qty) {
    this.orderQuantity = parseInt(qty);
}

CategoryItem.prototype.getOrderQuantity = function() {
    return this.orderQuantity;
}

CategoryItem.prototype.allowSeconds = function() {
    return (this.orderAllowSeconds != 0);
}

CategoryItem.prototype.allowAlternateSuppliers = function() {
    return (this.orderAltSuppliers != 0);
}

CategoryItem.prototype.setOrderSchedule = function(sched) {
    this.orderSchedule = String(sched);
}

CategoryItem.prototype.getOrderSchedule = function() {
    return this.orderSchedule;
}

CategoryItem.prototype.getOrderScheduleType = function() {
    return this.orderSchedule.substring(0,1); // returns d or p for delivery or pickup (format is d#s# or p#s#)
}

CategoryItem.prototype.getOrderScheduleId = function() {
    return this.orderSchedule.substring(1, this.orderSchedule.indexOf('s')); // the schedule id
}

CategoryItem.prototype.getOrderScheduleDate = function() {
    return this.orderSchedule.substring(this.orderSchedule.indexOf('s')+1); // the date of the schedule
}


CategoryItem.prototype.getLeft = function() {
    return this.left;
}

CategoryItem.prototype.setLeft = function(left) {
    return this.left = left;
}

CategoryItem.prototype.getTop = function() {
    return this.top;
}

CategoryItem.prototype.setTop = function(top) {
    return this.top = top;
}


CategoryItem.prototype.clone = function(that) {

    this.parentName = that.parentName;

    this.parentId = that.parentId;
    this.catItemId = that.catItemId;
    this.catItemName = that.catItemName;
    this.catItemDesc = that.catItemDesc;
    this.catItemRetired = that.catItemRetired;
    this.catItemLevel = that.catItemLevel;
    this.catItemOrder = that.catItemOrder;

    this.acctItemStatus = that.acctItemStatus;
    this.acctItemDesc = that.acctItemDesc;
    this.acctItemSKU = that.acctItemSKU;

    this.acctItemPrice = that.acctItemPrice;
    this.acctItemMarkup = that.acctItemMarkup;
    this.acctItemRoundup = that.acctItemRoundup;
    this.acctItemOverride = that.acctItemOverride;
    this.acctItemHide = that.acctItemHide;

    this.acctItemUnit = that.acctItemUnit;
    this.acctItemPackage = that.acctItemPackage;
    this.acctItemCustomPackage = that.acctItemCustomPackage;
    this.acctItemMinQty = that.acctItemMinQty;
    this.acctItemUnitsPerPackage = that.acctItemUnitsPerPackage;

    this.acctItemUnitsAvailable = that.acctItemUnitsAvailable;
    this.acctItemCertIds = that.acctItemCertIds;
    this.acctItemCertNames = that.acctItemCertNames;

}

// end categoryitem.js
