package cern.accsoft.steering.aloha.read.yasp;

import java.io.File;
import java.util.StringTokenizer;

import cern.accsoft.steering.aloha.plugin.kickresp.meas.data.CorrectorKickData;
import cern.accsoft.steering.aloha.plugin.kickresp.meas.data.CorrectorKickDataImpl;
import cern.accsoft.steering.aloha.read.CorrectorKickDataReader;
import cern.accsoft.steering.jmad.tools.response.DeflectionSign;
import cern.accsoft.steering.util.acc.BeamNumber;
import cern.accsoft.steering.util.io.TextFileParser;
import cern.accsoft.steering.util.io.impl.TextFileParserImpl;
import cern.accsoft.steering.util.meas.data.Plane;
import cern.accsoft.steering.util.meas.read.filter.ReadSelectionFilter;
import cern.accsoft.steering.util.meas.read.yasp.YaspFileReader;
import cern.accsoft.steering.util.meas.read.yasp.YaspReaderException;

/**
 * this class represents a reader for CorrectorKickData as generated by Yasp
 * 
 * @author kfuchsbe
 */
public class YaspCorrectorKickDataReader extends YaspFileReader implements CorrectorKickDataReader {

    // possible elements of the filename
    private final static String FILENAME_PREFIX = "RM";
    private final static int MIN_FILENAME_COUNT_TOKENS = 6;
    private final static String FILENAME_TOKEN_DELIMITER = ".";

    /**
     * reads the data from files.
     * 
     * @throws YaspReaderException
     */
    @Override
    public CorrectorKickData read(File file, ReadSelectionFilter selection) throws YaspReaderException {
        CorrectorKickDataImpl data = new CorrectorKickDataImpl();
        parseFileName(file, data);
        super.read(file, selection, data);
        return data;
    }

    /**
     * extracts the Name of the activated Corrector-magnet out of the filename.
     * 
     * @throws YaspReaderException
     */
    void parseFileName(File file, CorrectorKickDataImpl data) throws YaspReaderException {
        if (file == null) {
            throw new YaspReaderException("File 'null' is not allowed!");
        }

        /* split path from actual filename */
        String name = file.getName();

        StringTokenizer tokenizer = new StringTokenizer(name, FILENAME_TOKEN_DELIMITER);

        int countTokens = tokenizer.countTokens();
        int countTokensOfInterest = countTokens;
        if (name.endsWith(TextFileParserImpl.EXTENSION_GZIP)) {
            countTokensOfInterest -= 1;
        }

        if (countTokensOfInterest < MIN_FILENAME_COUNT_TOKENS) {
            throw new YaspReaderException("Invalid Amount of Delimiters '" + FILENAME_TOKEN_DELIMITER
                    + "' in filename '" + name + "'.");
        }

        int count = 0;

        String correctorName = "";
        String planeToken = null;
        String signToken = null;
        while (tokenizer.hasMoreElements()) {
            String element = (String) tokenizer.nextElement();
            if (count == 0) {
                // first element: just for verification
                if (!element.equals(FILENAME_PREFIX)) {
                    throw new YaspReaderException("Missing prefix '" + FILENAME_PREFIX + "' in filename '" + name
                            + "'.");
                }
            } else if (count == (countTokensOfInterest - 3)) {
                if (element.equals(Plane.HORIZONTAL.getTag()) || element.equals(Plane.VERTICAL.getTag())) {
                    planeToken = element;
                } else {
                    throw new YaspReaderException("Unknown plane '" + element + "' in filename '" + name + "'.");
                }
            } else if (count == (countTokensOfInterest - 2)) {
                if (element.equals(DeflectionSign.PLUS.getTag()) || element.equals(DeflectionSign.MINUS.getTag())) {
                    signToken = element;
                } else {
                    throw new YaspReaderException("Unknown sign '" + element + "' in filename '" + name + "'.");
                }
            } else if ((count > 0) && (count < (countTokensOfInterest - 3))) {
                if (correctorName.length() > 0) {
                    correctorName += ".";
                }
                correctorName += element;
            }
            count++;
        }
        
        BeamNumber beamNumber = BeamNumber.fromElementName(correctorName);
        if (beamNumber == null) {
            beamNumber = BeamNumber.BEAM_1;
        }
        data.setBeamNumber(beamNumber);
        data.setCorrectorName(correctorName);
        data.setSignToken(signToken);
        data.setPlaneToken(planeToken);
    }

    /**
     * constructs fileName from correctorName, sign and (optional) measurement-number
     * 
     * @param correctorName The Corrector Name (including plane - token)
     * @param sign
     * @param measurementNumber
     * @return the Filename (without path)
     */
    public final static String constructFileName(String correctorName, DeflectionSign sign, Integer measurementNumber,
            boolean gzip) {
        if (measurementNumber == null)
            measurementNumber = 1;
        String fileName = FILENAME_PREFIX + FILENAME_TOKEN_DELIMITER + correctorName + FILENAME_TOKEN_DELIMITER
                + sign.getTag() + FILENAME_TOKEN_DELIMITER + Integer.toString(measurementNumber);
        if (gzip) {
            fileName += TextFileParserImpl.EXTENSION_GZIP;
        }
        return fileName;
    }

    /**
     * constructs fileName from correctorName and sign.
     * 
     * @param correctorName The Corrector Name (including plane - token)
     * @param sign
     * @return the Filename (without path)
     */
    public final static String constructFileName(String correctorName, DeflectionSign sign, boolean gzip) {
        return constructFileName(correctorName, sign, null, gzip);
    }

    /**
     * constructs a fileName from correctornamen, plane, sign and measurement number
     * 
     * @param correctorName the correctorname (WITHOUT plane-token)
     * @param plane the plane
     * @param sign the sign
     * @param measurementNumber
     * @return
     */
    public final static String constructFileName(String correctorName, Plane plane, DeflectionSign sign,
            Integer measurementNumber, boolean gzip) {
        return constructFileName(correctorName + FILENAME_TOKEN_DELIMITER + plane.getTag(), sign, measurementNumber,
                gzip);
    }

    /**
     * checks if the given fileName is ad Yasp-Corrector file
     * 
     * @param fileName the filename to check
     * @return true if it is a filename, false is not.
     */
    public final static boolean isCorrectorFile(String fileName) {
        if (fileName.toUpperCase().startsWith((FILENAME_PREFIX + FILENAME_TOKEN_DELIMITER).toUpperCase())) {
            return true;
        } else {
            return false;
        }
    }

}

@@ -1184,9 +1184,9 @@
 S = 
-6
+5
 ;%0A  

set the minimum amount of delimiters to 5 (MedAustron do not have dots in the corrector name)