/*
Copyright (C) 2001, 2006 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.formats.rpf;

import gov.nasa.worldwind.*;

import static java.util.logging.Level.*;

/**
 * @author dcollins
 * @version $Id: RpfFrameFilenameUtil.java 1762 2007-05-07 19:43:55Z dcollins $
 */
public class RpfFrameFilenameUtil
{
    /* [Section 30.6, MIL-C-89038] */
    /* [Section A.3.6, MIL-PRF-89041A] */
    public static final char[] BASE34_ALPHABET =
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
            'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
    private static char[] charArray;

    /* [Section 30.6, MIL-C-89038] */
    /* [Section A.3.6, MIL-PRF-89041A] */
    public static char[] base34ValueOf(int i, char[] dest, int offset, int count)
    {
        if (dest == null || dest.length < count)
            dest = new char[count];
        for (int digit = count + offset - 1; digit >= offset; digit--)
        {
            dest[digit] = BASE34_ALPHABET[i % 34];
            i /= 34;
        }
        return dest;
    }

    private static void ensureCharArray(int length)
    {
        if (charArray == null || charArray.length < length)
            charArray = new char[length];
    }

    public static String filenameFor(RpfFrameProperties frameProperties, String rpfDataType)
    {
        validateFrameProperties(frameProperties);
        if (rpfDataType == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull");
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        ensureCharArray(12);
        if (rpfDataType.compareToIgnoreCase("CADRG") == 0)
            filenameForCadrgOrCib(frameProperties, 5, 2, charArray);
        else if (rpfDataType.compareToIgnoreCase("CIB") == 0)
            filenameForCadrgOrCib(frameProperties, 6, 1, charArray);
        else
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.UnknownRpfDataType") + rpfDataType;
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        return new String(charArray, 0, 12);
    }

    public static String filenameFor(RpfFrameProperties frameProperties)
    {
        validateFrameProperties(frameProperties);
        return filenameFor(frameProperties, frameProperties.dataSeries.rpfDataType);
    }

    /* [Section 30.6, MIL-C-89038] */
    /* [Section A.3.6, MIL-PRF-89041A] */
    private static void filenameForCadrgOrCib(RpfFrameProperties frameProperties, int frameChars, int versionChars,
        char[] dest)
    {
        int index = 0;
        base34ValueOf(frameProperties.frameNumber, dest, index, frameChars);
        index += frameChars;
        base34ValueOf(frameProperties.version, dest, index, versionChars);
        index += versionChars;
        dest[index++] = frameProperties.producer.id;
        dest[index++] = '.';
        frameProperties.dataSeries.seriesCode.getChars(0, 2, dest, index);
        index += 2;
        dest[index] = frameProperties.zone.zoneCode;
    }

    /* [Section 30.6, MIL-C-89038] */
    /* [Section A.3.6, MIL-PRF-89041A] */
    public static int parseBase34(char[] src, int offset, int count)
    {
        int i = 0;
        for (int digit = offset; digit < offset + count; digit++)
        {
            int index;
            char charUpper = Character.toUpperCase(src[digit]);
            if (charUpper >= '0' && charUpper <= '9')
                index = charUpper - '0';
            else if (charUpper >= 'A' && charUpper <= 'H')
                index = 10 + charUpper - 'A';
            else if (charUpper >= 'J' && charUpper <= 'N')
                index = 18 + charUpper - 'J';
            else if (charUpper >= 'P' && charUpper <= 'Z')
                index = 23 + charUpper - 'P';
            else
            {
                String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.Base34Error");
                WorldWind.logger().log(FINE, message);
                throw new IllegalArgumentException(message);
            }
            i = (i * 34) + index;
        }
        return i;
    }

    public static RpfFrameProperties parseFilename(String filename, String rpfDataType)
    {
        if (filename == null || rpfDataType == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull");
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        if (filename.length() != 12)
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.BadFilenameLength") + filename;
            WorldWind.logger().log(FINE, message);
            throw new RpfFrameFilenameFormatException(message);
        }
        ensureCharArray(12);
        filename.getChars(0, 12, charArray, 0);
        RpfFrameProperties frameProperties;
        if (rpfDataType.compareToIgnoreCase("CADRG") == 0)
            frameProperties = parseFilenameCadrgOrCib(charArray, 5, 2);
        else if (rpfDataType.compareToIgnoreCase("CIB") == 0)
            frameProperties = parseFilenameCadrgOrCib(charArray, 6, 1);
        else
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.UnknownRpfDataType") + rpfDataType;
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        return frameProperties;
    }

    public static RpfFrameProperties parseFilename(String filename)
    {
        if (filename == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull");
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        if (filename.length() != 12)
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.BadFilenameLength") + filename;
            WorldWind.logger().log(FINE, message);
            throw new RpfFrameFilenameFormatException(message);
        }
        RpfDataSeries dataSeries;
        try
        {
            dataSeries = RpfDataSeries.dataSeriesFor(filename.substring(9, 11));
        }
        catch (EnumConstantNotPresentException e)
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.EnumNotFound");
            WorldWind.logger().log(FINE, message);
            throw new RpfFrameFilenameFormatException(message, e);
        }
        return parseFilename(filename, dataSeries.rpfDataType);
    }

    /* [Section 30.6, MIL-C-89038] */
    /* [Section A.3.6, MIL-PRF-89041A] */
    private static RpfFrameProperties parseFilenameCadrgOrCib(char[] src, int frameChars, int versionChars)
    {
        int index = 0;

        int frameNumber;
        int version;
        try
        {
            frameNumber = parseBase34(src, index, frameChars);
            index += frameChars;
            version = parseBase34(src, index, versionChars);
            index += versionChars;
        }
        catch (IllegalArgumentException e)
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.IntegerNotParsed");
            WorldWind.logger().log(FINE, message);
            throw new RpfFrameFilenameFormatException(message, e);
        }

        RpfProducer producer;
        RpfDataSeries dataSeries;
        RpfZone zone;
        try
        {
            producer = RpfProducer.producerFor(src[index]);
            index += 2;
            dataSeries = RpfDataSeries.dataSeriesFor(new String(src, index, 2));
            index += 2;
            zone = RpfZone.zoneFor(src[index]);
        }
        catch (EnumConstantNotPresentException e)
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.EnumNotFound");
            WorldWind.logger().log(FINE, message);
            throw new RpfFrameFilenameFormatException(message, e);
        }

        return new RpfFrameProperties(zone, frameNumber, dataSeries, producer, version);
    }

    private static void validateFrameProperties(RpfFrameProperties frameProperties)
    {
        if (frameProperties == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.RpfFramePropertiesIsNull");
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        if (frameProperties.zone == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.RpfZoneIsNull");
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        if (frameProperties.frameNumber < 0)
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameProperties.BadFrameNumber")
                + frameProperties.frameNumber;
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        if (frameProperties.dataSeries == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.RpfDataSeriesIsNull");
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        if (frameProperties.producer == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.RpfProducerIsNull");
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
        if (frameProperties.version < 0)
        {
            String message = WorldWind.retrieveErrMsg("RpfFrameProperties.BadVersion")
                + frameProperties.version;
            WorldWind.logger().log(FINE, message);
            throw new IllegalArgumentException(message);
        }
    }
}
