view flys-backend/src/main/java/de/intevation/flys/importer/parsers/HYKParser.java @ 1219:d80997bd94ce

HYKParser: Create data structures while parsing. flys-backend/trunk@2345 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 17 Jul 2011 22:30:09 +0000
parents f8b5c37f15e4
children ca7d461a53f1
line wrap: on
line source
package de.intevation.flys.importer.parsers;

import de.intevation.flys.importer.ImportHYK;
import de.intevation.flys.importer.ImportHYKEntry;
import de.intevation.flys.importer.ImportHYKFormation;
import de.intevation.flys.importer.ImportHYKFlowZone;
import de.intevation.flys.importer.ImportHYKFlowZoneType;

import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;

import java.util.HashMap;
import java.util.Map;
import java.util.Date;
import java.util.Calendar;

import java.math.BigDecimal;

import org.apache.log4j.Logger;

import de.intevation.flys.utils.FileTools;

public class HYKParser
{
    private static Logger log = Logger.getLogger(HYKParser.class);

    public interface Callback {
        boolean hykAccept(File file);
        void    hykParsed(HYKParser parser);
    } // interface Callback

    public static enum State {
        LINE_1, LINE_2, LINE_3, LINE_4, LINE_5, LINE_6
    };

    private static final String ENCODING = "ISO-8859-1";

    protected Map<String, ImportHYKFlowZoneType> flowZoneTypes;

    protected ImportHYK hyk;

    public HYKParser() {
        flowZoneTypes = new HashMap<String, ImportHYKFlowZoneType>();
    }

    public ImportHYK getHYK() {
        return hyk;
    }

