package org.lucci.madhoc.simulation.measure;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.sql.Date;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.lucci.madhoc.Version;
import org.lucci.madhoc.simulation.MadhocSimulation;
import org.lucci.madhoc.simulation.Monitor;
import org.lucci.madhoc.simulation.projection.Projection;
import org.lucci.text.TextUtilities;
import org.lucci.util.Collections;
import org.lucci.util.Filter;

/*
 * Created on Aug 16, 2004
 */

/**
 * @author luc.hogie
 */
public class MeasureUtility
{
    public static void saveNumericalMeasuresToGNUPlotStream(MadhocSimulation simulation, PrintStream os, boolean printHeader)
        throws IOException
    {
        int columnSize = 40;
        
        if (printHeader)
        {
            os.println("# This file has been generated on " + new Date(System.currentTimeMillis()).toLocaleString() + " by Madhoc '" + Version.RELEASE_NAME + "'");
            os.println("# It contains the result of the simulation '" + simulation.getName() + "' executed by user '" + System.getProperty("user.name") + "' on computer '" + InetAddress.getLocalHost().getHostName() + "'");
            os.println("# The parameters were:");
            os.println("#");
            os.println(TextUtilities.prefixEachLineBy(simulation.getConfiguration().toString(), "# \t"));
            os.println("#");
            os.println("# " + simulation.getNetwork().getMonitorMap().size() + " applications were executed simultaneously:");
            Iterator apps = simulation.getNetwork().getMonitorMap().values().iterator();
            
            while (apps.hasNext())
            {
                Monitor app = (Monitor) apps.next();
                os.println("#\t- " + app.getName());
            }
            
            os.println("#");
            os.println("# " + simulation.getNetwork().getProjectionMap().size() + " projections defined:");
            Iterator projectionIterator = simulation.getNetwork().getProjectionMap().values().iterator();
            
            while (projectionIterator.hasNext())
            {
                Projection projection = (Projection) projectionIterator.next();
                os.println("# \t- " + projection.getName());
            }
            
            os.println("#");
        }

        Iterator projectionIterator = simulation.getNetwork().getProjectionMap().values().iterator();
        
        while (projectionIterator.hasNext())
        {
            Projection projection = (Projection) projectionIterator.next();
            os.println("#");
            os.println("# Projection: " + projection.getName());

            // get all the measures available for this projection
            List measureRepositories = new Vector(projection.getMeasureHistoryMap().values());
            
            // retain only the numerical measures
            Collections.filter(measureRepositories, new Filter()
                {
                    public boolean accept(Object o)
                    {
                        MeasureHistory measureRepository = (MeasureHistory) o;
                        return measureRepository.getSensor() instanceof NumericalSensor;
                    }
                });
            
            // and sort them by name
            java.util.Collections.sort(measureRepositories, new Comparator()
                {
                    public int compare(Object arg0, Object arg1)
                    {
                        MeasureHistory mr0 = (MeasureHistory) arg0;
                        MeasureHistory mr1 = (MeasureHistory) arg1;
                        return mr0.getSensor().getName().compareToIgnoreCase(mr1.getSensor().getName());
                    }
                });


            os.print("\n#");

            for (int m = 0; m < measureRepositories.size(); ++m)
            {
                os.print(TextUtilities.flushRight(String.valueOf(m + 1), columnSize) + '\t');
            }

            os.print("\n#");

            for (int m = 0; m < measureRepositories.size(); ++m)
            {
                MeasureHistory measure = (MeasureHistory) measureRepositories.get(m);
                os.print(TextUtilities.flushRight(measure.getSensor().getName(), columnSize) + '\t');
            }

            os.print("\n#");

            for (int m = 0; m < measureRepositories.size(); ++m)
            {
                MeasureHistory measure = (MeasureHistory) measureRepositories.get(m);
                Unit unit = ((NumericalSensor) measure.getSensor()).getUnit();
                os.print(TextUtilities.flushRight(unit == null ? "" : "("+ unit.getName() + ")", columnSize) + '\t');
            }

            os.println();

            for (int i = 0; i < simulation.getIteration(); ++i)
            {
                for (int m = 0; m < measureRepositories.size(); ++m)
                {
                    MeasureHistory repository = (MeasureHistory) measureRepositories.get(m);
                    Object value = repository.getValues().get(i);
                    os.print(TextUtilities.flushRight(value == null ? "-" : value.toString(), columnSize) + '\t');
                }

                os.println();
            }
        }
    }

    public static void saveNumericalMeasuresToGNUPlotFile(MadhocSimulation simulation, File measureFile, boolean h)
        throws IOException
    {
            FileOutputStream fos = new FileOutputStream(measureFile);
            PrintStream pos = new PrintStream(fos);
            saveNumericalMeasuresToGNUPlotStream(simulation, pos, h);
            pos.close();
            fos.close();
    }

}