/**
* Copyright (c) 2005-2017, KoLmafia development team
* http://kolmafia.sourceforge.net/
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* [1] Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* [2] Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* [3] Neither the name "KoLmafia" nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package net.sourceforge.kolmafia.persistence;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import net.java.dev.spellcast.utilities.LockableListModel;
import net.sourceforge.kolmafia.AdventureResult;
import net.sourceforge.kolmafia.CoinmasterData;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.KoLConstants.CraftingType;
import net.sourceforge.kolmafia.StaticEntity;
import net.sourceforge.kolmafia.objectpool.Concoction;
import net.sourceforge.kolmafia.objectpool.ConcoctionPool;
import net.sourceforge.kolmafia.objectpool.IntegerPool;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.CoinMasterPurchaseRequest;
import net.sourceforge.kolmafia.request.PurchaseRequest;
import net.sourceforge.kolmafia.utilities.FileUtilities;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class CoinmastersDatabase
{
// Map from Integer( itemId ) -> CoinMasterPurchaseRequest
public static final HashMap<Integer, CoinMasterPurchaseRequest> COINMASTER_ITEMS = new HashMap<Integer, CoinMasterPurchaseRequest>();
// Map from String -> LockableListModel
public static final TreeMap<String,LockableListModel<AdventureResult>> items = new TreeMap();
// Map from String -> LockableListModel
public static final TreeMap<String,LockableListModel<AdventureResult>> buyItems = new TreeMap();
// Map from String -> Map from Integer -> Integer
public static final TreeMap<String, Map<Integer, Integer>> buyPrices = new TreeMap<String, Map<Integer, Integer>>();
// Map from String -> LockableListModel
public static final TreeMap<String,LockableListModel<AdventureResult>> sellItems = new TreeMap();
// Map from String -> Map from Integer -> Integer
public static final TreeMap<String, Map<Integer, Integer>> sellPrices = new TreeMap<String, Map<Integer, Integer>>();
// Map from String -> Map from Integer -> Integer
public static final TreeMap<String, Map<Integer, Integer>> itemRows = new TreeMap<String, Map<Integer, Integer>>();
public static final LockableListModel<AdventureResult> getItems( final String key )
{
return CoinmastersDatabase.items.get( key );
}
public static final LockableListModel<AdventureResult> getBuyItems( final String key )
{
return CoinmastersDatabase.buyItems.get( key );
}
public static final Map<Integer, Integer> getBuyPrices( final String key )
{
return CoinmastersDatabase.buyPrices.get( key );
}
public static final LockableListModel<AdventureResult> getSellItems( final String key )
{
return CoinmastersDatabase.sellItems.get( key );
}
public static final Map<Integer, Integer> getSellPrices( final String key )
{
return CoinmastersDatabase.sellPrices.get( key );
}
public static final Map<Integer, Integer> getRows( final String key )
{
return CoinmastersDatabase.itemRows.get( key );
}
public static final Map<Integer, Integer> getOrMakeRows( final String key )
{
return CoinmastersDatabase.getOrMakeMap( key, CoinmastersDatabase.itemRows );
}
public static final LockableListModel<AdventureResult> getNewList()
{
return new LockableListModel<AdventureResult>();
}
public static final Map<Integer, Integer> getNewMap()
{
return new TreeMap<Integer, Integer>();
}
private static final LockableListModel<AdventureResult> getOrMakeList( final String key, final Map<String,LockableListModel<AdventureResult>> map )
{
LockableListModel<AdventureResult> retval = map.get( key );
if ( retval == null )
{
retval = CoinmastersDatabase.getNewList();
map.put( key, retval );
}
return retval;
}
private static final Map<Integer, Integer> getOrMakeMap( final String key, final Map<String, Map<Integer, Integer>> map )
{
Map<Integer, Integer> retval = (Map<Integer, Integer>) map.get( key );
if ( retval == null )
{
retval = CoinmastersDatabase.getNewMap();
map.put( key, retval );
}
return retval;
}
public static final Map<Integer, Integer> invert( final Map<Integer, Integer> map )
{
Map<Integer, Integer> retval = new TreeMap<Integer, Integer>();
for ( Entry<Integer, Integer> entry : map.entrySet() )
{
retval.put(entry.getValue(), entry.getKey());
}
return retval;
}
static
{
BufferedReader reader = FileUtilities.getVersionedReader( "coinmasters.txt", KoLConstants.COINMASTERS_VERSION );
String[] data;
while ( ( data = FileUtilities.readData( reader ) ) != null )
{
if ( data.length < 4 )
{
continue;
}
String master = data[ 0 ];
String type = data[ 1 ];
int price = StringUtilities.parseInt( data[ 2 ] );
Integer iprice = IntegerPool.get( price );
AdventureResult item = AdventureResult.parseItem( data[ 3 ], true );
Integer iitemId = IntegerPool.get( item.getItemId() );
Integer row = null;
if ( data.length > 4 )
{
String[] extra = data[ 4 ].split( "\\s,\\s" );
for ( String extra1 : extra )
{
if ( extra1.startsWith( "ROW" ) )
{
row = IntegerPool.get( StringUtilities.parseInt( data[ 4 ].substring( 3 ) ) );
Map<Integer, Integer> rowMap = CoinmastersDatabase.getOrMakeMap( master, CoinmastersDatabase.itemRows );
rowMap.put( iitemId, row );
}
}
}
if ( type.equals( "buy" ) )
{
LockableListModel<AdventureResult> list = CoinmastersDatabase.getOrMakeList( master, CoinmastersDatabase.buyItems );
list.add( item.getInstance( CoinmastersDatabase.purchaseLimit( iitemId ) ) );
Map<Integer, Integer> map = CoinmastersDatabase.getOrMakeMap( master, CoinmastersDatabase.buyPrices );
map.put( iitemId, iprice );
}
else if ( type.equals( "sell" ) )
{
LockableListModel<AdventureResult> list = CoinmastersDatabase.getOrMakeList( master, CoinmastersDatabase.sellItems );
list.add( item );
Map<Integer, Integer> map = CoinmastersDatabase.getOrMakeMap( master, CoinmastersDatabase.sellPrices );
map.put( iitemId, iprice );
}
}
try
{
reader.close();
}
catch ( Exception e )
{
// This should not happen. Therefore, print
// a stack trace for debug purposes.
StaticEntity.printStackTrace( e );
}
}
private static final int purchaseLimit( final int itemId )
{
switch ( itemId )
{
case ItemPool.ZEPPELIN_TICKET:
case ItemPool.TALES_OF_DREAD:
case ItemPool.BRASS_DREAD_FLASK:
case ItemPool.SILVER_DREAD_FLASK:
return 1;
}
return PurchaseRequest.MAX_QUANTITY;
}
public static final int getPrice( final int itemId, final Map prices )
{
if ( itemId == -1 )
{
return 0;
}
Integer price = (Integer) prices.get( (Integer) itemId );
return ( price == null ) ? 0 : price.intValue();
}
public static final boolean availableItem( final int itemId )
{
switch( itemId )
{
case ItemPool.CRIMBO_CAROL_V1:
return KoLCharacter.getClassType().equals( KoLCharacter.SEAL_CLUBBER );
case ItemPool.CRIMBO_CAROL_V2:
return KoLCharacter.getClassType().equals( KoLCharacter.TURTLE_TAMER );
case ItemPool.CRIMBO_CAROL_V3:
return KoLCharacter.getClassType().equals( KoLCharacter.PASTAMANCER );
case ItemPool.CRIMBO_CAROL_V4:
return KoLCharacter.getClassType().equals( KoLCharacter.SAUCEROR );
case ItemPool.CRIMBO_CAROL_V5:
return KoLCharacter.getClassType().equals( KoLCharacter.DISCO_BANDIT );
case ItemPool.CRIMBO_CAROL_V6:
return KoLCharacter.getClassType().equals( KoLCharacter.ACCORDION_THIEF );
case ItemPool.BLACK_BARTS_BOOTY:
return Preferences.getInteger( "pirateSwagger" ) >= Preferences.getInteger( "blackBartsBootyCost" );
case ItemPool.HOLIDAY_FUN_BOOK:
return Preferences.getInteger( "holidaySwagger" ) >= Preferences.getInteger( "holidayHalsBookCost" );
case ItemPool.ANTAGONISTIC_SNOWMAN_KIT:
return Preferences.getInteger( "iceSwagger" ) >= Preferences.getInteger( "antagonisticSnowmanKitCost" );
case ItemPool.MAP_TO_KOKOMO:
return Preferences.getInteger( "drunkenSwagger" ) >= Preferences.getInteger( "mapToKokomoCost" );
case ItemPool.ESSENCE_OF_BEAR:
return Preferences.getInteger( "bearSwagger" ) >= Preferences.getInteger( "essenceOfBearCost" );
case ItemPool.MANUAL_OF_NUMBEROLOGY:
return Preferences.getInteger( "numericSwagger" ) >= Preferences.getInteger( "manualOfNumberologyCost" );
case ItemPool.ROM_OF_OPTIMALITY:
return Preferences.getInteger( "optimalSwagger" ) >= Preferences.getInteger( "ROMOfOptimalityCost" );
case ItemPool.SCHOOL_OF_HARD_KNOCKS_DIPLOMA:
return Preferences.getInteger( "schoolSwagger" ) >= Preferences.getInteger( "schoolOfHardKnocksDiplomaCost" );
}
return true;
}
public static final void clearPurchaseRequests( CoinmasterData data )
{
// Clear all purchase requests for a particular Coin Master
Iterator it = CoinmastersDatabase.COINMASTER_ITEMS.values().iterator();
while ( it.hasNext() )
{
CoinMasterPurchaseRequest request = (CoinMasterPurchaseRequest) it.next();
if ( request.getData() == data )
{
it.remove();
}
}
}
public static final void registerPurchaseRequest( final CoinmasterData data, final AdventureResult item, final AdventureResult price )
{
int itemId = item.getItemId();
int quantity = item.getCount();
// Register a purchase request
CoinMasterPurchaseRequest request = new CoinMasterPurchaseRequest( data, item, price );
CoinmastersDatabase.COINMASTER_ITEMS.put( IntegerPool.get( itemId ), request );
// Register this in the Concoction for the item
// Special case: ten-leaf-clovers are limited
if ( itemId == ItemPool.TEN_LEAF_CLOVER )
{
return;
}
Concoction concoction = ConcoctionPool.get( itemId );
if ( concoction == null )
{
return;
}
// If we can create it any other way, prefer that method
if ( concoction.getMixingMethod() == CraftingType.NOCREATE )
{
concoction.setMixingMethod( CraftingType.COINMASTER );
concoction.addIngredient( price );
}
// If we can create this only via a coin master trade, save request
if ( concoction.getMixingMethod() == CraftingType.COINMASTER )
{
concoction.setPurchaseRequest( request );
}
}
public static final CoinMasterPurchaseRequest getPurchaseRequest( final int itemId )
{
Integer id = IntegerPool.get( itemId );
CoinMasterPurchaseRequest request = (CoinMasterPurchaseRequest) CoinmastersDatabase.COINMASTER_ITEMS.get( id );
if ( request == null )
{
return null;
}
request.setLimit( request.affordableCount() );
request.setCanPurchase();
return request;
}
public static final boolean contains( final int itemId )
{
return CoinmastersDatabase.contains( itemId, true );
}
public static final boolean contains( final int itemId, boolean validate )
{
PurchaseRequest item = CoinmastersDatabase.getPurchaseRequest( itemId );
return item != null && ( !validate || item.canPurchase() );
}
}