/**
 * Title:        Pommeja taivaalta
 * Description:  Geneerinen räiskintäpeli Javalla
 * Copyright:    Copyright (c) 2003
 *
 * @author Juho Makkonen
 * @version 1.0
 */

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;


/**
 * Tulostaulukko-luokan olio sisältää joukon
 * tulosrivejä. Olen käyttänyt pohjana
 * nelosharjoituksessa tekemääni ratkaisua.
 */
public class Tulostaulukko {

    /** Tiedosto, josta luetaan ja johon kirjoitetaan. */
    private String tiedostonNimi;

    /** Tekstivirta tiedostoon kirjoittamista varten. */
    private FileWriter kirjoittaja = null;

    /** Tekstivirran puskuri. */
    private BufferedWriter bkirjoittaja = null;

    /** Binaarivirta tiedostosta lukemista varten. */
    private InputStream in = null;

    /** Merkkivirta, joka lukee merkit binaarivirrasta. */
    private Reader lukija = null;

    /** Merkkivirran puskuri. */
    private BufferedReader blukija = null;

    /** Tulosrivien joukko. */
    private Set setti;

    /** Tulostaulukkoon viimeksi lisätty tulosrivi.*/
    private Tulosrivi pelaajanRivi;

    /** Tulostettava tulosrivi. */
    private Tulosrivi tulostettava;

    /** Mahtuuko tulostettava rivi kymmenen joukkoon. */
    private boolean mahtuukoMukaan = false;

    /** Vaihdetaanko tulosrivin väriä. */
    private boolean variVaihtuu = false;

    /** Sijoittuiko pelaaja ensimmäiseksi. */
    private int ykkostila = 0;


    /**
     * Luo uuden tulostaulukon ilman parametrejä.
     */
    public Tulostaulukko() {
	setti = new TreeSet();
    }
    

    /** 
     * Luo uuden tulostaulukon, jonka sisältö luetaan parametrina
     * annetusta tiedostosta.
     *
     * @param tiedostonNimi tulostaulukon alustuksen sisältävän
     * tiedoston nimi
     * @throws IOException jos lukeminen ei onnistu
     */
    public Tulostaulukko(String tiedostonNimi) throws IOException {
	
	setti = new TreeSet();

	// Luodaan binaarivirta tiedostosta lukemista varten.
	in = new FileInputStream(tiedostonNimi);
	
	// Luodaan merkkivirta, joka lukee merkit binaarivirrasta.
	lukija = new InputStreamReader(in);

	// Puskuroidaan luotu merkkivirta.
	blukija = new BufferedReader(lukija);

	// Luetaan rivejä, kunnes päästään loppuun. Muutetaan rivien
	// merkkijonot Tulosrivi-olioiksi ja lisätään ne tulostaulukkoon.
	String rivi = null;
	for (int m=0;(rivi=blukija.readLine()) != null;m++) {
	    SimpleDateFormat aika = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
	    try {
		StringTokenizer st = new StringTokenizer(rivi,"&");
		if (st.hasMoreTokens()) {
		    String nimi = st.nextToken();
		    Date paiva = aika.parse(st.nextToken());
		    int peliaika = Integer.parseInt(st.nextToken());
		    int tuhotutPommit = Integer.parseInt(st.nextToken());
		    int pisteet = Integer.parseInt(st.nextToken());
		    Tulosrivi t = new Tulosrivi(nimi,paiva,peliaika,tuhotutPommit,pisteet);
		    this.lisaaRivi(t);		    
		} else {
		    System.out.println("Ei rivejä.");
		}
	    } catch(ParseException pe) {
		pe.printStackTrace();
	    }
	}

	// Suljetaan virta.
	if (blukija != null) {
	    blukija.close();
	}	 	
    }     


    /**
     * Palauttaa muuttujan <code>mahtuukoMukaan</code>
     * arvon, joka on true tai false.
     *
     * @return mahtuuko pelaajan tulosrivi kymmenen
     * joukkoon
     */
    public boolean mahtuukoMukaan() {
	return mahtuukoMukaan;
    }


    /**
     * Palauttaa muuttujan <code>ykkostila</code>
     * arvon. Jos ykköstila tuli, arvo on 1.
     *
     * @return tuliko ykköstila
     */
    public int tulikoYkkostila() {
	return ykkostila;
    }


    /**
     * Asettaa muuttujan <code>variVaihtuu</code>
     * arvoksi parametrina annetun totuusarvon.
     *
     * @param b totuusarvo, joka määrää vaihtuuko
     * pelaajan rivin väri
     */
    public void asetaVariVaihtuu(boolean b) {
	variVaihtuu = b;
    }


    /**
     * Lisää parametrina annetun tulosrivin tulostaulukon
     * tulosrivejä sisältävään joukkoon. Lisäksi
     * asetetaan muuttujan pelaajanRivi arvoksi
     * annettu rivi.
     * 
     * @param rivi Tulosrivi rivi
    */
    public void lisaaRivi(Tulosrivi rivi) {
	pelaajanRivi = rivi;
	setti.add(rivi);
    }


    /**
     * Käy läpi tulostaulukon tulosrivit.
     * 
     * @return tulostaulukon tulosrivit
     */
    public Iterator tulosriviIteraattori() {
	return setti.iterator();
    }


    /**
     * Tulostaa tulostaulukosta parametrina annetun
     * rivimäärän mukaisen määrän tuloksia parhaimmasta
     * alkaen parametrina annettuun tiedostoon.
     *
     * @param tiedostonNimi sen tiedoston nimi, johon
     * tiedot tulostetaan
     * @param rivimaara tulostettavien rivien määrä
     * @throws IOException jos kirjoittaminen ei onnistu
     */
    public void tulosta(String tiedostonNimi, int rivimaara) throws IOException {	
	
	// Alustetaan tekstivirta.
	kirjoittaja = new FileWriter(tiedostonNimi);

	// Puskuroidaan tekstivirta.
	bkirjoittaja = new BufferedWriter(kirjoittaja);

	// Käydään läpi tulostaulukon tulosrivit ja kirjoitetaan annettu
	// määrä tuloksia annetun nimiseen tiedostoon.
	Iterator sIt = tulosriviIteraattori();
	for (int k=0;sIt.hasNext() && k<rivimaara;k++) {
	    tulostettava = (Tulosrivi)sIt.next();

	    // Tulostetaan viimeisenä lisättyyn tulosriviin
	    // ylimääräinen pätkä, jos se on tulostettavien
	    // joukossa ja väriä on tarkoitus vaihtaa.
	    // Tällöin muuttujan <code>mahtuukoMukaan</code>
	    // arvoksi tulee true. Muuttujan
	    // <code>ykkostila</code> arvo kertoo, mikä on
	    // pelaajan rivin sijoitus tulostaulukossa.
	    if (tulostettava.toString().equals(pelaajanRivi.toString())
		&& variVaihtuu == true) {
		bkirjoittaja.write(tulostettava.toString() + "&" + k);
		mahtuukoMukaan = true;
		ykkostila = (k+1);
	    } else {
		bkirjoittaja.write(tulostettava.toString());
	    }

	    // Vaihdetaan riviä.
	    bkirjoittaja.newLine();

	    // Varmistetaan, että tieto menee muistiin.
	    bkirjoittaja.flush();

	}
	
	// Suljetaan virta.
	if (bkirjoittaja != null) {
	    bkirjoittaja.close();	
	}

    }

}

