/* WriterOutputStream.java

	Purpose:
		
	Description:
		
	History:
		Mon May  1 22:00:51     2006, Created by tomyeh

Copyright (C) 2006 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under LGPL Version 2.1 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.io;

import java.io.Writer;
import java.io.OutputStream;
import java.io.IOException;

/**
 * An output stream that is on top of a writer.
 *
 * @author tomyeh
 */
public class WriterOutputStream extends OutputStream {
	private final Writer _writer;
	private final String _charset;
	private final byte[] _bs; //used only with writer
	private int _cnt, _type; //used only with writer

	/** Constructs an out stream with the specified encoding.
	 *
	 * @param charset the charset. If null, "UTF-8" is assumed.
	 */
	public WriterOutputStream(Writer writer, String charset) {
		if (writer == null) throw new IllegalArgumentException("null");
		_writer = writer;
		_bs = new byte[3];
		_charset = charset == null ? "UTF-8": charset;
	}
	/** Constructs an output stream assuming UTF-8 encoding.
	 */
	public WriterOutputStream(Writer writer) {
		this(writer, null);
	}
	public void write(byte[] b) throws IOException {
		_writer.write(new String(b, _charset));
	}
	public void write(byte[] b, int off, int len) throws IOException {
		_writer.write(new String(b, 0, b.length, _charset));
	}
	public void write(int b) throws IOException {
		if (_type != 0) {
			if (!"UTF-8".equals(_charset) || (b & 0xc0) == 0x80) {
				_bs[_cnt ++] = (byte)b;
				if (_cnt == _type) { //complete
					_writer.write(new String(_bs, 0, _type, _charset));
					_type = 0; //reset
				}
				return;
			} else { //failed
				for (int j = 0; j < _cnt; ++j)
					_writer.write(_bs[j]);
				_type = 0; //reset
			}
		} else {
			if ("UTF-8".equals(_charset)) {
				if ((b & 0xe0) == 0xc0 || (b & 0xf0) == 0xe0) {
					_type = (b & 0xf0) == 0xe0 ? 3: 2;
					_bs[0] = (byte)b;
					_cnt = 1;
					return;
				}
			} else {
				//assume two-bytes per char if 0x80 -- might fail.
				if ((b & 0x80) != 0) {
					_type = 2;
					_bs[0] = (byte)b;
					_cnt = 1;
					return;
				}
			}
		}
		_writer.write(b);
	}
	public void flush() throws IOException {
		if (_type != 0) {
			for (int j = 0; j < _cnt; ++j)
				_writer.write(_bs[j]); //reset
			_type = 0;
		}
		_writer.flush();
		super.flush();
	}
	public void close() throws IOException {
		flush();
		_writer.close();
		super.close();
	}
}
