/***************************************************************************
  PointPackX.java

  Revision of PointPack, Chapter 8, page 140 of
  "The Java Handbook" (Osborne McGraw-Hill)

  The original source prints out the "thawed," i.e., unpacked
  decimal values but does not print the "packed" array.

  Code has been added to accomplish this.

  (This PointPackX is, in turn, a revision of an earlier PointPackX.
   Method System.arraycopy() replaces a for(...) loop in order
   to copy an array, and the cumbersome use of a Hashtable
   object has been replaced with a much simpler use of a
   StringBuffer object.)

  ***************************************************************************/

interface Packable {
    byte[] pack();
    void unpack(byte raw[]);
}

class Point {
    int x, y;
    Point(int x, int y) {
	this.x = x;
	this.y = y;
    }
}

class NewPoint extends Point implements Packable {
    NewPoint(int x, int y) {
        super(x, y);
    }
    NewPoint() {
	this(0, 0);
    }
    private byte p(int t, int n) {
	return (byte)((t>>n) & 0xff);
    }
    public byte pack()[] {
        byte ret[] = new byte[8];
        ret[0] = p(x, 24);
        ret[1] = p(x, 16);
        ret[2] = p(x, 8);
        ret[3] = p(x, 0);
        ret[4] = p(y, 24);
        ret[5] = p(y, 16);
        ret[6] = p(y, 8);
        ret[7] = p(y, 0);
        return ret;
    }
    private int u(byte b, int n) {
	return (b & 0xff) << n;
    }
    public void unpack(byte raw[]) {
        x = u(raw[0], 24) | u(raw[1], 16) | u(raw[2], 8) | u(raw[3], 0);
        y = u(raw[4], 24) | u(raw[5], 16) | u(raw[6], 8) | u(raw[7], 0);
    }

    public String toString() {
	return "NewPoint[" + x + "," + y + "]";
    }

}

// ADDED:
class DecToHex {

	private StringBuffer hexValue = new StringBuffer("0123456789abcdef");

	public char toHex(int v) {
		return hexValue.charAt(v);
	}

} // DecToHex

// ADDED:
class PackedArray {

	private byte[] packed;
	private int packedLength;
	private DecToHex dth = new DecToHex();
	private StringBuffer sb = new StringBuffer();
	private String SPACE = " ";

	PackedArray(byte[] packed) {
		AssignPacked(packed);
		ConvertPacked();
	}

	private void AssignPacked(byte[] packed) {
		this.packed = new byte[packedLength = packed.length];
		System.arraycopy(packed, 0, this.packed, 0, packedLength);
	}

	private void ConvertPacked() {
		int n;
		int packedLengthIndex = packedLength - 1;

		for (int i = 0; i < packedLength; i++) {
			// left nybble (mask out low-order bits
			// before shifting!):
			n = (packed[i] & 0xF0) >>> 4;
			sb.append(dth.toHex(n));
			// right nybble:
			n = packed[i] & 0x0F;
			sb.append(dth.toHex(n));
			if (i != (packedLengthIndex))
				sb.append(SPACE);
		}
	}
	
	public String toString() {
		return new String(sb);
	}

} // PackedArray

class PointPackX {
    public static void main(String args[]) {
	Packable p = new NewPoint(123456789, 2147483647);
	byte packed[] = p.pack();
	NewPoint thawed = new NewPoint();
	thawed.unpack(packed);
	// System.out.println("p  = " + thawed); // ORIGINAL LINE
	// ADDED:
	PackedArray packed_array = new PackedArray(packed);
	System.out.println(packed_array + " = " + thawed);
    }
}
