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(); } }