// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.crypto.digests;

import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.ExtendedDigest;

abstract class BufferBaseDigest implements ExtendedDigest
{
    protected int DigestSize;
    protected int BlockSize;
    protected byte[] m_buf;
    protected int m_bufPos;
    protected String algorithmName;
    protected ProcessingBuffer processor;
    
    protected BufferBaseDigest(final ProcessingBufferType processingBufferType, final int blockSize) {
        this.BlockSize = blockSize;
        this.m_buf = new byte[blockSize];
        switch (processingBufferType.ord) {
            case 0: {
                this.processor = new BufferedProcessor();
                break;
            }
            case 1: {
                this.processor = new ImmediateProcessor();
                break;
            }
        }
    }
    
    @Override
    public String getAlgorithmName() {
        return this.algorithmName;
    }
    
    @Override
    public int getDigestSize() {
        return this.DigestSize;
    }
    
    @Override
    public int getByteLength() {
        return this.BlockSize;
    }
    
    @Override
    public void update(final byte b) {
        this.processor.update(b);
    }
    
    @Override
    public void update(final byte[] array, int n, int bufPos) {
        this.ensureSufficientInputBuffer(array, n, bufPos);
        final int n2 = this.BlockSize - this.m_bufPos;
        if (this.processor.isLengthWithinAvailableSpace(bufPos, n2)) {
            System.arraycopy(array, n, this.m_buf, this.m_bufPos, bufPos);
            this.m_bufPos += bufPos;
            return;
        }
        if (this.m_bufPos > 0) {
            System.arraycopy(array, n, this.m_buf, this.m_bufPos, n2);
            n += n2;
            bufPos -= n2;
            this.processBytes(this.m_buf, 0);
        }
        while (this.processor.isLengthExceedingBlockSize(bufPos, this.BlockSize)) {
            this.processBytes(array, n);
            n += this.BlockSize;
            bufPos -= this.BlockSize;
        }
        System.arraycopy(array, n, this.m_buf, 0, bufPos);
        this.m_bufPos = bufPos;
    }
    
    @Override
    public int doFinal(final byte[] array, final int n) {
        this.ensureSufficientOutputBuffer(array, n);
        this.finish(array, n);
        this.reset();
        return this.DigestSize;
    }
    
    @Override
    public void reset() {
        Arrays.clear(this.m_buf);
        this.m_bufPos = 0;
    }
    
    protected void ensureSufficientInputBuffer(final byte[] array, final int n, final int n2) {
        if (n + n2 > array.length) {
            throw new DataLengthException("input buffer too short");
        }
    }
    
    protected void ensureSufficientOutputBuffer(final byte[] array, final int n) {
        if (this.DigestSize + n > array.length) {
            throw new OutputLengthException("output buffer is too short");
        }
    }
    
    protected abstract void processBytes(final byte[] p0, final int p1);
    
    protected abstract void finish(final byte[] p0, final int p1);
    
    private class BufferedProcessor implements ProcessingBuffer
    {
        @Override
        public void update(final byte b) {
            if (BufferBaseDigest.this.m_bufPos == BufferBaseDigest.this.BlockSize) {
                BufferBaseDigest.this.processBytes(BufferBaseDigest.this.m_buf, 0);
                BufferBaseDigest.this.m_bufPos = 0;
            }
            BufferBaseDigest.this.m_buf[BufferBaseDigest.this.m_bufPos++] = b;
        }
        
        @Override
        public boolean isLengthWithinAvailableSpace(final int n, final int n2) {
            return n <= n2;
        }
        
        @Override
        public boolean isLengthExceedingBlockSize(final int n, final int n2) {
            return n > n2;
        }
    }
    
    protected interface ProcessingBuffer
    {
        void update(final byte p0);
        
        boolean isLengthWithinAvailableSpace(final int p0, final int p1);
        
        boolean isLengthExceedingBlockSize(final int p0, final int p1);
    }
    
    private class ImmediateProcessor implements ProcessingBuffer
    {
        @Override
        public void update(final byte b) {
            BufferBaseDigest.this.m_buf[BufferBaseDigest.this.m_bufPos] = b;
            if (++BufferBaseDigest.this.m_bufPos == BufferBaseDigest.this.BlockSize) {
                BufferBaseDigest.this.processBytes(BufferBaseDigest.this.m_buf, 0);
                BufferBaseDigest.this.m_bufPos = 0;
            }
        }
        
        @Override
        public boolean isLengthWithinAvailableSpace(final int n, final int n2) {
            return n < n2;
        }
        
        @Override
        public boolean isLengthExceedingBlockSize(final int n, final int n2) {
            return n >= n2;
        }
    }
    
    protected static class ProcessingBufferType
    {
        public static final int BUFFERED = 0;
        public static final int IMMEDIATE = 1;
        public static final ProcessingBufferType Buffered;
        public static final ProcessingBufferType Immediate;
        private final int ord;
        
        ProcessingBufferType(final int ord) {
            this.ord = ord;
        }
        
        static {
            Buffered = new ProcessingBufferType(0);
            Immediate = new ProcessingBufferType(1);
        }
    }
}
