// Copyright 1996, Marimba Inc. All Rights Reserved.
// @(#)SamegameApplication.java, 1.14, 11/19/96

package samegame;

import java.net.*;
import java.io.*;
import java.awt.*;
import java.util.*;

import marimba.channel.*;
import marimba.gui.*;
import marimba.io.*;
import marimba.desktop.*;
import marimba.persist.*;

/**
 * A helper class for creating channel applications. This
 * class creates and shows, and destroys an AWT frame as
 * the base frame of the application.
 *
 * @author      Carl W. Haynes III
 * @version     1.14, 11/19/96
 */
public class SamegameApplication extends ApplicationPlayerFrame implements Application {

    /** high scores */
    HighScoreManager highScores;

    AppMenuBar mb;
    Menu fileMenu;
    Menu editMenu;
    Menu optionsMenu;
    AppMenuItem undoMenu = null;
    AppMenuItem redoMenu = null;

    static final String highScoreFile = "hsm.txt";
    static final String stateFile = "state.txt";

    /**
     * Create a new ApplicationPlayerFrame.
     */
    public SamegameApplication() {
	super();
	setMenuBar(mb = new AppMenuBar());
	fileMenu = new Menu("File");
	mb.add(fileMenu);
	fileMenu.add(new AppMenuItem("New Game", null, "New Game", "New Game"));
	fileMenu.add(new AppMenuItem("-", "-", "-", "-"));
	fileMenu.add(new AppMenuItem("Quit", null, "Quit", "Quit"));
	
	mb.add(editMenu = new Menu("Edit"));
	editMenu.add(undoMenu = new AppMenuItem("Undo", null, "Undo", "Undo"));
	editMenu.add(redoMenu = new AppMenuItem("Redo", null, "Redo", "Redo"));
	
	mb.add(optionsMenu = new Menu("Options"));
	optionsMenu.add(new AppMenuItem("High Scores...", null, "High Scores", "High Scores"));

	mb.add(optionsMenu = new Menu("Help"));
	optionsMenu.add(new AppMenuItem("Playing SameGame...", null, "Playing SameGame", "Playing SameGame"));
	optionsMenu.add(new AppMenuItem("About SameGame...", null, "About SameGame", "About SameGame"));
    }

    /**
     * Initialize the Channel.
     */
    public void start() {
        super.start();
	highScores.setContext(context);
	highScores.readLocalHighScores();
	highScores.readGlobalHighScores();
	readState();
	show();
    }

    /**
      * returns current Highscore manager
      */
    public HighScoreManager getHighScoreManager() {
	return(highScores);
    }

