/**
	* Retrieves an array of category data for the specified category
	*
	* Elements use the category ID as their key. Each category has the following fields:
	* 	name 					=> The category name (string)
	* 	category_id				=> The ID of the category (int)
	* 	parent_id				=> The ID of the parent category (int)
	* 	is_leaf					=> Is this a leaf category? (bool)
	* 	lot_size_enabled		=> Are lot sizes allowed on listings in this category? (bool)
	* 	best_offer_enabled 		=> Are best offers allowed on listings? (bool)
	* 	reserve_price_allowed	=> Are reserve prices allowed on listings? (bool)
	* 	minimum_reserve_price 	=> The minimum reserve price for listings. (double)
	*
	* @param int $parentCategoryId The parent category to retrieve child categories from.
	* @param int $levelLimit The maximum depth of the heirarchy to retrieve.
	* @param int $siteId The eBay site to get categories for
	* @return array An array of category data in the format described.
	*/
	public static function getCategories($parentCategoryId, $levelLimit, $siteId)
	{
		ISC_ADMIN_EBAY_OPERATIONS::setSiteId($siteId);

		$currentCategoryVersion = 0;
		$cacheCategoryVersion = 0;
		$categories = array();

		$keystore = Interspire_KeyStore::instance();
		$versionKey = 'ebay:categories:version:site:' . $siteId;
		$updateKey = 'ebay:categories:last_update:site:' . $siteId;

		// get the cached version and last update time
		$cacheVersion = $keystore->get($versionKey);
		$cacheLastUpdate = $keystore->get($updateKey);

		if ($cacheVersion !== false && $cacheLastUpdate !== false) {
			$cacheCategoryVersion = $cacheVersion;

			// use the cached version as the current version if it was retrieved from ebay less than 10 minutes ago
			if ($cacheLastUpdate > (time() - 600)) {
				$currentCategoryVersion = $cacheCategoryVersion;
			}
		}

		if (empty($currentCategoryVersion)) {
			// retrieve the latest category version from ebay
			$currentCategoryVersion = ISC_ADMIN_EBAY_OPERATIONS::getCategoryVersion();

			// update our cached version
			$keystore->set($versionKey, $currentCategoryVersion);
			$keystore->set($updateKey, time());
		}

		// is our category heirarchy out of date?
		if ($currentCategoryVersion != $cacheCategoryVersion) {
			// lets nuke off our locally stored categories
			$GLOBALS['ISC_CLASS_DB']->DeleteQuery('ebay_categories', 'WHERE ebay_site_id = ' . $siteId);
		}

		// fetch categories from the database if they exist
		$query = '
			SELECT
				*
			FROM
				[|PREFIX|]ebay_categories
			WHERE
				parent_id = ' . $parentCategoryId . ' AND
				ebay_site_id = ' . $siteId . '
			ORDER BY
				name
		';
		$res = $GLOBALS['ISC_CLASS_DB']->Query($query);

		if ($GLOBALS['ISC_CLASS_DB']->CountResult($res)) {
			while ($categoryRow = $GLOBALS['ISC_CLASS_DB']->Fetch($res)) {
				$categories[$categoryRow['category_id']] = $categoryRow;
			}

			return $categories;
		}

		// retrieve categories from the API
		$categoriesXML = ISC_ADMIN_EBAY_OPERATIONS::getCategories($levelLimit, $parentCategoryId);

		if ((int)$categoriesXML->CategoryCount == 0) {
			return false;
		}

		// are reserved prices allowed (site-wide level)
		$reservePriceAllowed = (bool)$categoriesXML->ReservePriceAllowed;

		$categories = array();
		foreach($categoriesXML->CategoryArray->Category as $categoryInfo) {
			// skip categories not on the level we've requested (ie. the parent category) and virtual categories as they don't allow listing
			if ((int)$categoryInfo->CategoryLevel != $levelLimit || (bool)$categoryInfo->Virtual) {
				continue;
			}

			$categoryReservedPriceAllowed = $reservePriceAllowed;

			// is this category overriding the reserve price allowed? toggle the site-side setting.
			if (isset($categoryInfo->ORPA)) {
				$categoryReservedPriceAllowed = !$categoryReservedPriceAllowed;
			}

			$newCategory = array(
				'name' 					=> (string)$categoryInfo->CategoryName,
				'category_id'			=> (int)$categoryInfo->CategoryID,
				'parent_id'				=> $parentCategoryId,
				'ebay_site_id'			=> $siteId,
				'is_leaf' 				=> isset($categoryInfo->LeafCategory),
				'lot_size_enabled'		=> !isset($categoryInfo->LSD),
				'best_offer_enabled'	=> isset($categoryInfo->BestOfferEnabled),
				'reserve_price_allowed'	=> $categoryReservedPriceAllowed,
				'minimum_reserve_price' => (double)$categoryInfo->MinimumReservePrice
			);

			$categories[(int)$categoryInfo->CategoryID] = $newCategory;

			// add the category to the database
			$GLOBALS['ISC_CLASS_DB']->InsertQuery('ebay_categories', $newCategory);
		}

		return $categories;
	}