/*                          
 * mBench: The Open Source Micro Benchmark Tool 
 *                                             
 * Distributable under GPL license. 
 * See terms of license at gnu.org.                 
 *
 * Copyright (C) 2005 Sumisho Computer Systems Corp.
 */
package jp.co.scs.mbench;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;

/**
 *      Data log handler (writer), asynchronous, cvs format.
 * 
 *      @author Tetsuro Ikeda
 */
public class CSVAsynchronousDataWriter
        extends Thread implements DataWriter {
    /**
     *  the file name of cvs file to write.
     */
    private String dataName = null;
    
    /**
     *  bufferd writer
     */
    private BufferedWriter writer = null;
    
    /**
     *  the flag if this instance is already initialized
     */
    private boolean isInitialized = false;
    
    /**
     *  the flag if this instance is running
     */
    private boolean isRunning = false;
    
    /**
     *  the queue for data log
     */
    private LinkedList dataQueue = new LinkedList();

    /**
     *  the command for remove the data from queue
     */
    private int remove = 0;
    
    /**
     *  the command for add the data to queue
     */
    private int add = 1;
    
    /**
     *  Creates the instance of this class with file name
     * 
     *  @param dataName file name
     */
    public CSVAsynchronousDataWriter(String dataName) {
        this.dataName = dataName;
    }
    
    /**
     *  Sets the file name
     * 
     *  @param dataName file name
     */
    public void setDataName(String dataName) {
        this.dataName = dataName;    
    }
    
    /**
     *  Gets the file name
     * 
     *  @return file name3
     */
    public String getDataName() {
        return this.dataName;
    }
    
    /**
     *  Gets if this instance is already initialized
     *
     *  @return the flag if this instance is already initialized
     */
    public boolean isInitialized() {
        return this.isInitialized;
    }
    
    /**
     *  Gets the if this instance is running
     *
     *  @return the flag if this instance is running
     */
    public boolean isRunning() {
        return this.isRunning;
    }
    
    /**
     *  Gets the size of queue
     *
     *  @return size of queue
     */
    public int getDataQueueSize() {
        return this.dataQueue.size();
    }
    
    /**
     *  initialize this instance
     * 
     *  @throws BenchmarkTerminateException benchmark should be terminated
     */
    public void init() throws BenchmarkTerminateException {
        try {
            this.writer = new BufferedWriter(new FileWriter(this.dataName));
            this.start();
            this.isInitialized = true;
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new BenchmarkTerminateException(ex);
        }
    }
    
    /**
     *  Add the data log to queue
     * 
     *  @param data data log
     */
    public void write(String[] data) {
        manipulateQueue(this.add, data);
    }
    
    /**
     *  write the data log in queue and loop
     */
    public void run() {
        try {
            this.isRunning = true;
            while (this.isRunning || this.dataQueue.size() > 0) {
                Object obj = manipulateQueue(this.remove, null);
                if (obj != null) {
                    String[] data = (String[]) obj;
                    for (int i = 0; i < data.length; i++) {
                        this.writer.write(data[i]);
                        if (i < data.length - 1) {
                            this.writer.write(",");
                        }
                    }
                    this.writer.write("\n");
                // wait if queue is blank
                } else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException ex) {
                        // ignore
                    }
                }
            }
        } catch (IOException ex) {
            this.isRunning = false;
            this.isInitialized = false;
            ex.printStackTrace();
        }
    }
    
    /**
     *  finalize this instance
     */
    public void clean() {
        try {
            // wait if any data log is still in queue
            while (this.isInitialized && this.dataQueue.size() > 0) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {
                    // ignore
                }
            }
            this.isRunning = false;
            if (writer != null) {
                this.writer.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            this.isInitialized = false;
        }
    }
    
    /**
     *  manipulate the queue (add or remove).
     *  this method is synchronized.
     *  returns null if the command is "add" or "remove" but no data log in queue
     * 
     *  @param command manipulation command, 0 is for remove, 1 is for add
     *  @param obj data log (only if command is "add")
     *  @return data log (only if command is "remove")
     */
    private synchronized Object manipulateQueue(int command, Object obj) {
        if (command == this.add) {
            this.dataQueue.addLast(obj);
            return null;
        } else if (command == this.remove) {
            if (this.dataQueue.size() > 0) {
                return this.dataQueue.removeFirst();
            } else {
                return null;
            }
        }
        return null;
    }

}