    public void showHighScoreList() {
	try {
	    new HighScoreListFrame(new URL(context.getBase(),
					    "highscorelist.gui"),
				    highScores,
				    null);
	}
	catch(MalformedURLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Destroy the Channel.
     */
    public void stop() {
	highScores.writeLocalHighScores();
	writeHighScores();
	writeState();
	hide();
	dispose();
    }


    
    /**
     * This methods is called by the system to initialize the Application.
     * It will try to find and load the 'presentation' specified in
     * the channel properties.
     */
    public void setContext(ApplicationContext context) {
        super.setContext(context);

	File f = new File(context.getDataDirectory(), highScoreFile);
	if (f.exists()) {
	    try {
		FastInputStream fis = new FastInputStream(f);
		highScores = (HighScoreManager)fis.readObject();
		fis.close();
	    }
	    catch(IOException e) {
		e.printStackTrace();
		highScores = new HighScoreManager();
	    }
	}
	else
	    highScores = new HighScoreManager();
    }

    /**
     * Updated data is available. By default, if property "update.action"
     * is "restart", then the entire channel is restarted (with the new
     * updated data).
     */
    public void notifyAvailable(String dir) {
	if ("restart".equals(context.getParameter("update.action"))) {
	    context.restart();
	}
	
	// force the install
	context.installData(dir);
    }
    
    /**
     * Data has been installed. Called to notify the application
     * that new data has been installed. This is only called if
     * the application explicitly requests installation of new data
     * using installChannel().
     */
    public void notifyInstall(String dir) {
	// handle new top 10 scores here
	highScores.readGlobalHighScores();
    }

    /**
     * Event handler for Window Management events: Asks for the
     * channel to be stopped (and soon destroyed) when the presentation
     * is closed.
     */
    public boolean handleEvent(Event evt) {
	switch (evt.id) {
	  case Event.ACTION_EVENT:
	    if ((""+evt.arg).equalsIgnoreCase("quit")) {
		context.stop();
	    }
	    else if ((""+evt.arg).equalsIgnoreCase("high scores...")) {
		showHighScoreList();
	    }
	    else if ((""+evt.arg).equalsIgnoreCase("New Game")) {
		((SameGameWidget)util.getPresentation().getWidget("samegame")).newGame();
	    }
	    else if ((""+evt.arg).equalsIgnoreCase("Undo")) {
		((SameGameWidget)util.getPresentation().getWidget("samegame")).undoButton();
	    }
	    else if ((""+evt.arg).equalsIgnoreCase("Redo")) {
		((SameGameWidget)util.getPresentation().getWidget("samegame")).redoButton();
	    }
	    else if ((""+evt.arg).equalsIgnoreCase("Playing SameGame...")) {
		try {
		    PlayerFrame pf = new PlayerFrame();
		    pf.util.setPresentation(new URL(context.getBase(), "help.gui"));
		    pf.show();
		}
		catch(MalformedURLException e) {
		    e.printStackTrace();
		}
	    }
	    else if ((""+evt.arg).equalsIgnoreCase("About SameGame...")) {
		try {
		    PlayerFrame pf = new PlayerFrame();
		    pf.util.setPresentation(new URL(context.getBase(), "about.gui"));
		    pf.show();
		}
		catch(MalformedURLException e) {
		    e.printStackTrace();
		}
	    }
	    return true;

	  case DATA_AVAILABLE_EVENT:
	    notifyAvailable((String)evt.arg);
	    return true;
	    
	  case DATA_INSTALLED_EVENT:
    	    notifyInstall((String)evt.arg);
	    return true;

	  case Event.WINDOW_DESTROY:
	    context.stop();
	    return true;
	}
	return super.handleEvent(evt);
    }


    /**
     * able/disable undo menu
     */
    public void setUndoMenuState(boolean state) {
	undoMenu.enable(state);
    }

    /**
     * able/disable redo menu
     */
    public void setRedoMenuState(boolean state) {
	redoMenu.enable(state);
    }


    /**
     * write high scores to disk
     */
    public void writeHighScores() {
	File f = new File(context.getDataDirectory(), highScoreFile);
	try {
	    FastOutputStream fis = new FastOutputStream(f);
	    fis.writeObject(highScores);
	    fis.close();
	}
	catch(IOException e) {
	    e.printStackTrace();
	    highScores = new HighScoreManager();
	}
    }

    /** 
     * write current state to disk
     */
    public void writeState() {
	File f = new File(context.getDataDirectory(), stateFile);
	try {
	    FastOutputStream fos = new FastOutputStream(f);
	    ((SameGameWidget)util.getPresentation().getWidget("samegame")).writeState(fos);
	    fos.close();
	}
	catch(IOException e) {
	    e.printStackTrace();
	}
    }

    /** 
     * read last state from disk
     */
    public void readState() {
	File f = new File(context.getDataDirectory(), stateFile);
	if (f.exists() == false) {
	    ((SameGameWidget)util.getPresentation().getWidget("samegame")).newGame();
	    return;
	}

	try {
	    FastInputStream fis = new FastInputStream(f);
	    ((SameGameWidget)util.getPresentation().getWidget("samegame")).readState(fis);
	    fis.close();
	}
	catch(IOException e) {
	    e.printStackTrace();
	}
    }

    /**
     * for debugging
     */
    public void DebugStr(String s) {
        System.out.println(this.getClass().getName() + ": " + s);
    }
    
}

