/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.munjaon.client.util;

import com.munjaon.client.server.packet.Packet;

import java.io.UnsupportedEncodingException;

/**
 * bytes 관련 유틸리티 클래스
 * @author JDS
 */
public final class ByteUtil {
    public static final int BYTE_SIZE = 128;
    /* 큐에 저장하기전에 바이트를 채울 문자 */
    public static final byte SET_DEFAULT_BYTE = (byte) 0x00;

    /**
     * bytes 배열의 핵사값을 16자리씩 개행하여 반환한다.<BR>
     * 핵사 로그 출력을 위해 사용한다.
     * @param src
     * @param isLine
     * @return 16자리씩 개행된 핵사값
     */
    public static String byteToHex(byte[] src, boolean isLine) {
        String hex = "";
        // if(src.length > 16)
        hex = "";
        for (int i = 0, j = 1; i < src.length; i++, j++) {
            hex += pad0(Integer.toHexString(src[i] & 0xff), 2) + " ";

            if (isLine && src.length > 16 && (j % 16) == 0) {
                // hex += " " + new String(codes, j-16, 16);
                hex += "\r\n";
            }
        }
        return hex;
    }

    /**
     * bytes 배열의 핵사값을 16자리씩 개행하여 반환한다.<BR>
     * 핵사 로그 출력을 위해 사용한다.
     * @param src
     * @return 16자리씩 개행된 핵사값
     */
    public static String byteToHex(byte[] src) {
        String hex = "";
        // if(src.length > 16)
        //hex = "\r\n";
        for (int i = 0, j = 1; i < src.length; i++, j++) {
            hex += pad0(Integer.toHexString(src[i] & 0xff), 2) + " ";

            if (src.length > 16 && (j % 16) == 0) {
                // hex += " " + new String(codes, j-16, 16);
                hex += "\r\n";
            }
        }
        return hex;
    }

    /**
     * bytes 배열의 지정된 위치값에 대해 16자리씩 개행된 핵사값으로 반환한다.<BR>
     * 핵사 로그 출력을 위해 사용한다.
     * @param src
     * @param srcPos
     * @param length
     * @return 16자리씩 개행된 핵사값
     */
    public static String byteToHex(byte[] src, int srcPos, int length) {
        String hex = "";
        //if(src.length > 16)
        hex = "\r\n";
        for (int i = srcPos, j = 1; i < srcPos + length; i++, j++) {
            hex += pad0(Integer.toHexString(src[i] & 0xff), 2) + " ";
            if (src.length > 16 && (j % 16) == 0) {
                hex += "\r\n";
            }
        }
        return hex;
    }
    
    public static String intToHex(int src) {
        String hex = "0x";
        byte[] bSrc = ByteUtil.intToByte(src);
        for (int i = 0, j = 1; i < bSrc.length; i++, j++) {
            hex += pad0(Integer.toHexString(bSrc[i] & 0xff), 2);
        }
        return hex;
    }

    public static byte[] shortToByte(short s) {
        byte dest[] = new byte[2];
        dest[1] = (byte) (s & 0xff);
        dest[0] = (byte) (s >>> 8 & 0xff);
        return dest;
    }

    public static byte[] intToByte(int i) {
        byte dest[] = new byte[4];
        dest[3] = (byte) (i & 0xff);
        dest[2] = (byte) (i >>> 8 & 0xff);
        dest[1] = (byte) (i >>> 16 & 0xff);
        dest[0] = (byte) (i >>> 24 & 0xff);
        return dest;
    }

    public static byte[] longToByte(long l) {
        byte dest[] = new byte[8];
        dest[7] = (byte) (int) (l & 255L);
        dest[6] = (byte) (int) (l >>> 8 & 255L);
        dest[5] = (byte) (int) (l >>> 16 & 255L);
        dest[4] = (byte) (int) (l >>> 24 & 255L);
        dest[3] = (byte) (int) (l >>> 32 & 255L);
        dest[2] = (byte) (int) (l >>> 40 & 255L);
        dest[1] = (byte) (int) (l >>> 48 & 255L);
        dest[0] = (byte) (int) (l >>> 56 & 255L);
        return dest;
    }

