@VisibleForTesting
	boolean valueSearch(final int itemId, final String str)
	{
		final Matcher matcher = VALUE_SEARCH_PATTERN.matcher(str);
		if (!matcher.matches())
		{
			return false;
		}

		// Count bank items and remember it for determining item quantity
		if (itemQuantities == null)
		{
			itemQuantities = getBankItemSet();
		}

		final ItemComposition itemComposition = itemManager.getItemComposition(itemId);
		final int qty = matcher.group("individual") != null ? 1 : itemQuantities.count(itemId);
		final long gePrice = (long) itemManager.getItemPrice(itemId) * qty;
		final long haPrice = (long) itemComposition.getHaPrice() * qty;
		final boolean isPlaceholder = itemComposition.getPlaceholderTemplateId() != -1;

		long value = Math.max(gePrice, haPrice);

		final String mode = matcher.group("mode");
		if (mode != null)
		{
			switch (mode.toLowerCase())
			{
				case "qty":
					value = isPlaceholder ? 0 : qty;
					break;
				case "ge":
					value = gePrice;
					break;
				case "ha":
				case "alch":
					value = haPrice;
					break;
			}
		}

		final String op = matcher.group("op");
		if (op != null)
		{
			long compare;
			try
			{
				compare = QuantityFormatter.parseQuantity(matcher.group("num"));
			}
			catch (ParseException e)
			{
				return false;
			}

			switch (op)
			{
				case ">":
					return value > compare;
				case "<":
					return value < compare;
				case "=":
					return value == compare;
				case ">=":
					return value >= compare;
				case "<=":
					return value <= compare;
			}
		}

		final String num1 = matcher.group("num1");
		final String num2 = matcher.group("num2");
		if (num1 != null && num2 != null)
		{
			long compare1, compare2;
			try
			{
				compare1 = QuantityFormatter.parseQuantity(num1);
				compare2 = QuantityFormatter.parseQuantity(num2);
			}
			catch (ParseException e)
			{
				return false;
			}

			return compare1 <= value && compare2 >= value;
		}

		return false;
	}
@Test
	public void testValueSearch()
	{
		int itemId = ItemID.ABYSSAL_WHIP;

		ItemContainer itemContainer = mock(ItemContainer.class);
		when(itemContainer.getItems()).thenReturn(new Item[]{new Item(itemId, 30)});
		when(client.getItemContainer(InventoryID.BANK)).thenReturn(itemContainer);

		ItemComposition comp = mock(ItemComposition.class);

		// 60k HA price * 30 = 1.8m
		when(comp.getHaPrice())
			.thenReturn(60_000);

		// 400k GE Price * 30 = 12m
		when(itemManager.getItemPrice(itemId))
			.thenReturn(400_000);
		when(itemManager.getItemComposition(itemId))
			.thenReturn(comp);

		assertTrue(bankPlugin.valueSearch(itemId, ">500k"));
		assertTrue(bankPlugin.valueSearch(itemId, "< 5.5b"));
		assertTrue(bankPlugin.valueSearch(itemId, "500k - 20.6m"));

		assertTrue(bankPlugin.valueSearch(itemId, "per=400k"));
		assertTrue(bankPlugin.valueSearch(itemId, "ge per 50k - 20.6m"));
		assertTrue(bankPlugin.valueSearch(itemId, "ge per > 300k"));

		assertTrue(bankPlugin.valueSearch(itemId, "ha=1.8m"));
		assertTrue(bankPlugin.valueSearch(itemId, "ha 500k - 20.6m"));
		assertTrue(bankPlugin.valueSearch(itemId, "ha > 940k"));

		assertTrue(bankPlugin.valueSearch(itemId, "ha per=60k"));
		assertTrue(bankPlugin.valueSearch(itemId, "ha per 50k - 20.6m"));
		assertTrue(bankPlugin.valueSearch(itemId, "ha per > 9k"));

		assertTrue(bankPlugin.valueSearch(itemId, "qty=0"));
		assertTrue(bankPlugin.valueSearch(itemId, "qty<600"));

		assertFalse(bankPlugin.valueSearch(itemId, "<500k"));
		assertFalse(bankPlugin.valueSearch(itemId, "ha >2m"));
		assertFalse(bankPlugin.valueSearch(itemId, "ge > 0.02b"));
		assertFalse(bankPlugin.valueSearch(itemId, "ha per >100k"));
		assertFalse(bankPlugin.valueSearch(itemId, "ge per > 1m"));

		assertFalse(bankPlugin.valueSearch(itemId, "qty=1"));
		assertFalse(bankPlugin.valueSearch(itemId, "qty>30"));

		assertFalse(bankPlugin.valueSearch(itemId, "1000k"));
	}