package com.jscape.crypto;

import com.jscape.util.BigEndianBits;
import com.jscape.util.EndianBits;
import com.jscape.util.LittleEndianBits;

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

/**
 * @author Alex Usun
 */
public class CRC32
        implements Hash {

    private static final int HASH_LENGTH = 4;

    private final java.util.zip.CRC32 base;
    private final EndianBits endianBits;

    public static CRC32 bigEndianHash() {
        return new CRC32(new BigEndianBits());
    }

    public static CRC32 littleEndianHash() {
        return new CRC32(new LittleEndianBits());
    }

    public CRC32(EndianBits endianBits) {
        this.base = new java.util.zip.CRC32();

        assertNotNull(endianBits);
        this.endianBits = endianBits;
    }

    @Override
    public int getLength() {
        return HASH_LENGTH;
    }

    @Override
    public Hash reset() {
        this.base.reset();
        return this;
    }

    @Override
    public Hash update(byte data) {
        this.base.update(data);
        return this;
    }

    @Override
    public Hash update(byte[] data) {
        return update(data, 0, data.length);
    }

    @Override
    public Hash update(byte[] data, int offset, int length) {
        this.base.update(data, offset, length);
        return this;
    }

    @Override
    public byte[] compute() {
        int value = (int) this.base.getValue();
        reset();

        return this.endianBits.putInt(value, new byte[4], 0);
    }

    @Override
    public byte[] compute(byte[] data) {
        return compute(data, 0, data.length);
    }

    @Override
    public byte[] compute(byte[] data, int offset, int length) {
        update(data, offset, length);
        return compute();
    }
}