    public static byte[] floatToByte(float f) {
        byte dest[] = new byte[4];
        return setFloat(dest, 0, f);
    }

    public static byte[] doubleToByte(double d) {
        byte dest[] = new byte[8];
        return setDouble(dest, 0, d);
    }

    public static byte getByte(byte src[], int offset) {
        return src[offset];
    }

    public static byte[] getBytes(String data) throws UnsupportedEncodingException {
        byte[] b = null;

        b = data.getBytes(Packet.AGENT_CHARACTER_SET);

        return (b);
    }
    
    public static byte[] getBytes(byte src[], int offset, int length) {
        byte dest[] = new byte[length];
        System.arraycopy(src, offset, dest, 0, length);
        return dest;
    }

    public static short getShort(byte src[], int offset) {
        return (short) ((src[offset] & 0xff) << 8 | src[offset + 1] & 0xff);
    }

    public static int getInt(byte src[], int offset) {
        return (src[offset] & 0xff) << 24 | (src[offset + 1] & 0xff) << 16
                | (src[offset + 2] & 0xff) << 8 | src[offset + 3] & 0xff;
    }

    public static long getLong(byte src[], int offset) {
        return (long) getInt(src, offset) << 32
                | (long) getInt(src, offset + 4) & 0xffffffffL;
    }

    public static float getfloat(byte src[], int offset) {
        return Float.intBitsToFloat(getInt(src, offset));
    }

    public static double getdouble(byte src[], int offset) {
        return Double.longBitsToDouble(getLong(src, offset));
    }

    public static byte[] setByte(byte dest[], int offset, byte b) {
        dest[offset] = b;
        return dest;
    }

    public static void setBytes(byte[] dest, int offset, String s) throws UnsupportedEncodingException {
        setBytes(dest, offset, s.getBytes(Packet.AGENT_CHARACTER_SET));
    }

    public static byte[] setBytes(byte dest[], int offset, byte src[]) {
        System.arraycopy(src, 0, dest, offset, src.length);
        return dest;
    }

    public static byte[] setBytes(byte dest[], int offset, byte src[],
            int len) {
        System.arraycopy(src, 0, dest, offset, len);
        return dest;
    }

    public static byte[] setShort(byte dest[], int offset, short s) {
        dest[offset] = (byte) (s >>> 8 & 0xff);
        dest[offset + 1] = (byte) (s & 0xff);
        return dest;
    }

    public static byte[] setInt(byte dest[], int offset, int i) {
        dest[offset] = (byte) (i >>> 24 & 0xff);
        dest[offset + 1] = (byte) (i >>> 16 & 0xff);
        dest[offset + 2] = (byte) (i >>> 8 & 0xff);
        dest[offset + 3] = (byte) (i & 0xff);
        return dest;
    }

    public static byte[] setLong(byte dest[], int offset, long l) {
        setInt(dest, offset, (int) (l >>> 32));
        setInt(dest, offset + 4, (int) (l & 0xffffffffL));
        return dest;
    }

    public static byte[] setFloat(byte dest[], int offset, float f) {
        return setInt(dest, offset, Float.floatToIntBits(f));
    }

    public static byte[] setDouble(byte dest[], int offset, double d) {
        return setLong(dest, offset, Double.doubleToLongBits(d));
    }

    public static boolean isEquals(byte b[], String s) {
        if (b == null || s == null)
            return false;
        int slen = s.length();
        if (b.length != slen)
            return false;
        for (int i = slen; i-- > 0;)
            if (b[i] != s.charAt(i))
                return false;

        return true;
    }

    public static boolean isEquals(byte a[], byte b[]) {
        if (a == null || b == null)
            return false;
        if (a.length != b.length)
            return false;
        for (int i = a.length; i-- > 0;)
            if (a[i] != b[i])
                return false;

        return true;
    }

    public static int hexToInt(byte[] b) {
        int sum = 0;
        int len = 0;
        int pos = 0;

        if (b != null) {
            len = b.length;

            for (int i = len - 1; i > 0; i--) {
                sum += sqrt(BYTE_SIZE, i) * (int) b[pos];
                pos++;
            }
            sum += b[pos];
        }

        return (sum);
    }

