package com.eactive.eai.transformer.util;

import java.io.PrintWriter;

public final class HexUtil {
    /** maximum int value that can be converted to char */
    public static final int MAX_CHAR_INT = 35;
    
    private HexUtil() {
    	
    }
    
    /**
    *   encodes a string of 4-digit hex numbers to unicode
    *   <br />
    *   Note: this method is slower than hexToString(String,StringBuilder)
    *   @param hex string of 4-digit hex numbers
    *   @return normal java string 
    */
    /*
    public static final String hex2Ascii (String hex) {
        if (hex == null) return "";
        int length = hex.length() & -4;
        StringBuilder result = new StringBuilder(length/4);
        hexToString(hex, result);
        return result.toString();
    }
    */
    public static final String hex2Ascii (String hex) {
        if (hex == null) return "";
        int length = hex.length() & -4;
        byte[] result = new byte[length/4];
        hexToString(hex, result);
        return new String(result);
    }
    
    public static final byte[] hex2bytes(String hex) {
        if (hex == null) return (new byte[0]);
        int length = hex.length() & -4;
        byte[] result = new byte[length/4];
        hexToString(hex, result);
        return result;
    }

    protected static final void hexToString (String hex, byte[] out) {
        if ( hex == null ) return;
        int length = hex.length() & -4;

        for ( int pos=0; pos < length; pos += 4) {
            int thisChar = 0;
            try {
            	String hex1 = hex.substring( pos+2,pos+4); 
            	thisChar = Integer.parseInt(hex1 , 16);
            }
            catch ( NumberFormatException e) { 
                /* dont care*/
            	thisChar = 0;
            }
            out[pos/4] = (byte)thisChar;
        }

    }
    /**
    *   encodes a unicode string to a string of 4-digit hex numbers
    *   <br />
    *   Note: this method is slower than stringToHex(String,StringBuilder)
    *   @param java normal java string
    *   @return string of 4-digit hex numbers
    */
    public static final String string2Hex (String stringValue) {
        if ( stringValue == null ) return "";
        int length = stringValue.length();
        StringBuilder result = new StringBuilder( length*4 );
        stringToHex(stringValue, result);
        return result.toString();
    }
 
    /**
    *   encodes a unicode string to a string of 4-digit hex numbers
    *   @param java normal java string
    *   @param out string of 4-digit hex numbers
    */
    protected static final void stringToHex ( String stringValue, StringBuilder out ) {
        if ( stringValue == null ) return;
        int length = stringValue.length();
        for ( int pos=0; pos < length; pos ++) {
            int thisChar = stringValue.charAt( pos);
            for ( int digit = 0; digit < 4; digit ++ ) {
                int thisDigit = thisChar & 0xf000;
                thisChar = thisChar << 4;
                thisDigit = (thisDigit >> 12);
                if ( thisDigit >= 10 )
                    out.append ( (char)( thisDigit+87));
                else
                    out.append ( (char)( thisDigit+48));
            }
        }
    }
 
    /**
    *   encodes a unicode string to a string of 4-digit hex numbers
    *   @param java normal java string
    *   @param out string of 4-digit hex numbers
    */
    public static final void stringToHex ( String stringValue, PrintWriter out ) {
        if ( stringValue == null ) return;
        int length = stringValue.length();
        for ( int pos=0; pos < length; pos ++) {
            int thisChar = stringValue.charAt( pos);
            for ( int digit = 0; digit < 4; digit ++ ) {
                int thisDigit = thisChar & 0xf000;
                thisChar = thisChar << 4;
                thisDigit = (thisDigit >> 12);
                if ( thisDigit >= 10 )
                    out.print ( (char)( thisDigit+87));
                else
                    out.print ( (char)( thisDigit+48));
            }
        }
    }
 
    /** 
    *   checks, if the parameter is a decimal number 
    */
    public static final boolean isDecimalNumber ( String stringValue) {
        int fixSize = stringValue.length();
        if ( fixSize == 0 ) return false;
        int dotcount = 0;
        for ( int pos = 0; pos < fixSize; pos ++ ) {
            char probe = stringValue.charAt(pos);
            if (!((( probe >= '0' ) && ( probe <= '9' ))
                || (( pos == 0) && ( probe == '-' ))
                || (( pos > 0) && (probe == '.' )))) 
            {
                return false;
            }
            if ( probe == '.' ) {
                dotcount ++;
                if ( dotcount > 1 ) return  false;
            }
        }
        return true;
    }
    
    /**
    *   converts a one-digit number to an int (base 36)
    *   <br />
    *   Note: the result is undefined, if parameter is out of range
    */
    public static final int charToInt( char base36) {
        if ( base36 <= '9')
            if ( base36 >= '0') {
                return ((int)( base36 - '0'));
            } else {
                return 0;
            }
        else if ( base36 < 'a')
            if ( base36 <= 'Z') {
                return ((int)( base36 - 'A'))+10;
            } else {
                return 0;
            }
        else 
            if ( base36 <= 'z') {
                return ((int)( base36 - 'a'))+10;
            } else {
                return 0;
            }
    }
    
