package rabbitescape.ui.text;
import java.io.IOException;
import java.util.Stack;
import static rabbitescape.engine.util.Util.*;
import static rabbitescape.engine.i18n.Translation.*;
import rabbitescape.engine.CompletedLevelWinListener;
import rabbitescape.engine.LevelWinListener;
import rabbitescape.engine.MultiLevelWinListener;
import rabbitescape.engine.config.Config;
import rabbitescape.engine.config.TapTimer;
import rabbitescape.engine.err.RabbitEscapeException;
import rabbitescape.engine.menu.AboutText;
import rabbitescape.engine.menu.ByNameConfigBasedLevelsCompleted;
import rabbitescape.engine.menu.LevelMenuItem;
import rabbitescape.engine.menu.LevelsCompleted;
import rabbitescape.engine.menu.LevelsList;
import rabbitescape.engine.menu.LoadLevelsList;
import rabbitescape.engine.menu.Menu;
import rabbitescape.engine.menu.MenuDefinition;
import rabbitescape.engine.menu.MenuItem;
import rabbitescape.engine.menu.MenuItem.Type;
import rabbitescape.engine.util.FileSystem;
public class TextMenu
{
public static class InputError extends RabbitEscapeException
{
public static final long serialVersionUID = 1L;
public InputError( Throwable e )
{
super( e );
}
}
public static class UnknownMenuItemType extends RabbitEscapeException
{
public static final long serialVersionUID = 1L;
public final String name;
public final Type type;
public UnknownMenuItemType( MenuItem item )
{
this.name = item.name;
this.type = item.type;
}
}
private final FileSystem fs;
private final Terminal terminal;
private final LevelsList levelsList;
private final LevelsCompleted levelsCompleted;
private final Stack<Menu> stack = new Stack<Menu>();
public TextMenu( FileSystem fs, Terminal terminal, Config config )
{
this.fs = fs;
this.terminal = terminal;
this.levelsList = LoadLevelsList.load( MenuDefinition.allLevels );
this.levelsCompleted = new ByNameConfigBasedLevelsCompleted(
config, levelsList );
}
public void run()
{
Menu menu = MenuDefinition.mainMenu(
levelsCompleted, levelsList, true );
stack.clear();
stack.push( menu );
while ( true )
{
MenuItem item = showMenu( stack.peek() );
if ( item == null || item.type == MenuItem.Type.QUIT )
{
stack.pop();
if ( stack.empty() )
{
break;
}
}
else if ( item.type == MenuItem.Type.MENU )
{
stack.push( item.menu );
}
else
{
handleTarget( item );
}
}
}
private void handleTarget( MenuItem item )
{
switch ( item.type )
{
case ABOUT:
{
about();
return;
}
case LEVEL:
{
level( item );
return;
}
default:
{
throw new UnknownMenuItemType( item );
}
}
}
private void level( MenuItem item )
{
LevelMenuItem levelItem = (LevelMenuItem)item;
new TextSingleGameEntryPoint( fs, terminal.out, terminal.locale )
.launchGame(
new String[] { levelItem.fileName },
winListeners( levelItem )
);
}
protected LevelWinListener winListeners( LevelMenuItem item )
{
return new MultiLevelWinListener(
new CompletedLevelWinListener(
item.levelsDir, item.levelNumber, levelsCompleted ),
new UpdateTextMenuLevelWinListener( this )
);
}
private void about()
{
terminal.out.println(
"\n"
+ t( AboutText.text ) + "\n"
+ "\n"
+ t( "Press Return to continue." ) + "\n"
);
readLine();
}
public MenuItem showMenu( Menu menu )
{
terminal.out.println( menu.intro + "\n" );
terminal.out.println( renderItems( menu ) );
while( true )
{
int chosenNum = readItemNum( menu.items.length );
if ( chosenNum == -1 )
{
return null;
}
else
{
MenuItem ret = menu.items[chosenNum];
if ( ret.enabled || TapTimer.matched )
{
return ret;
}
else
{
terminal.out.println( t( "That menu item is disabled." ) );
}
}
}
}
private int readItemNum( int length )
{
int num = -1;
while ( num < 0 || num > length )
{
terminal.out.print(
t(
"Enter a number (1-${max}), or 0 to go back: ",
newMap( "max", String.valueOf( length ) )
)
);
String answer = readLine();
try
{
num = Integer.parseInt( answer );
}
catch ( NumberFormatException e )
{
num = -1;
}
}
return num - 1;
}
private String readLine()
{
try
{
return terminal.in.readLine();
}
catch ( IOException e )
{
throw new InputError( e );
}
}
public static String renderItems( Menu menu )
{
StringBuilder ret = new StringBuilder();
for ( IdxObj<MenuItem> item : enumerate1( menu.items ) )
{
if ( item.object.hidden && !TapTimer.matched )
{
continue;
}
ret.append( renderItem( item.index, item.object ) );
}
return ret.toString();
}
private static String renderItem( int i, MenuItem item )
{
if ( item.enabled || TapTimer.matched )
{
return t(
"${num}. ${item}\n",
newMap(
"num", String.valueOf( i ),
"item", t( item.name, item.nameParams )
)
);
}
else
{
return t(
" ${item} (disabled)\n",
newMap(
"num", String.valueOf( i ),
"item", t( item.name, item.nameParams )
)
);
}
}
public void refreshEnabledItems()
{
Menu menu = stack.lastElement();
menu.refresh();
}
}