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

package org.jline.utils;

import java.nio.charset.CoderResult;
import java.io.IOException;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.Charset;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import java.nio.charset.CharsetDecoder;
import java.io.Writer;
import java.io.OutputStream;

public class WriterOutputStream extends OutputStream
{
    private final Writer out;
    private final CharsetDecoder decoder;
    private final ByteBuffer decoderIn;
    private final CharBuffer decoderOut;
    
    public WriterOutputStream(final Writer out, final Charset charset) {
        this(out, charset.newDecoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE));
    }
    
    public WriterOutputStream(final Writer out, final CharsetDecoder decoder) {
        this.decoderIn = ByteBuffer.allocate(256);
        this.decoderOut = CharBuffer.allocate(128);
        this.out = out;
        this.decoder = decoder;
    }
    
    @Override
    public void write(final int b) throws IOException {
        this.write(new byte[] { (byte)b }, 0, 1);
    }
    
    @Override
    public void write(final byte[] b) throws IOException {
        this.write(b, 0, b.length);
    }
    
    @Override
    public void write(final byte[] b, int off, int len) throws IOException {
        while (len > 0) {
            final int c = Math.min(len, this.decoderIn.remaining());
            this.decoderIn.put(b, off, c);
            this.processInput(false);
            len -= c;
            off += c;
        }
        this.flush();
    }
    
    @Override
    public void flush() throws IOException {
        this.flushOutput();
        this.out.flush();
    }
    
    @Override
    public void close() throws IOException {
        this.processInput(true);
        this.flush();
        this.out.close();
    }
    
    private void processInput(final boolean endOfInput) throws IOException {
        this.decoderIn.flip();
        CoderResult coderResult;
        while (true) {
            coderResult = this.decoder.decode(this.decoderIn, this.decoderOut, endOfInput);
            if (!coderResult.isOverflow()) {
                break;
            }
            this.flushOutput();
        }
        if (coderResult.isUnderflow()) {
            this.decoderIn.compact();
            return;
        }
        throw new IOException("Unexpected coder result");
    }
    
    private void flushOutput() throws IOException {
        if (this.decoderOut.position() > 0) {
            this.out.write(this.decoderOut.array(), 0, this.decoderOut.position());
            this.decoderOut.rewind();
        }
    }
}