    /**
    *   converts an int number between 0 and 36 to a char (base 36)
    *   <br />
    *   Note: the result is undefined, if parameter is out of range
    */
    public static final char intToChar( int zeroTo36) {
        if ( zeroTo36 <= 9)
            if ( zeroTo36 >= 0)
                return (char)( zeroTo36 + ((int)'0'));
            else
                return 0;
        else 
            if ( zeroTo36 < 36)
                return (char)( zeroTo36-10 + ((int)'a'));
            else
                return 0;
    }
    
    /**
    *   converts an int number to hexadecimal representation
    */
    public static final void intToHex( int x, StringBuilder out) {
        for ( int pos = 0; pos < 8; pos ++ ) 
            out.append( intToChar((x>>>(28-(pos*4)))&0xf));
    }
    
    /**
    *   converts an UTC time to local time 
    *   or local time to UTC.
    *   @param Time string representing the time
    *   @param Minutes minutes to be added to Time
    *   @return String where minutes are added to Time 
    *           or null in case of errors
    */
    public static String addToTime( String timeString, long min ) { 
        String result = null;
        try {
            //  complete waste of memory - but how else do i convert this?
            result = ( new java.sql.Timestamp (
                java.sql.Timestamp.valueOf( timeString ).getTime() + ( min * 60000)))
                .toString();
        }
        catch ( RuntimeException ex) {
        	result = "";
        }
        return result;
    }

    /**
    *   replaces several characters in a string and writes the result to a printwriter
    *   @param original string that shall be converted and copied to out
    *   @param badGuys characters that shall be replaced
    *   @param goodGuys replacements for badGuys
    *   @param out PrintWriter to which the result is written
    */
    public static void replace ( String original, char[] badGuys, String[] goodGuys, 
        PrintWriter out) 
    { 
        //  check + init params:
        if ( original == null ) return;
        int startOutputAt = 0;      //  this variable indicates 
                                    //  which chars haven't yet been printed
        int countRules = badGuys.length;

        //  do the transformation:
        int origLength = original.length();
        for ( int pos = 0; pos < origLength; pos ++ ) {
            //  get + init params:
            char probe = original.charAt(pos); //  character at current string position
            String appendAfterFlush = null; //  string, the current charater shall be replaced by
            
            //  is this a bad character:
            for ( int rule = 0; rule < countRules; rule ++ )
                if ( probe == badGuys[rule]) { appendAfterFlush = goodGuys[rule]; }
                
            //  flush if bad character found:
            if ( appendAfterFlush != null) {
                out.print( original.substring( startOutputAt, pos));
                out.print( appendAfterFlush);
                startOutputAt = pos+1;
            }
            
            //  if this is the last character, print the tail of the string
            if ( (pos+1)==origLength ) 
                out.print( original.substring( startOutputAt));
        }
    }
    
    /**
    *   encodes a string of 2-digit hex numbers to unicode
    *   <br />
    *   Note: this method is slower than hexToString(String,StringBuilder)
    *   @param hex string of 2-digit hex numbers
    *   @return normal java string 
    */
    public static final String hex2Ascii2Digit (String hex) {
        if (hex == null) return "";
        int length = hex.length() & -2;
        StringBuilder result = new StringBuilder(length/2);
        hexToString2Digit(hex, result);
        return result.toString();
    }

    /**
    *   encodes a string of 2-digit hex numbers to unicode
    *   @param hex string of 2-digit hex numbers
    *   @param out normal java string 
    */
    protected static final void hexToString2Digit (String hex, StringBuilder out) {
        if ( hex == null ) return;
        int length = hex.length() & -2;
        for ( int pos=0; pos < length; pos += 2) {
            int thisChar = 0;
            try { 
            	thisChar = Integer.parseInt( hex.substring( pos,pos+2), 16);
            } catch ( NumberFormatException e) { 
                /* dont care*/
            	thisChar = 0;
            }
            out.append( (char) thisChar);
        }
    }

    /**
    *   encodes a unicode string to a string of 2-digit hex numbers
    *   <br />
    *   Note: this method is slower than stringToHex(String,StringBuilder)
    *   @param java normal java string
    *   @return string of 2-digit hex numbers
    */
    public static final String string2Hex2Digit ( String java ) {
        if ( java == null ) return "";
        int length = java.length();
        StringBuilder result = new StringBuilder( length*2);
        stringToHex2Digit( java, result);
        return result.toString();
    }
 
    /**
    *   encodes a unicode string to a string of 2-digit hex numbers
    *   @param java normal java string
    *   @param out string of 2-digit hex numbers
    */
    protected static final void stringToHex2Digit ( String stringValue, StringBuilder out ) {
        if (stringValue == null) return;
        
        for (int pos=0; pos < stringValue.length(); pos ++) {
            int this_char = (int) stringValue.charAt(pos);
            out.append(Integer.toHexString(this_char));
        }
    }
}

