class MGRSConverter {

    public UTM convertToUTM(String input)
    {
        String mgrsString = input.replaceAll("\\s+", "");
        // Only a valid mgrs string if we have an odd number in the range of 3
        // to 15
        if (!validateMGRSString(mgrsString))
        {
            return null;
        }

        try
        {
            int zone = Integer.parseInt(mgrsString.substring(0, 2));
            char latitudeBand = mgrsString.charAt(2);

            Character squareLetter1 = null;
            Character squareLetter2 = null;
            String remainingDigits = null;

            if (mgrsString.length() > 4)
            {
                squareLetter1 = Character.valueOf(mgrsString.charAt(3));
                squareLetter2 = Character.valueOf(mgrsString.charAt(4));

                remainingDigits = mgrsString.substring(5);
            }

            // Default values of 0 will be lower left. Values of 50000 will be
            // in middle (which could put us outside of UTM zone when we are
            // clipped on the border).
            int easting = 50000;
            int northing = 50000;

            // Check to see we have northing/easting values. If not use default
            // values.
            if (remainingDigits != null && !remainingDigits.isEmpty())
            {
                int precision = remainingDigits.length() / 2;

                // easting and northing in (meters). Precision 1 = 10km, 2 =
                // 1km, 3 = 100m, 4 = 10m, 5 = 1m
                easting = Integer.parseInt(remainingDigits.substring(0, precision)) * (int)Math.pow(10, 5 - precision);
                northing = Integer.parseInt(remainingDigits.substring(precision, remainingDigits.length()))
                        * (int)Math.pow(10, 5 - precision);
            }

            // Now convert to UTM
            // Check for special zones that shouldn't exist.
            if (latitudeBand == 'X' && (zone == 32 || zone == 34 || zone == 36))
            {
                LOGGER.error("Unable to process zone X" + zone + " (shouldn't exist).");
                return null;
            }

            // Now find the letter range for mgrs grid letter.
            int sqLetter1LowValue = findLowValueIndex(zone);
            int sqLetter1HighValue = findHighValueIndex(zone);

            // Find false northing at A for second letter of grid square
            double falseNorthing = 0.;
            if (zone % 2 == 0)
            {
                final double onePointFiveMil = 1500000.0;
                falseNorthing = onePointFiveMil;
            }

            if (squareLetter1 != null && squareLetter2 != null
                    && (ALPHABET.indexOf(squareLetter1.charValue()) < sqLetter1LowValue
                            || ALPHABET.indexOf(squareLetter1.charValue()) > sqLetter1HighValue
                            || ALPHABET.indexOf(squareLetter2.charValue()) > LETTER_V))
            {
                LOGGER.error("Out of Range Error - Square Letter 1: " + squareLetter1 + " Range: " + sqLetter1LowValue + " - "
                        + sqLetter1HighValue);
                LOGGER.error("                     Square Letter 2: " + squareLetter2);
                return null;
            }

            LatitudeBandData bandData = getLatitudeBand(ALPHABET.indexOf(latitudeBand));
            if (bandData == null)
            {
                return null;
            }

            // Determine the hemisphere
            Hemisphere hemisphere = determineHemisphere(latitudeBand);

            // Find grid easting and grid northing values
            double gridEasting = findGridEasting(squareLetter1, squareLetter2, sqLetter1LowValue, sqLetter1HighValue);
            double gridNorthing = findGridNorthing(squareLetter1, squareLetter2, bandData, falseNorthing);

            double utmEasting = gridEasting + easting;
            double utmNorthing = gridNorthing + northing;

            return new UTM(zone, hemisphere, utmEasting, utmNorthing);
        }
        catch (NumberFormatException nfe)
        {
            if (LOGGER.isDebugEnabled())
            {
                LOGGER.debug("Exception : " + nfe.getMessage());
            }
            return null;
        }
        catch (IndexOutOfBoundsException ioobe)
        {
            if (LOGGER.isDebugEnabled())
            {
                LOGGER.debug("Exception : " + ioobe.getMessage());
            }
            return null;
        }
    }

    public  MGRSConverter();

}