package net.mcforkage.ant.compression;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public abstract class HuffmanNode<T> {
public static class Leaf<T> extends HuffmanNode<T> {
public T value;
public Leaf(T value, int freq) {
this.value = value;
this.freq = freq;
}
@Override
void initCodes(HuffmanNode<T> parent, boolean nextBit, HuffmanTable<T> table) {
super.initCodes(parent, nextBit, table);
table.valueToNode.put(value, this);
}
@Override
public void writeTree(BitOutputStream out) throws IOException {
out.write(false);
if(value instanceof Integer) {
new DataOutputStream(out).writeInt((Integer)value);
} else if(value instanceof Character) {
new DataOutputStream(out).writeChar((Character)value);
} else
throw new RuntimeException("Can't write "+value);
}
@Override
public void accept(HuffmanTreeVisitor<T> v) {
v.visit(this);
}
@Override
public T getRepresentativeValue() {
return value;
}
@Override
public T read(BitInputStream in) throws IOException {
return value;
}
}
public static class Node<T> extends HuffmanNode<T> {
public HuffmanNode<T> c0, c1;
public Node(HuffmanNode<T> c0, HuffmanNode<T> c1) {
this.c0 = c0;
this.c1 = c1;
this.freq = c0.freq + c1.freq;
}
@Override
void initCodes(HuffmanNode<T> parent, boolean nextBit, HuffmanTable<T> table) {
super.initCodes(parent, nextBit, table);
c0.initCodes(this, false, table);
c1.initCodes(this, true, table);
}
@Override
public void writeTree(BitOutputStream out) throws IOException {
out.write(true);
c0.writeTree(out);
c1.writeTree(out);
}
@Override
public void accept(HuffmanTreeVisitor<T> v) {
v.visit(this);
}
@Override
public T getRepresentativeValue() {
return c0.getRepresentativeValue();
}
@Override
public T read(BitInputStream in) throws IOException {
return (in.readBit() ? c1 : c0).read(in);
}
}
public int freq;
public boolean[] code;
void initCodes(HuffmanNode<T> parent, boolean nextBit, HuffmanTable<T> table) {
if(parent == null)
code = new boolean[0];
else {
code = new boolean[parent.code.length + 1];
System.arraycopy(parent.code, 0, code, 0, parent.code.length);
code[parent.code.length] = nextBit;
}
}
public abstract void writeTree(BitOutputStream out) throws IOException;
public abstract void accept(HuffmanTreeVisitor<T> v);
public abstract T getRepresentativeValue();
public static <T> HuffmanNode<T> readTree(BitInputStream in, Class<T> valueType) throws IOException {
if(in.readBit())
return new Node<T>(readTree(in, valueType), readTree(in, valueType));
else {
Leaf<T> l = new Leaf<T>(null, 0);
if(valueType == Integer.class) {
l.value = valueType.cast(new DataInputStream(in).readInt());
} else if(valueType == Character.class) {
l.value = valueType.cast(new DataInputStream(in).readChar());
} else
throw new RuntimeException("Can't read "+valueType);
return l;
}
}
public abstract T read(BitInputStream in) throws IOException;
}