/**
* 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.session;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.ModifierExpression;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.StaticEntity;
import net.sourceforge.kolmafia.objectpool.IntegerPool;
import net.sourceforge.kolmafia.persistence.EffectDatabase;
import net.sourceforge.kolmafia.persistence.HolidayDatabase;
import net.sourceforge.kolmafia.persistence.ItemDatabase;
import net.sourceforge.kolmafia.persistence.SkillDatabase;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.GenericRequest;
import net.sourceforge.kolmafia.utilities.FileUtilities;
public abstract class ConsequenceManager
{
private static final HashMap<String, Consequence> itemDescs = new HashMap<String, Consequence>();
private static final HashMap<String, Consequence> effectDescs = new HashMap<String, Consequence>();
private static final HashMap<String, Consequence> skillDescs = new HashMap<String, Consequence>();
private static final ArrayList<String> descriptions = new ArrayList<String>();
private static final HashMap<String, Consequence> monsters = new HashMap<String, Consequence>();
private static final ArrayList<Consequence> accomplishments = new ArrayList<Consequence>();
private static final Pattern GROUP_PATTERN = Pattern.compile( "\\$(\\d)" );
private static final Pattern EXPR_PATTERN = Pattern.compile( "\\[(.+?)\\]" );
static
{
BufferedReader reader = FileUtilities.getVersionedReader( "consequences.txt", KoLConstants.CONSEQUENCES_VERSION );
String[] data;
// Format is: type / spec / regex / action...
while ( ( data = FileUtilities.readData( reader ) ) != null )
{
if ( data.length < 4 )
{
continue;
}
Pattern patt;
try
{
patt = Pattern.compile( data[ 2 ] );
}
catch ( PatternSyntaxException e )
{
RequestLogger.printLine( "Consequence " + data[ 0 ] + "/" + data[ 1 ] + ": " + e );
continue;
}
ConsequenceManager.addConsequence( new Consequence( data, patt ) );
}
try
{
reader.close();
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
}
public static void addConsequence( Consequence cons )
{
String type = cons.getType();
String spec = cons.getSpec();
if ( type.equals( "DESC_ITEM" ) )
{
String key = ItemDatabase.getDescriptionId( ItemDatabase.getItemId( spec ) );
if ( key == null )
{
RequestLogger.printLine( "Unknown DESC_ITEM consequence: " + spec );
}
else
{
cons.register( ConsequenceManager.itemDescs, key );
ConsequenceManager.descriptions.add( "desc_item.php?whichitem=" + key );
}
}
else if ( type.equals( "DESC_SKILL" ) )
{
int id = SkillDatabase.getSkillId( spec );
if ( id == -1 )
{
RequestLogger.printLine( "Unknown DESC_SKILL consequence: " + spec );
}
else
{
Integer key = IntegerPool.get( id );
cons.register( ConsequenceManager.skillDescs, key );
ConsequenceManager.descriptions.add( "desc_skill.php?whichskill=" + id + "&self=true" );
}
}
else if ( type.equals( "DESC_EFFECT" ) )
{
String key = EffectDatabase.getDescriptionId( EffectDatabase.getEffectId( spec ) );
if ( key == null )
{
RequestLogger.printLine( "Unknown DESC_EFFECT consequence: " + spec );
}
else
{
cons.register( ConsequenceManager.effectDescs, key );
ConsequenceManager.descriptions.add( "desc_effect.php?whicheffect=" + key );
}
}
else if ( type.equals( "MONSTER" ) )
{
String key = spec;
cons.register( ConsequenceManager.monsters, key );
}
else if ( type.equals( "QUEST_LOG" ) )
{
String key = spec;
cons.register( ConsequenceManager.accomplishments );
}
else
{
RequestLogger.printLine( "Unknown consequence type: " + type );
}
}
public static void parseSkillDesc( int id, String responseText )
{
Consequence cons = ConsequenceManager.skillDescs.get( IntegerPool.get( id ) );
if ( cons != null )
{
cons.test( responseText );
}
}
public static void parseItemDesc( String id, String responseText )
{
Consequence cons = ConsequenceManager.itemDescs.get( id );
if ( cons != null )
{
cons.test( responseText );
}
}
public static void parseEffectDesc( String id, String responseText )
{
Consequence cons = ConsequenceManager.effectDescs.get( id );
if ( cons != null )
{
cons.test( responseText );
}
}
public static void updateOneDesc()
{
int size = ConsequenceManager.descriptions.size();
if ( size == 0 )
{ // this shouldn't happen...
return;
}
// getCalendarDay is good for up to 96 description items
int seq = HolidayDatabase.getCalendarDay( new Date() );
GenericRequest req = new GenericRequest( ConsequenceManager.descriptions.get( seq % size ) );
RequestThread.postRequest( req );
}
public static void parseAccomplishments( String responseText )
{
for ( Consequence cons : ConsequenceManager.accomplishments )
{
if ( cons != null )
{
cons.test( responseText );
}
}
}
public static String disambiguateMonster( String monster, String responseText )
{
Consequence cons = ConsequenceManager.monsters.get( monster );
if ( cons != null )
{
String rv = cons.test( responseText, false );
if ( rv != null )
{
return rv;
}
}
return monster;
}
private static class Consequence
{
private String[] data;
private Pattern patt;
private Consequence next;
public Consequence( String[] data, Pattern patt )
{
this.data = data;
this.patt = patt;
}
public String getType()
{
return this.data[ 0 ];
}
public String getSpec()
{
return this.data[ 1 ];
}
public Matcher matcher( CharSequence text )
{
return this.patt.matcher( text );
}
public void register( Map map, Object key )
{
this.next = (Consequence) map.get( key );
map.put( key, this );
}
public void register( List<Consequence> list )
{
list.add( this );
}
@Override
public String toString()
{
return "consequence " + this.getType() + "/" + this.getSpec();
}
public void test( CharSequence text )
{
this.test( text, true );
}
public String test( CharSequence text, boolean printText )
{
String rv = null;
if ( this.next != null )
{
rv = this.next.test( text, printText );
if ( rv != null && !printText )
{
return rv;
}
}
else if ( Preferences.getBoolean( "debugConsequences" ) )
{
RequestLogger.printLine( "Testing " + this );
}
Matcher m = this.matcher( text );
if ( m.find() )
{
for ( int i = 3; i < this.data.length; ++i )
{
String res = this.fireAction( data[ i ], m );
if ( res != null )
{
rv = res;
if ( printText )
{
RequestLogger.printLine( res );
}
}
}
}
return rv;
}
private String fireAction( String action, Matcher match )
{
StringBuffer buff = new StringBuffer();
Matcher m = ConsequenceManager.GROUP_PATTERN.matcher( action );
if ( m.find() )
{
do
{
int group = Integer.parseInt( m.group( 1 ) );
if ( group < 0 || group > match.groupCount() )
{
RequestLogger.printLine( "Bad group number in " + this );
}
else
{
String grout = match.group( group );
if ( grout == null )
{
grout = "";
}
m.appendReplacement( buff, grout );
}
} while ( m.find() );
m.appendTail( buff );
action = buff.toString();
}
m = ConsequenceManager.EXPR_PATTERN.matcher( action );
if ( m.find() )
{
buff.setLength( 0 );
do
{
double val = ModifierExpression.getInstance( m.group( 1 ), "consequence" ).eval();
if ( val == (int) val )
{ // Avoid decimal point for integer values
m.appendReplacement( buff, String.valueOf( (int) val ) );
}
else
{
m.appendReplacement( buff, String.valueOf( val ) );
}
} while ( m.find() );
m.appendTail( buff );
action = buff.toString();
}
if ( Preferences.getBoolean( "debugConsequences" ) )
{
RequestLogger.printLine( "Firing action: " + action );
}
int pos;
if ( action.startsWith( "\"" ) )
{
pos = action.length() - (action.endsWith( "\"" ) ? 1 : 0);
return action.substring( 1, pos );
}
pos = action.indexOf( '=' );
if ( pos != -1 )
{ String setting = action.substring( 0, pos ).trim();
String value = action.substring( pos + 1 ).trim();
if ( value.equals( "ascensions" ) ) value = String.valueOf( KoLCharacter.getAscensions() );
Preferences.setString( setting, value );
return null;
}
// Assume anything that didn't match a specific action type is text.
return action;
}
}
}