/*
 * @(#)HexFormat.java
 *
 * Copyright (c) 2002-2003 JSCAPE
 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JSCAPE. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 * the terms of the license agreement you entered into with JSCAPE.
 */

package com.jscape.util;

import static com.jscape.util.Parameters.assertArrayValid;
import static com.jscape.util.Parameters.assertNotNull;

/**
 * Hex format.
 *
 * @author Alex
 */
public final class HexFormat
        implements BinaryDataFormat {

    public static final String DEFAULT_SEPARATOR = ":";

    private final String separator;

    public static String formatData(byte[] data) {
        if (data == null) {
            return "";
        }
        
        return formatData(data, 0, data.length);
    }

    public static String formatData(byte[] data, int offset, int length) {
        return formatData(data, offset, length, DEFAULT_SEPARATOR);
    }

    public static String formatData(byte[] data, String separator) {
        if (data == null) {
            return "";
        }
        
        return formatData(data, 0, data.length, separator);
    }

    public static String formatData(byte[] data, int offset, int length, String separator) {
        return new HexFormat(separator).format(data, offset, length);
    }

    public static byte[] parseData(String data) {
        return parseData(data, DEFAULT_SEPARATOR);
    }

    public static byte[] parseData(String data, String separator) {
        return new HexFormat(separator).parse(data);
    }

    public HexFormat(String separator) {
        assertNotNull(separator);
        this.separator = separator;
    }

    public HexFormat() {
        this(DEFAULT_SEPARATOR);
    }

    public String format(byte[] data) {
        if (data == null) {
            return "";
        }
        
        return format(data, 0, data.length);
    }

    public String format(byte[] data, int offset, int length) {
        if (data == null) {
            return "";
        }
        
        assertArrayValid(data, offset, length);

        StringBuilder buffer = new StringBuilder();

        for (int i = 0; i < length; ++i) {
            buffer.append(i > 0 ? this.separator : "").append((data[offset + i] & 0xFF) <= 0xF ? "0" : "").append(Integer.toHexString(data[offset + i] & 0xFF));
        }

        return buffer.toString();
    }

    /**
     * @see com.jscape.util.BinaryDataFormat#parse(String)
     */
    public byte[] parse(String data) {
        assertNotNull(data);

        if (this.separator.length() == 0) {
            return parseNonSeparatedValue(data);
        }

        String[] values = StringTools.split(data, this.separator, false);
        byte[] bytes = new byte[values.length];

        for (int i = 0; i < values.length; ++i) {
            bytes[i] = (byte) Integer.parseInt(values[i], 16);
        }

        return bytes;
    }

    private byte[] parseNonSeparatedValue(String data) {
        byte[] bytes = new byte[data.length() / 2];

        for (int i = 0, b = 0; i < data.length(); i += 2, ++b) {
            String value = data.substring(i, Math.min(i + 2, data.length()));
            bytes[b] = (byte) Integer.parseInt(value, 16);
        }

        return bytes;
    }
}
