package usda.weru.weps.location;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import java.beans.PropertyChangeEvent;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import javax.measure.unit.NonSI;
import org.apache.log4j.Logger;
import org.jscience.geography.coordinates.LatLong;
import usda.weru.util.ConfigData;

/**
 *
 * @author Joseph Levin <joelevin@weru.ksu.edu>
 */
public class WindgenDataModel extends AbstractStationDataModel {

    private final static Logger LOGGER = Logger.getLogger(WindgenDataModel.class);

    private final Object DATA_LOCK = new Object();

    private static WindgenDataModel c_instance;

    private List<WindgenStation> c_stations;

    /**
     *
     * @return
     */
    public static final synchronized WindgenDataModel getInstance() {
        if (c_instance == null) {
            c_instance = new WindgenDataModel();
        }
        return c_instance;
    }

    /**
     *
     * @param id
     * @return
     */
    public WindgenStation getStation(long id) {
        for (WindgenStation station : stations()) {
            if (station.getWBan() == id) {
                return station;
            }
        }
        return null;
    }

    @Override
    protected void configDataPropertyChange(PropertyChangeEvent event) {
        super.configDataPropertyChange(event);
        switch (event.getPropertyName()) {
            case ConfigData.WinIndex:
                //the backing data has changed.
                clearStations();
                break;
            case ConfigData.GISData:
                fireGISDataChanged();
                break;
        }
    }

    private void clearStations() {
        synchronized (DATA_LOCK) {
            if (c_stations == null) {
                //nothing has changed
                return;
            }
            c_stations = null;
        }
        clearCache();
        fireStationDataChanged();
    }

    @Override
    public List<WindgenStation> stations() {
        //lock around the data
        synchronized (DATA_LOCK) {
            if (c_stations == null) {
                c_stations = new LinkedList<WindgenStation>();
                readFromFile(c_stations);
            }
            return c_stations;
        }
    }

    private void readFromFile(List<WindgenStation> stations) {
        String path = ConfigData.getDefault().getDataParsed(ConfigData.WinIndex);
        if (path == null) {
            return;
        }
        TFile file = new TFile(path);
        if (!file.canRead()) {
            LOGGER.warn("Can not read file: " + file.getAbsolutePath());
        }
        BufferedReader in = null;
        try {
            in = new BufferedReader(new TFileReader(file.getCanOrAbsFile()));
            for (String line = in.readLine(); line != null; line = in.readLine()) {
                line = line.trim();
                if (line.startsWith("#") || line.length() == 0) {
                    //skip comments and blank lines
                    continue;
                }

                String[] parts = line.split("\\s+");

                int offset = 0;
                double lat = parseCoordinate(parts, offset + 0);
                double lon = parseCoordinate(parts, offset + 3);

                LatLong latlong = LatLong.valueOf(lat, lon, NonSI.DEGREE_ANGLE);

                long id = Long.parseLong(parts[offset + 12].trim());

                String country = parts[offset + 13].trim();
                String state = parts[offset + 14].trim();
                String name = join(parts, offset + 15);

                WindgenStation station = new WindgenStation(latlong, id, country, state, name);

                if (!stations.contains(station)) {
                    stations.add(station);
                } else {
                    LOGGER.warn("Duplicate windgen station id.  Skipping record: " + station);
                }

            }

            in.close();
        } catch (FileNotFoundException fnfe) {
            LOGGER.error("Wingen index file not found:" + file.getPath());
        } catch (IOException | NumberFormatException e) {
            LOGGER.error("Error reading the wingen index file:" + file.getPath(), e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    LOGGER.error("Unable to close stream.", e);
                }
            }
        }
    }

    private String join(String[] parts, int start) {
        StringBuilder buffer = new StringBuilder();
        for (int i = start; i < parts.length; i++) {
            buffer.append(parts[i]);
            buffer.append(" ");
        }
        return buffer.toString().trim();

    }

    private double parseCoordinate(String[] parts, int start) {
        double degree = Double.parseDouble(parts[start].trim());
        double minutes = Double.parseDouble(parts[start + 1].trim());

        double value = degree + (minutes / 60);

        String quadrant = parts[start + 2].trim();
        if ("S".equals(quadrant) || "W".equals(quadrant)) {
            value = value * -1;
        }

        return value;
    }

}
