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;

/**
 *
 * @author jonathanhornbaker
 */
public class HydrobalParser 
{
    private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
    /**
     * hydroData contains the entirety of the hydrobal 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> > > > hydroData;
    
    public HydrobalParser()
    {
        hydroData = new ArrayList<Map<Date, List<Map<String, String> > > >();
    }
    
    /**
     * This will take any valid hydrobal file and parse it, with each line in the file
     * corresponding to an item in the hydroData 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[] hydroLine = line.split("\\|", -1);
                String[] keys = null;
                int keyOffset = 0;
                Date curDate;
                boolean named = true; //data is "named" until the first date occurs.
                Map<String, String> dateData = new HashMap<String, String>();
                List<Map<String, String> > multiDate = new ArrayList<Map<String, String> >();
                String prefix = "";
                for(int index = 0; index < hydroLine.length; index ++)
                {
                    if(!named)
                    {
                        dateData.put("cropName", hydroLine[index].trim());
                        named = true;
                        continue;
                    }
                    if(keys == null)
                    {
                        String[] testset = hydroLine[index].split(",");
                        if(testset.length > 1)
                        {
                            //We need to see if we need to extract a prefix ("start" or "end")
                            String[] prefixCheck = testset[0].split(" ");
                            if(prefixCheck.length == 2)
                            {
                                prefix = prefixCheck[0];
                                testset[0] = prefixCheck[1];
                            }
                            keys = testset;
                            keyOffset = index + 1; 
                        }
                        else
                        {
                            try 
                            { 
                                if(hydroLine[index].trim().equals("")) continue;
                                curDate = dateFormat.parse(hydroLine[index].trim()); 
                                dateData = new HashMap<String, String>();
                                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("Key/Data mismatch:  " + index); }
                            named = false;
                            continue;
                        }   
                    }
                    else
                    {
                        dateData.put(prefix + keys[index - keyOffset].trim(), hydroLine[index].trim());
                        if((index + 1) == (keyOffset + keys.length)) 
                        {
                            keys = null;
                            prefix = "";
                        } //We have finished our keyset.
                    }
                }
                hydroData.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 = hydroData.get(cycleNum);
        List<Map<String, String> > dateList = dateMap.get(termination);
        if(dateList == null)
        {
            int hello = 9;
        }
        if(!(order < dateList.size())) return null;
        Map<String, String> keyMap = dateList.get(order);
        return keyMap.get(dataName);
    }
    
    /**
     * Returns the total number of cycles, i.e. lines.
     * @return 
     */
    public int cycle() { return hydroData.size(); }
    
    public static void main(String[] args)
    {
        HydrobalParser parse = new HydrobalParser();
        parse.parse("/home/jonathanhornbaker/Documents/WEPSFiles/Runs/alfalfa_4_nospray_cycletest_1.wjr/hydrobal.out");
        
        int hello = 5;
    }
}
