import java.io.*;
import java.text.*;

/**
 *  VUCAKO Bench results persistance object (simple on-line version).
 *   @author  Josef.Pelikan@mff.cuni.cz
 *   @version 0.008 (2001/07/22)
 *   @since   0.008
 */
public class BenchResults {

    /** Default working file-name. */
    protected static final String DEFAULT_FILE_NAME  = "results.txt";

    /** Default backup file-name. */
    protected static final String BACKUP_FILE_NAME   = "results.bak";

    /** Default temporary file-name. */
    protected static final String TEMP_FILE_NAME     = "results.tmp";

    /** Enhanced results' file-name. */
    protected static final String ENHANCED_FILE_NAME = "enhanced.txt";

    /** Format pattern for test number. */
    protected static final String TEST_PATTERN    = "#0";

    /** Format pattern for elapsed time. */
    protected static final String ELAPSED_PATTERN = " 0";

    /** Working file-name. */
    protected String fileName;

    /** Backup file-name. */
    protected String fileNameBak;

    /** Temporary file-name. */
    protected String fileNameTmp;

    /**
     *  Initializing constructor.
     *   @param  fn File-name (or <code>null</code> for default file-names).
     */
    public BenchResults ( String fn ) {
        if ( fn == null ) {
            fileName    = DEFAULT_FILE_NAME;
            fileNameBak = BACKUP_FILE_NAME;
            fileNameTmp = TEMP_FILE_NAME;
            }
        else {
            fileName = fn;
            fileNameBak = fn + ".bak";
            fileNameTmp = fn + ".tmp";
            }
    }

    private static void alignRight ( StringBuffer buf, FieldPosition pos, int width ) {
        if ( buf == null || pos == null ||
             pos.getEndIndex() - pos.getBeginIndex() >= width ) return;
        width -= pos.getEndIndex() - pos.getBeginIndex();
        do
            buf.insert(pos.getBeginIndex(),' ');
        while ( --width > 0 );
    }

    private static void skipWhiteSpaces ( String buf, ParsePosition pos ) {
        int ptr = pos.getIndex();
        while ( ptr < buf.length() && Character.isSpaceChar(buf.charAt(ptr)) ) ptr++;
        pos.setIndex(ptr);
    }

    private static void enhancedResult ( String line ) {
        try {
            PrintStream enhRes = new PrintStream( new FileOutputStream(ENHANCED_FILE_NAME,true) );
            enhRes.println(line);
            enhRes.close();
            }
        catch ( FileNotFoundException e ) {}
    }

    /**
     *  Adds the new result to actual result file.
     *   @param  test Test ordinal number.
     *   @param  clock Clock speed in MHz.
     *   @param  cpu CPU description string.
     *   @param  elapsed Test running time in milliseconds.
     *   @return <code>true</code> if result file was changed.
     */
    public boolean addResult ( int test, int clock, String cpu, long elapsed ) {
        BufferedReader oldRes;
        try {
            oldRes = new BufferedReader( new FileReader(fileName) );
            }
        catch ( FileNotFoundException e ) {
            System.out.println( "Result file '" + fileName + "' was not found! Creating a new one.." );
            oldRes = null;
            }
        File newFile = new File(fileNameTmp);
        PrintStream newRes;
        try {
            newRes = new PrintStream( new FileOutputStream(newFile) );
            }
        catch ( FileNotFoundException e ) {
            System.out.println( "Cannot write to the '" + fileNameTmp + "' result file!");
            return false;
            }

        DecimalFormat fmt = new DecimalFormat();
        StringBuffer nLine = new StringBuffer();
        FieldPosition fPos = new FieldPosition(DecimalFormat.INTEGER_FIELD);
        boolean notFound = true;
        boolean changed = false;
        if ( oldRes != null ) {             // process the old result file
            String line;
            ParsePosition pos = new ParsePosition(0);
            try {
                while ( (line = oldRes.readLine()) != null ) {
                    if ( notFound ) {
                        pos.setIndex(0);
                            // test number:
                        skipWhiteSpaces(line,pos);
                        Number num = fmt.parse(line,pos);
                        if ( num == null ) continue;
                        int oTest = num.intValue();
                            // elapsed:
                        skipWhiteSpaces(line,pos);
                        num = fmt.parse(line,pos);
                        if ( num == null ) continue;
                        long oElapsed = num.longValue();
                            // cpu clock:
                        skipWhiteSpaces(line,pos);
                        num = fmt.parse(line,pos);
                        if ( num == null ) continue;
                        int oClock = num.intValue();
                        skipWhiteSpaces(line,pos);
                        String oCpu = line.substring(pos.getIndex());
                        if ( cpu.equals(oCpu) && oClock == clock && oTest == test ) {
                            notFound = false;
                            if ( elapsed < oElapsed ) {
                                changed = true;
                                fmt.applyPattern(TEST_PATTERN);
                                fmt.format(test,nLine,fPos);
                                alignRight(nLine,fPos,2);
                                fmt.applyPattern(ELAPSED_PATTERN);
                                fmt.format(elapsed,nLine,fPos);
                                alignRight(nLine,fPos,8);
                                fmt.format(clock,nLine,fPos);
                                alignRight(nLine,fPos,4);
                                nLine.append(" ");
                                nLine.append(cpu);
                                line = new String(nLine);
                                enhancedResult(line);
                                }
                            }
                        }
                    newRes.println(line);
                    }
                oldRes.close();
                }
            catch ( IOException e ) {}
            }

        if ( notFound ) {                   // append the new result to the end:
            changed = true;
            fmt.applyPattern(TEST_PATTERN);
            fmt.format(test,nLine,fPos);
            alignRight(nLine,fPos,2);
            fmt.applyPattern(ELAPSED_PATTERN);
            fmt.format(elapsed,nLine,fPos);
            alignRight(nLine,fPos,8);
            fmt.format(clock,nLine,fPos);
            alignRight(nLine,fPos,4);
            nLine.append(" ");
            nLine.append(cpu);
            newRes.println(nLine);
            enhancedResult( new String(nLine) );
            }

        newRes.close();

        if ( changed ) {                    // change the result file: results.txt -> results.bak
            File oldFile = new File(fileName);
            if ( oldRes != null ) {         // backup "results.txt"
                File bakFile = new File(fileNameBak);
                if ( bakFile.exists() ) bakFile.delete();
                oldFile.renameTo(bakFile);
                }
            newFile.renameTo(oldFile);
            }
        else                                // throw away the new result file
            newFile.delete();

        return changed;
    }

    /**
     *  Close the actual result file.
     *  <br>On-line version needs not be closed.
     */
    public void close () {
    }

}
