// (C)2007 Attila Kovacs <attila@submm.caltech.edu>

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

public class ASCIISpectrum {
    

    public static void main(String[] args) {
	System.err.println();
	System.err.println("  ASCIISpectrum -- Calculate spectra for Labview time-series.");
	System.err.println("                   2006 Attila Kovacs <attila@submm.caltech.edu> <akovacs@mpifr-bonn.mpg.de>");	
	System.err.println();

	if(args.length == 0) usage();

	int channels = -1;
	Vector buffer = new Vector();	

	try { 
	    BufferedReader in = new BufferedReader(new FileReader(args[0]));
	    int index = args[0].lastIndexOf('.');
	    String fileNameStem = index > 0 ? args[0].substring(0, index) : args[0];
	    String fileNameExt = index > 0 ? args[0].substring(index) : "";
	    int windowSize = ArrayUtil.getPaddedFFTSize(Integer.parseInt(args[1]));
	    double[] w = ArrayUtil.getWindowFunction(args.length > 2 ? args[2] : "Hamming", windowSize);
	    double dt = 1.0 / Double.parseDouble(in.readLine());
	    String line;

	    double[] offset = null;

	    System.err.println("  Reading data.");
	    while((line = in.readLine()) != null) {
		StringTokenizer tokens = new StringTokenizer(line);
		if(channels <= 0) {
		    channels = tokens.countTokens();
		    offset = new double[channels];
		}
		else if(channels == tokens.countTokens()) {
		    double[] entry = new double[channels];
		    for(int i=0; i<entry.length; i++) {
			entry[i] = Double.parseDouble(tokens.nextToken());
			offset[i] += entry[i];
		    }
		    buffer.add(entry);
		}
	    }

	    for(int c=0; c<channels; c++) offset[c] /= buffer.size();

	    System.err.println("  Calculating Power spectra.");
	    double[] data = new double[buffer.size()];
	    double[][] spectrum = new double[channels][];
	    for(int c=0; c<channels; c++) {
		for(int t=0; t<buffer.size(); t++) {
		    double[] entry = (double[]) buffer.get(t);
		    data[t] = entry[c] - offset[c];
		}
		spectrum[c] = ArrayUtil.averagePower(data, w);
	    }

	    
	    double df = 1.0 / (dt * windowSize);	    
	    DecimalFormat e3 = new DecimalFormat("0.000E0");	    

	    PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(fileNameStem + ".spec"), 1000000));
	
	    System.err.println("  Writing Power spectra.");
	    for(int f=1; f<spectrum[0].length; f++) {
		out.print(e3.format(f*df));
		for(int c=0; c<channels; c++) out.print("\t" + e3.format(spectrum[c][f]/df));
		out.println();
	    }
	    
	    out.flush();
	    out.close();

	    System.err.println();
	}
	catch(IOException e) { System.err.println("  " + e.getMessage()); }
    }



    public static void usage() {
	
	System.out.println("  Usage: spectrum <data-file> <window-size> [window-type]");
	System.out.println();
	System.out.println("       <data-file>    The Labview-style ASCII time series file.");
	System.out.println("       <window-size>  The requested window function size in samples.");
	System.out.println("       [window-type]  (Optional) The type of window to use.");
	System.out.println();
	System.exit(0);
    }
}