    public static int hexToInt(byte[] b, int start, int len) {
        int sum = 0;
        int pos = start;

        if (b != null) {
            for (int i = len - 1; i > 0; i--) {
                sum += sqrt(BYTE_SIZE, i) * (int) b[pos];
                pos++;
            }
            sum += b[pos];
        }

        return (sum);
    }

    public static byte[] intToHex(int num, int digit) {
        byte[] b = new byte[digit];
        int[] intArr = makeFunction(num, digit, BYTE_SIZE);

        for (int i = 0; i < digit; i++) {
            b[i] = (byte) intArr[i];
        }

        return (b);
    }

    private static int[] makeFunction(int num, int digit, int jinso) {
        int[] fun = new int[digit];
        int restNum = num;
        int pos = 0;

        for (int i = digit - 1; i > 0; i--) {
            int quotient = restNum / sqrt(jinso, i);
            fun[pos++] = quotient;
            restNum -= (quotient * sqrt(jinso, i));
        }
        fun[pos++] = restNum;

        return (fun);
    }

    private static int sqrt(int num, int count) {
        int sum = 0;

        sum = (count >= 1) ? num : 0;
        for (int i = 1; i < count; i++) {
            sum = sum * num;
        }

        return (sum);
    }

    public static boolean arrayComp(byte[] src, byte[] obj) {
        boolean isSame = true;

        if (src.length != obj.length) {
            isSame = false;
        } else {
            for (int i = 0; i < src.length; i++) {
                if (src[i] != obj[i]) {
                    isSame = false;
                    break;
                }
            }
        }

        return (isSame);
    }

    public static String pad0(String str, int size) {
        char[] zeros = new char[size - str.length()];
        for (int i = 0; i < zeros.length; i++)
            zeros[i] = '0';
        return new String(zeros) + str;
    }

    public static byte[] convertCharArrayToByteArray(char[] ca) {
        byte[] ba = new byte[ca.length*2];
        java.nio.ByteBuffer.wrap(ba).asCharBuffer().put(ca);
        return ba;
    }

    public static char[] convertByteArrayToCharArray(byte[] ba) {
        char[] ca = new char[ba.length/2];
        java.nio.ByteBuffer.wrap(ba).asCharBuffer().get(ca);
        return ca;
    }

    public static byte[] setNull(byte[] b) {
        for(int i=0; i<b.length; i++) {
            b[i] = 0x00;
        }
        return b;
    }
    

    // Big Endian: network order
    public static int toInt(byte[] value) {
        return (int)(
                (value[3] & 0xff) |
                (value[2] & 0xff) << 8 |
                (value[1] & 0xff) << 16 |
                (value[0] & 0xff) << 24 );
    }

    // Big Endian: network order
    public static byte[] toBytes(int value) {
        byte[] ret = new byte[4];
        
        ret[3] = (byte)(value & 0xff);
        ret[2] = (byte)(value >> 8 & 0xff);
        ret[1] = (byte)(value >> 16 & 0xff);
        ret[0] = (byte)(value >> 24 & 0xff);

        return ret;
    }

    // Little Endian
    public static int toInt2(byte[] value) {
        return (int)(
                (value[0] & 0xff) |
                (value[1] & 0xff) << 8 |
                (value[2] & 0xff) << 16 |
                (value[3] & 0xff) << 24 );
    }

    // Little Endian
    public static byte[] toBytes2(int value) {
        byte[] ret = new byte[4];

        ret[0] = (byte)(value & 0xff);
        ret[1] = (byte)(value >> 8 & 0xff);
        ret[2] = (byte)(value >> 16 & 0xff);
        ret[3] = (byte)(value >> 24 & 0xff);

        return ret;
    }

    public static byte[] setSpaceAll(byte[] data) {
        return setAll(data, (byte) ' ');
    }

    public static byte[] setAll(byte[] data, byte bt) {
        int len = data.length;
        
        for( int i=0; i<len; i++ ) {
            data[i] = bt;
        }

        return data;
    }

    public static byte[] replaceAll(byte[] data, byte from, byte to) {
        int len = data.length;

        for( int i=0; i<len; i++ ) {
            if( data[i] == from ) {
                data[i] = to;
            }
        }

        return data;
    }
}
