/**
* 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.request;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.kolmafia.AdventureResult;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.persistence.ConcoctionDatabase;
import net.sourceforge.kolmafia.persistence.ItemDatabase;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.session.InventoryManager;
import net.sourceforge.kolmafia.utilities.AdventureResultArray;
import net.sourceforge.kolmafia.utilities.StringUtilities;
import org.json.JSONException;
import org.json.JSONObject;
public class ClosetRequest
extends TransferItemRequest
{
private int moveType;
public static final int REFRESH = 0;
public static final int INVENTORY_TO_CLOSET = 1;
public static final int CLOSET_TO_INVENTORY = 2;
public static final int MEAT_TO_CLOSET = 3;
public static final int MEAT_TO_INVENTORY = 4;
public static final int EMPTY_CLOSET = 5;
public static void refresh()
{
// To refresh closet, we get Meat from any page
// and items from api.php
RequestThread.postRequest( new ClosetRequest( REFRESH ) );
RequestThread.postRequest( new ApiRequest( "closet" ) );
}
public static final void parseCloset( final JSONObject JSON )
{
if ( JSON == null )
{
return;
}
ArrayList<AdventureResult> items = new ArrayList<AdventureResult>();
try
{
// {"1":"1","2":"1" ... }
Iterator< ? > keys = JSON.keys();
while ( keys.hasNext() )
{
String key = (String) keys.next();
int itemId = StringUtilities.parseInt( key );
int count = JSON.getInt( key );
String name = ItemDatabase.getItemDataName( itemId );
if ( name == null )
{
// Fetch descid from api.php?what=item
// and register new item.
ItemDatabase.registerItem( itemId );
}
items.add( ItemPool.get( itemId, count ) );
}
}
catch ( JSONException e )
{
ApiRequest.reportParseError( "closet", JSON.toString(), e );
return;
}
KoLConstants.closet.clear();
KoLConstants.closet.addAll( items );
if ( InventoryManager.canUseCloset() )
{
ConcoctionDatabase.refreshConcoctions();
}
}
public ClosetRequest()
{
super( "closet.php" );
this.moveType = REFRESH;
}
public ClosetRequest( final int moveType )
{
this( moveType, new AdventureResult[ 0 ] );
this.moveType = moveType;
}
public ClosetRequest( final int moveType, final int amount )
{
this( moveType, new AdventureResult( AdventureResult.MEAT, amount ) );
}
public ClosetRequest( final int moveType, final AdventureResult attachment )
{
this( moveType, new AdventureResult[] { attachment } );
}
public ClosetRequest( final int moveType, final AdventureResult[] attachments )
{
super( ClosetRequest.pickURL( moveType ), attachments );
this.moveType = moveType;
// Figure out the actual URL information based on the
// different request types.
switch ( moveType )
{
case REFRESH:
// It doesn't matter which page we visit to get Meat
this.addFormField( "which", "1" );
break;
case MEAT_TO_CLOSET:
// closet.php?action=addtakeclosetmeat&addtake=add&pwd&quantity=x
this.addFormField( "action", "addtakeclosetmeat" );
this.addFormField( "addtake", "add" );
break;
case MEAT_TO_INVENTORY:
// closet.php?action=addtakeclosetmeat&addtake=take&pwd&quantity=x
this.addFormField( "action", "addtakeclosetmeat" );
this.addFormField( "addtake", "take" );
break;
case INVENTORY_TO_CLOSET:
// fillcloset.php?action=closetpush&whichitem=4511&qty=xxx&pwd&ajax=1
// fillcloset.php?action=closetpush&whichitem=4511&qty=all&pwd&ajax=1
this.addFormField( "action", "closetpush" );
this.addFormField( "ajax", "1" );
this.source = KoLConstants.inventory;
this.destination = KoLConstants.closet;
break;
case CLOSET_TO_INVENTORY:
// closet.php?action=closetpull&whichitem=4511&qty=xxx&pwd&ajax=1
// closet.php?action=closetpull&whichitem=4511&qty=all&pwd&ajax=1
this.addFormField( "action", "closetpull" );
this.addFormField( "ajax", "1" );
this.source = KoLConstants.closet;
this.destination = KoLConstants.inventory;
break;
case EMPTY_CLOSET:
// closet.php?action=pullallcloset&pwd
this.addFormField( "action", "pullallcloset" );
this.source = KoLConstants.closet;
this.destination = KoLConstants.inventory;
break;
}
}
private static String pickURL( final int moveType )
{
switch ( moveType )
{
case INVENTORY_TO_CLOSET:
case CLOSET_TO_INVENTORY:
return "inventory.php";
default:
return "closet.php";
}
}
@Override
protected boolean retryOnTimeout()
{
return true;
}
public int getMoveType()
{
return this.moveType;
}
@Override
public String getItemField()
{
return "whichitem";
}
@Override
public String getQuantityField()
{
return "qty";
}
@Override
public String getMeatField()
{
return "quantity";
}
public List getItems()
{
List itemList = new ArrayList();
if ( this.attachments == null )
{
return itemList;
}
for ( int i = 0; i < this.attachments.length; ++i )
{
itemList.add( this.attachments[ i ] );
}
return itemList;
}
@Override
public int getCapacity()
{
return 1;
}
@Override
public boolean forceGETMethod()
{
return this.moveType == INVENTORY_TO_CLOSET || this.moveType == CLOSET_TO_INVENTORY;
}
@Override
public TransferItemRequest getSubInstance( final AdventureResult[] attachments )
{
return new ClosetRequest( this.moveType, attachments );
}
@Override
public boolean parseTransfer()
{
return ClosetRequest.parseTransfer( this.getURLString(), this.responseText );
}
@Override
public void run()
{
// If it's a transfer, let TransferItemRequest handle it
super.run();
}
@Override
public void processResults()
{
switch ( this.moveType )
{
case ClosetRequest.REFRESH:
ClosetRequest.parseCloset( this.getURLString(), this.responseText );
return;
default:
super.processResults();
}
}
// Your closet contains <b>170,000,000</b> meat.
private static final Pattern CLOSETMEAT_PATTERN = Pattern.compile( "Your closet contains <b>([\\d,]+)</b> meat\\." );
public static void parseCloset( final String urlString, final String responseText )
{
if ( !urlString.startsWith( "closet.php" ) )
{
return;
}
Matcher meatInClosetMatcher = ClosetRequest.CLOSETMEAT_PATTERN.matcher( responseText );
if ( meatInClosetMatcher.find() )
{
String meatInCloset = meatInClosetMatcher.group( 1 );
KoLCharacter.setClosetMeat( StringUtilities.parseInt( meatInCloset ) );
}
}
public static final boolean parseTransfer( final String urlString, final String responseText )
{
if ( urlString.indexOf( "action" ) == -1 )
{
ClosetRequest.parseCloset( urlString, responseText );
return true;
}
boolean success = false;
if ( urlString.indexOf( "action=addtakeclosetmeat" ) != -1 )
{
// Determine how much meat is left in your closet by locating
// "Your closet contains x meat" and update the display with
// that information.
Matcher matcher = ClosetRequest.CLOSETMEAT_PATTERN.matcher( responseText );
int before = KoLCharacter.getClosetMeat();
int after = matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
KoLCharacter.setClosetMeat( after );
success = before != after;
}
else if ( urlString.indexOf( "action=closetpull" ) != -1 )
{
if ( responseText.indexOf( "You acquire" ) == -1 )
{
return false;
}
// Since "you acquire" items, they have already been
// added to inventory
TransferItemRequest.transferItems( urlString,
TransferItemRequest.ITEMID_PATTERN,
TransferItemRequest.QTY_PATTERN,
KoLConstants.closet,
null, 0 );
success = true;
}
else if ( urlString.indexOf( "action=closetpush" ) != -1 )
{
if ( responseText.indexOf( "in your closet" ) != -1 )
{
TransferItemRequest.transferItems( urlString,
TransferItemRequest.ITEMID_PATTERN,
TransferItemRequest.QTY_PATTERN,
KoLConstants.inventory,
KoLConstants.closet, 0 );
success = true;
}
}
else if ( urlString.indexOf( "action=pullallcloset" ) != -1 )
{
if ( responseText.indexOf( "taken from your closet" ) == -1 )
{
return false;
}
TransferItemRequest.transferItems(
new AdventureResultArray( KoLConstants.closet ),
KoLConstants.closet,
KoLConstants.inventory );
success = true;
}
if ( success )
{
// If we can't use the closet as to get ingredients,
// moving items in or out of inventory can affect what
// we can make.
if ( !InventoryManager.canUseCloset() )
{
ConcoctionDatabase.refreshConcoctions( true );
}
KoLCharacter.updateStatus();
}
return success;
}
public static final boolean registerRequest( final String urlString )
{
if ( !urlString.startsWith( "closet.php" ) &&
!urlString.startsWith( "fillcloset.php" ) &&
!urlString.startsWith( "inventory.php" ) )
{
return false;
}
if ( urlString.indexOf( "action=closetpull" ) != -1 )
{
return TransferItemRequest.registerRequest(
"take from closet", urlString,
TransferItemRequest.ITEMID_PATTERN,
TransferItemRequest.QTY_PATTERN,
KoLConstants.closet, 0 );
}
if ( urlString.indexOf( "action=closetpush" ) != -1 )
{
return TransferItemRequest.registerRequest(
"add to closet", urlString,
TransferItemRequest.ITEMID_PATTERN,
TransferItemRequest.QTY_PATTERN,
KoLConstants.inventory, 0 );
}
int meat = TransferItemRequest.transferredMeat( urlString, "quantity" );
String message = null;
if ( urlString.indexOf( "action=addtakeclosetmeat" ) != -1 )
{
if ( urlString.indexOf( "addtake=add" ) != -1 )
{
message = "add to closet: " + meat + " Meat";
}
else if ( urlString.indexOf( "addtake=take" ) != -1 )
{
message = "take from closet " + meat + " Meat";
}
}
if ( meat > 0 && message != null )
{
RequestLogger.updateSessionLog();
RequestLogger.updateSessionLog( message );
}
return true;
}
@Override
public boolean allowMementoTransfer()
{
return true;
}
@Override
public boolean allowUntradeableTransfer()
{
return true;
}
@Override
public boolean allowUngiftableTransfer()
{
return true;
}
@Override
public String getStatusMessage()
{
switch ( this.moveType )
{
case REFRESH:
return "Examining Meat in closet";
case INVENTORY_TO_CLOSET:
return "Placing items into closet";
case CLOSET_TO_INVENTORY:
return "Removing items from closet";
case MEAT_TO_CLOSET:
return "Placing meat into closet";
case MEAT_TO_INVENTORY:
return "Removing meat from closet";
case EMPTY_CLOSET:
return "Emptying closet";
default:
return "Unknown request type";
}
}
}