/* 
 * E-XML Library:  For XML, XML-RPC, HTTP, and related.
 * Copyright (C) 2002-2008  Elias Ross
 * 
 * genman@noderunner.net
 * http://noderunner.net/~genman
 * 
 * 1025 NE 73RD ST
 * SEATTLE WA 98115
 * USA
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * $Id$
 */

package net.noderunner.exml;

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

/**
 * Collects characters in an array.  The data copied can be put in an escaped
 * or unescaped format to other <code>Writer</code>s.
 * It uses no locking or synchronization, meaning, this class is not
 * thread-safe.
 *
 * @version 1.0
 * @author Elias Ross
 */
public class XmlCharArrayWriter 
	extends Writer
{

	/**
	 * The buffer where data is stored.
	 */
	private char buf[];

	/**
	 * The number of chars in the buffer.
	 */
	private int count;

	/**
	 * Creates a new XmlCharArrayWriter with an initial size of 32.
	 */
	public XmlCharArrayWriter() {
		this(32);
	}

	/**
	 * Creates a new XmlCharArrayWriter with the specified initial size.
	 *
	 * @throws IllegalArgumentException if initialSize is negative
	 */
	public XmlCharArrayWriter(int initialSize) {
		if (initialSize < 0)
			throw new IllegalArgumentException("Negative size");
		buf = new char[initialSize];
	}

	/**
	 * Writes a character to the buffer.
	 */
	@Override
	public void write(int c) {
		int newcount = count + 1;
		if (newcount > buf.length) {
			char newbuf[] = new char[Math.max(buf.length << 1, newcount)];
			System.arraycopy(buf, 0, newbuf, 0, count);
			buf = newbuf;
		}
		buf[count] = (char)c;
		count = newcount;
	}

	/**
	 * Writes characters to the buffer.
	 * Writes the entire length of the array to the buffer.
	 *
	 * @param c source array
	 */
	@Override
	public void write(char c[]) {
		write(c, 0, c.length);
	}

	/**

	/**
	 * Writes characters to the buffer.
	 *
	 * @param c   source array
	 * @param off array offset
	 * @param len number of characters to write
	 */
	@Override
	public void write(char c[], int off, int len) {
		if (len == 0)
			return;
		int newcount = count + len;
		if (newcount > buf.length) {
			char newbuf[] = new char[Math.max(buf.length << 1, newcount)];
			System.arraycopy(buf, 0, newbuf, 0, count);
			buf = newbuf;
		}
		System.arraycopy(c, off, buf, count, len);
		count = newcount;
	}

	/**
	 * Writes a portion of a string to the buffer.
	 *
	 * @param  s    source string
	 * @param  off  string offset
	 * @param  len  number of characters to write 
	 */
	@Override
	public void write(String s, int off, int len) {
		int newcount = count + len;
		if (newcount > buf.length) {
			char newbuf[] = new char[Math.max(buf.length << 1, newcount)];
			System.arraycopy(buf, 0, newbuf, 0, count);
			buf = newbuf;
		}
		s.getChars(off, off + len, buf, count);
		count = newcount;
	}

	/**
	 * Writes a string to the buffer.
	 *
	 * @param  s source string
	 */
	@Override
	public void write(String s) {
		write(s, 0, s.length());
	}

	/**
	 * Writes the contents of the buffer to another character stream.
	 *
	 * @param out the output stream to write to
	 */
	public void writeTo(Writer out)
		throws IOException
	{
		out.write(buf, 0, count);
	}

	/**
	 * Writes the contents of the buffer to another character stream.
	 *
	 * @param out the output stream to write to
	 */
	public void writeEscapedTo(Writer out)
	     throws IOException
	{
		for (int i = 0; i < count; i++) {
			char c = buf[i];
			switch (c) {
			case '\'' :
				out.write("&apos;");
				break;
			case '"' :
				out.write("&quot;");
				break;
			case '<' :
				out.write("&lt;");
				break;
			case '>' :
				out.write("&gt;");
				break;
			case '&' :
				out.write("&amp;");
				break;
			default:
        out.write(c);
			}
		}
	}

	/**
	 * Writes the contents of the buffer to a string buffer.
	 *
	 * @param sb a string buffer
	 */
	public void writeEscapedTo(StringBuffer sb)
	{
		for (int i = 0; i < count; i++) {
			char c = buf[i];
			switch (c) {
			case '\'' :
				sb.append("&apos;");
				break;
			case '"' :
				sb.append("&quot;");
				break;
			case '<' :
				sb.append("&lt;");
				break;
			case '>' :
				sb.append("&gt;");
				break;
			case '&' :
				sb.append("&amp;");
				break;
			default:
				sb.append(c);
			}
		}
	}

	/**
	 * Returns the underlying buffer.
	 * The utilized length may be less than the array length.
	 * @see #size
	 */
	public char[] getBuffer() {
		return buf;
	}


	/**
	 * Resets the underlying buffer so that it may be used again.
	 */
	public void reset() {
		count = 0;
	}

	/**
	 * Returns the utilized length of the underlying buffer.
	 */
	public int size() {
		return count;
	}

	/**
	 * Returns the written data as a string.
	 */
	@Override
	public String toString() {
		if (count == 0)
			return "";
		return new String(buf, 0, count);
	}

	/**
	 * Does nothing.
	 */
	@Override
	public void flush() {
	}

	/**
	 * Does nothing.
	 */
	@Override
	public void close() {
	}
}
