package usda.weru.weps.reports.query.parse;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A class that handles the parsing of the entire season file into an easily accessible
 * map.
 * @author jonathanhornbaker
 */
public class SeasonParser 
{
    private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
    /**
     * seasonData contains the entirety of the season file in this structure:
     * 
     * List<Map<Date, List<Map<String, String> > > >:  A one to one relationship
     *              between the elements of this struct and the lines in the file.
     * Map<Date, List<Map<String, String> > >:  For each date, we keep track of the data.
     *              the termination date is our unique key, so we can coordinate between files.
     * List<Map<String, String> >:  In case of multiple events in a day, we need a list to
     *              keep the data in order.
     * Map<String, String>:  A direct mapping of key to value.
     * 
     * Please note that this structure SHOULD NOT ever be edited outside of the parse method,
     * only read.
     */
    private List<Map<Date, List<Map<String, String> > > > seasonData;
    private String[] keySet = { "planting", "termin", "cropName", "standingStem", 
                "standingLeaf", "standingStore", "flatStem", "flatLeaf", 
                "flatStore", "rootStem", "rootStore", "rootFiber", "height",
                "stemcount", "rootDepth", "grainf", "stmrepd", "cancov", "dapl", 
                "chill", "hucum",  "mxhu", "huind", "dafm", "spring" };
    
    public SeasonParser()
    {
        seasonData = new ArrayList<Map<Date, List<Map<String, String> > > >();
    }
    
    /**
     * This will take any valid season file and parse it, with each line in the file
     * corresponding to an item in the seasonData list.  Each item will consist of a
     * hashmap, using termination date as the unique key to identify all data in another
     * map where the header is the key and the data is the double.
     * @param fileName 
     */
    public void parse(String fileName)
    {
        try
        {
            TFile file = new TFile(fileName);
            BufferedReader reader = new BufferedReader(new TFileReader(file));
            String line;
            while(((line = Interval.getLine(reader)) != null))
            {
                Map<Date, List<Map<String, String> > > lineData = new HashMap<Date, List<Map<String, String> > >();
                String[] seasonLine = line.split("\\|", -1);
                Date curDate;
                Map<String, String> dateData = new HashMap<String, String>();
                List<Map<String, String> > multiDate = new ArrayList<Map<String, String> >();
                for(int index = 0; index < seasonLine.length; index ++)
                {
                    if((index % keySet.length) == 1)
                    {
                        try
                        {
                            if(seasonLine[index].trim().equals("")) continue;
                            curDate = dateFormat.parse(seasonLine[index].trim()); 
                            multiDate = lineData.get(curDate);
                            if(multiDate == null)
                            {
                                multiDate = new ArrayList<Map<String, String> >();
                                lineData.put(curDate, multiDate);
                            }
                            multiDate.add(dateData);
                        }
                        catch(ParseException pe) { throw new IOException("Termination Date out of place:  " + index); }
                    }
                    else
                    {
                        if((index % keySet.length) == 0) dateData = new HashMap<String, String>();
                        dateData.put(keySet[index % keySet.length], seasonLine[index]);
                    }
                }
                seasonData.add(lineData);
            }
        }
        catch(IOException ioe) { ioe.printStackTrace(); }
    }
    
    /**
     * Returns the data associated with the set of inputs.
     * @param cycleNum The line number (base one indexing)
     * @param termination The termination date
     * @param dataName The key of the column of output.
     * @param order  If there are multiple terminations on this day, the index of
     *                      the requested date (base zero indexing.
     * @return 
     */
    public String getData(int cycleNum, Date termination, String dataName, int order)
    {
        cycleNum --;
        Map<Date, List<Map<String, String> > > dateMap = seasonData.get(cycleNum);
        List<Map<String, String> > dateList = dateMap.get(termination);
        if(!(order < dateList.size())) return null;
        Map<String, String> keyMap = dateList.get(order);
        return keyMap.get(dataName);
    }
    
    /**
     * Returns true if the seasonData struct is empty.
     * @return 
     */
    public boolean isEmpty()
    {
        return seasonData.isEmpty();
    }
    
    /**
     * Returns the total number of cycles, i.e. lines.
     * @return 
     */
    public int cycle() { return seasonData.size(); }
    
    public static void main(String[] args)
    {
        SeasonParser parse = new SeasonParser();
        parse.parse("/home/jonathanhornbaker/Documents/WEPSFiles/Runs/alfalfa_4_nospray_cycletest_1.wjr/season.out");
        
        int hello = 5;
    }

    private Exception IndexOutOfBoundsException() {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}
