// Copyright 1996, Marimba Inc. All Rights Reserved.
// @(#)HighScoreManager.java, 1.7, 10/02/96

package wordsmith;

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

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

/**
 * Manages High Scores
 *
 * @author      Carl W. Haynes III
 * @version     1.7, 10/02/96
 */

public class HighScoreManager {

    /** total number of high scores kept around */
    static final int MAXHIGHSCORES = 100;

    /** data file name */
    static final String DATAFILE = "highscores.txt";

    /** types of top ten lists */
    static final int LOCAL = 0;
    static final int GLOBAL = 1;

    static final int NOT_IN_TOPTEN = -1;

    Vector localTopTen = new Vector();
    Vector globalTopTen = new Vector();

    int lowestLocalScore = 0;
    int lowestGlobalScore = 0;

    // properties
    public String lastNameUsed = "";
    public String lastEmailUsed = "";
    
    /** needed for reading files */
    ApplicationContext context = null;

    /**
      * constructor
      */
    public HighScoreManager() {
	for (int i = 0 ; i < MAXHIGHSCORES ; i++) {
	    HighScore hs = new HighScore();
	    localTopTen.addElement(hs);
	    hs = new HighScore();
	    globalTopTen.addElement(hs);
	}
    }

    /** set the application context */
    public void setContext(ApplicationContext context) {
	this.context = context;
    }

    public void readLocalHighScores() {
	clear(localTopTen);
	File f = new File(context.getDataDirectory() + DATAFILE);
	if (f.exists() == false) {
	    return;
	}
	
	try {
	    FastInputStream fis = new FastInputStream(f);
	    String s;
	    while ((s = fis.readLine()) != null) {
		add(s, LOCAL);
	    }
	    fis.close();
	}
	catch(IOException e) {
	    e.printStackTrace();
	    return;
	}
    }

    public void readGlobalHighScores() {
	clear(globalTopTen);

	if (context.channelFileExists(DATAFILE) == false) {
	    return;
	}

	// global file
	URL url = null;
	try {
	    url = new URL(context.getBase(), DATAFILE); 
	}
	catch(MalformedURLException e) {
	    e.printStackTrace();
	    return;
	}


	try {
	    FastInputStream fis = new FastInputStream(url.openStream());
	    String s;
	    while ((s = fis.readLine()) != null) {
		//DebugStr(s);
		add(s, GLOBAL);
	    }
	    fis.close();
	}
	catch(IOException e) {
	    e.printStackTrace();
	    return;
	}
    }

    public void add(String s, int type) {
	StringTokenizer st = new StringTokenizer(s, "\t");
	if (st.hasMoreElements() == false)
	    return;
	String name = (String)st.nextElement();
	//-----
	if (st.hasMoreElements() == false)
	    return;
	String email = (String)st.nextElement();
	//-----
	if (st.hasMoreElements() == false)
	    return;
	String tmp = (String)st.nextElement();
	int score = 0;
	try {
	    score = Integer.parseInt(tmp);
	}
	catch(NumberFormatException e) {
	    e.printStackTrace();
	    return;
	}
	//-----
	if (st.hasMoreElements() == false)
	    return;
	tmp = (String)st.nextElement();
	int time = 0;
	try {
	    time = Integer.parseInt(tmp);
	}
	catch(NumberFormatException e) {
	    e.printStackTrace();
	    return;
	}
	Date date = new Date(time);

	HighScore hs = new HighScore(score, name, email, date);
	insert(hs, type);
    }
    
    public void writeLocalHighScores() {
	File f = new File(context.getDataDirectory() + DATAFILE);
	//DebugStr(f.toString());
	try {
	    FastOutputStream fis = new FastOutputStream(f);
	    for (Enumeration e = localTopTen.elements() ; e.hasMoreElements() ; ) {
		HighScore hs = (HighScore)e.nextElement();
		fis.println(hs.toString());
	    }
	    fis.close();
	}
	catch(IOException e) {
	    e.printStackTrace();
	    return;
	}
    }

    /** finds location in top ten but does not insert */
    public int place(int score, int type) {
	if (score <= ((type==LOCAL)?lowestLocalScore:lowestGlobalScore))
	    return(NOT_IN_TOPTEN);
	
	int placement = MAXHIGHSCORES-1;
	Vector v = (type==LOCAL)?localTopTen:globalTopTen;
	for (int i = MAXHIGHSCORES-1 ; i >= 0 ; i--) {
	    HighScore hs = (HighScore)v.elementAt(i);
	    if (score < hs.getScore())
		return(placement);
	    placement = i;
	}
	return(placement);
    }
    
    /** finds location in top ten and inserts */
    public void insert(HighScore hs) {
	int i = place(hs.getScore(), LOCAL);
	if (i != NOT_IN_TOPTEN)
	    insertAt(hs, i, LOCAL);
	
	i = place(hs.getScore(), GLOBAL);
	if (i != NOT_IN_TOPTEN) {
	    insertAt(hs, i, GLOBAL);
	    logGlobal(hs);
	    context.update();
	}
    }

    /** finds location in top ten and inserts */
    public void insert(HighScore hs,  int type) {
	int i = place(hs.getScore(), type);
	if (i == NOT_IN_TOPTEN)
	    return;
	insertAt(hs, i, type);
    }

    /** finds location in top ten but does not insert */
    public void insertAt(HighScore hs, int place, int type) {
	Vector v = (type==LOCAL)?localTopTen:globalTopTen;
	v.insertElementAt(hs, place);
	while (v.size() > MAXHIGHSCORES)
	    v.removeElementAt(MAXHIGHSCORES);

	if (type == LOCAL)
	    lowestLocalScore = ((HighScore)v.elementAt(MAXHIGHSCORES-1)).getScore();
	else 
	    lowestGlobalScore = ((HighScore)v.elementAt(MAXHIGHSCORES-1)).getScore();
    }


    public void dumpHighScores() {
	DebugStr("LOCAL");
	for (int i = MAXHIGHSCORES-1 ; i >= 0 ; i--) {
	    HighScore hs = (HighScore)localTopTen.elementAt(i);
	    DebugStr (hs.toString());
	}
	DebugStr("-------");
	DebugStr("GLOBAL");
	for (int i = MAXHIGHSCORES-1 ; i >= 0 ; i--) {
	    HighScore hs = (HighScore)globalTopTen.elementAt(i);
	    DebugStr (hs.toString());
	}
    }


    /** return local top ten */
    public Vector getLocalTopTen() {
	return(localTopTen);
    }

    /** return global top ten */
    public Vector getGlobalTopTen() {
	return(globalTopTen);
    }

    public void logGlobal(HighScore hs) {
	context.appendLog(hs.toString());
    }


    public void clear(Vector v) {
	v.setSize(0);
	for (int i = 0 ; i < MAXHIGHSCORES ; i++) {
	    HighScore hs = new HighScore();
	    v.addElement(hs);
	}
    }
    
    /**
     * for debugging
     */
    public void DebugStr(String s) {
        System.out.println(this.getClass().getName() + ": " + s);
    }

}