    private static Date yearToDate(Integer year) {
        if (year == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.set(year, 0, 1, 12, 0, 0);
        long ms = cal.getTimeInMillis();
        cal.setTimeInMillis(ms - ms%1000);
        return cal.getTime();
    }

    public boolean parse(File file) {

        boolean debug = log.isDebugEnabled();

        log.info("Parsing HYK file '" + file + "'");

        LineNumberReader in = null;

        String description =
            file.getParentFile().getName() + "/" + file.getName();

        hyk = new ImportHYK(null, description);

        try {
            in =
                new LineNumberReader(
                new InputStreamReader(
                new FileInputStream(file), ENCODING));

            String line;

            State state = State.LINE_1;

            int numFormations = 0;

            BigDecimal km         = null;
            BigDecimal top        = null;
            BigDecimal bottom     = null;
            BigDecimal distanceVL = null;
            BigDecimal distanceHF = null;
            BigDecimal distanceVR = null;

            Integer    year       = null;
            int        numZones   = 0;

            ImportHYKFlowZoneType [] fzts     = null;
            BigDecimal            [] coords   = null;
            int                      coordPos = 0;

            ImportHYKEntry     entry     = null;
            ImportHYKFormation formation = null;

            while ((line = in.readLine()) != null) {

                if (line.startsWith("*") || line.startsWith("----")) {
                    continue;
                }

                line = line.trim();

                if (state != State.LINE_5 && line.length() == 0) {
                    continue;
                }

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

                if (debug) {
                    log.debug("'" + line + "': " + state);
                }

                switch (state) {
                    case LINE_1:
                        if (parts.length < 2) {
                            log.error("1: not enough elements in line " +
                                in.getLineNumber());
                            return false;
                        }

                        if (parts.length == 2) {
                            // no year given
                            year = null;
                        }
                        else {
                            try {
                                year = Integer.valueOf(parts[1]);
                            }
                            catch (NumberFormatException nfe) {
                                log.error(
                                    "year is not an integer in line " +
                                    in.getLineNumber());
                                return false;
                            }
                        }
                        try {
                            km = new BigDecimal(parts[0]);
                            numFormations = Integer.parseInt(
                                parts[parts.length > 2 ? 2 : 1]);
                        }
                        catch (NumberFormatException nfe) {
                            log.error(
                                "parsing number of formations " +
                                "or km failed in line " + in.getLineNumber());
                            return false;
                        }
                        entry = new ImportHYKEntry(hyk, km, yearToDate(year));
                        hyk.addEntry(entry);

                        state = State.LINE_2;
                        break;

                    case LINE_2:
                        if (parts.length < 3) {
                            log.error("2: not enough elements in line " +
                                in.getLineNumber());
                            return false;
                        }
                        try {
                            numZones = Integer.parseInt(parts[0]);
                            bottom   = new BigDecimal(parts[1]);
                            top      = new BigDecimal(parts[2]);
                        }
                        catch (NumberFormatException nfe) {
                            log.error(
                                "parsing num zones, bottom or top height " +
                                "failed in line " + in.getLineNumber());
                            return false;
                        }
                        formation = new ImportHYKFormation();
                        formation.setEntry(entry);

                        state = State.LINE_3;
                        break;

                    case LINE_3:
                        if (parts.length != numZones) {
                            log.error(
                                "number of flow zones mismatches " +
                                "in line " + in.getLineNumber());
                            return false;
                        }

                        fzts = new ImportHYKFlowZoneType[parts.length];
                        for (int i = 0; i < fzts.length; ++i) {
                            fzts[i] = getFlowZoneType(parts[i]);
                        }
                        coords = new BigDecimal[numZones];
                        state = State.LINE_4;
                        break;

                    case LINE_4:
                        try {
                            int N = Math.min(parts.length, coords.length);
                            for (coordPos = 0; coordPos < N; ++coordPos) {
                                coords[coordPos] =
                                    new BigDecimal(parts[coordPos]);
                            }
                        }
                        catch (NumberFormatException nfe) {
                            log.error("cannot parse number in line " +
                                in.getLineNumber());
                            return false;
                        }
                        state = State.LINE_5;
                        break;

                    case LINE_5:
                        if (parts.length + coordPos < coords.length) {
                            log.error("5: not enough elements in line " +
                                in.getLineNumber());
                            return false;
                        }
                        try {
                            for (int i = 0; 
                                i < parts.length && coordPos < coords.length;
                                ++i, ++coordPos
                            ) {
                                coords[coordPos] = new BigDecimal(parts[i]);
                            }
                        }
                        catch (NumberFormatException nfe) {
                            log.error("cannot parse number in line " + 
                                in.getLineNumber());
                            return false;
                        }
                        for (int i = 0; i < coords.length; ++i) {
                            ImportHYKFlowZone zone = new ImportHYKFlowZone(
                                formation,
                                fzts[i],
                                coords[i],
                                coords[i == coords.length-1 ? i : i+1]);
                            formation.addFlowZone(zone);
                        }
                        state = State.LINE_6;
                        break;

                    case LINE_6:
                        if (parts.length < 3) {
                            log.error("6: not enough elements in line " +
                                in.getLineNumber());
                            return false;
                        }
                        try {
                            distanceVL = new BigDecimal(parts[0]);
                            distanceHF = new BigDecimal(parts[1]);
                            distanceVL = new BigDecimal(parts[2]);
                        }
                        catch (NumberFormatException nfe) {
                            log.error("cannot parse number in line " +
                                in.getLineNumber());
                            return false;
                        }
                        formation.setDistanceVL(distanceVL);
                        formation.setDistanceHF(distanceHF);
                        formation.setDistanceVR(distanceVR);

                        // continue with next formation.
                        state = --numFormations > 0 // formations left?
                            ? State.LINE_2
                            : State.LINE_1;
                        break;
                }
            }
        }
        catch (IOException ioe) {
            log.error(ioe);
            return false;
        }
        finally {
            if (in != null) {
                try {
                    in.close();
                }
                catch (IOException ioe) {
                    log.error(ioe);
                }
            }
        }
        return true;
    }

    protected ImportHYKFlowZoneType getFlowZoneType(String name) {
        name = name.toUpperCase();
        ImportHYKFlowZoneType fzt = flowZoneTypes.get(name);
        if (fzt == null) {
            log.info("New flow zone type: " + name);
            fzt = new ImportHYKFlowZoneType(name);
            flowZoneTypes.put(name, fzt);
        }
        return fzt;
    }

    protected void reset() {
        hyk = null;
    }

    public void parseHYKs(File root, final Callback callback) {

        FileTools.walkTree(root, new FileTools.FileVisitor() {
            @Override
            public boolean visit(File file) {
                if (file.isFile() && file.canRead()
                && file.getName().toLowerCase().endsWith(".hyk")
                && (callback == null || callback.hykAccept(file))) {
                    reset();
                    boolean success = parse(file);
                    log.info("parsing " + (success ? "succeeded" : "failed"));
                    if (success && callback != null) {
                        callback.hykParsed(HYKParser.this);
                    }
                }
                return true;
            }
        });
    }

    public static void main(String [] args) {

        HYKParser parser = new HYKParser();

        for (String arg: args) {
            parser.parseHYKs(new File(arg), null);
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org