//===============================================================
// package : com.tetrasix.majix.rtf
// class : com.tetrasix.majix.RtfReader
//===============================================================
// The contents of this file are subject to the Mozilla Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is TetraSys code.
//
// The Initial Developer of the Original Code is TetraSys..
// Portions created by TetraSys are 
// Copyright (C) 1998-2000 TetraSys. All Rights Reserved.
//
// Contributor(s): Arne Jans, Quinscape GmbH (www.quinscape.de)
//===============================================================


/**
 *
 * @version 1.1
 */


package vkc.converter.rtf;

import java.io.IOException;
import java.io.PushbackInputStream;

import java.net.URL;

public class RtfReader {
	private final static int maxBufSize = 10000;
	private PushbackInputStream _in;
	private StringBuffer _buf;
	private int _depth;
	private String _filename;
	private long _nbtoken;
	private int unicodeIgnoreCounter = 1;

	public RtfReader(String url) throws IOException
	{
        open(url);
    }

	public void open(String url) throws IOException 
	{
        _in = new PushbackInputStream(new URL(url).openStream());
        _buf = new StringBuffer();
        _depth = 0;
        _filename = url;
        _nbtoken = 0;
    }

	public RtfToken getNextToken() throws IOException
	{
		//_buf.setLength(0);
		_buf = new StringBuffer();
		_nbtoken++;

		for(;;) {
			int ch = _in.read();

			if (ch == -1) {
				return null;
			}
			else if (ch == '\\') {
				
				if ((_buf.length() > 0)){
					_in.unread(ch);
					String data = _buf.toString();
					_buf.setLength(0);
					return new RtfToken(data);
				}

				ch = _in.read();
				
				//siehe: http://www.biblioscape.com/rtf15_spec.htm#Heading9
				if (ch == 'u') { //Unicode-Zeichen
					ch = _in.read();
					
					if (Character.isDigit((char)ch) || (ch == '-')) {
						if (_buf.length() < maxBufSize) {
							_buf.append((char)ch);
						}
						
						ch = _in.read();

						while (Character.isDigit((char)ch)) {
							if (_buf.length() < maxBufSize)
								_buf.append((char)ch);
							ch = _in.read();
						}
						
						//ANSI-Kopatiblitätszeichen überlesen
						int c = Integer.parseInt( _buf.toString() );
						
						if (c < 0) {
						    c += 65536;
						}
						
		                String s = new String(new char[] {(char) c});
						RtfToken token = new RtfToken(s);
						
						for (int i = unicodeIgnoreCounter; i > 0; i--){
							if (ch == 13) {
							    ch = _in.read();
							    i++;
							} else if (ch == '\\') {
							    ch = _in.read();
							    ch = _in.read();
							    ch = _in.read();
							} else {
							    ch = _in.read();
							}

							ch = _in.read();
						}
						
						_in.unread(ch);

						return token;
					} 

					if (ch == 'c') {
						ch = _in.read();
						
						while (Character.isDigit((char)ch)) {
							if (_buf.length() < maxBufSize)
								_buf.append((char)ch);
							
							ch = _in.read();
						}
						
						unicodeIgnoreCounter = new Integer(_buf.toString()).intValue();
						unicodeIgnoreCounter = unicodeIgnoreCounter == 0 ? 1 : unicodeIgnoreCounter;
						_buf.setLength(0);
						_in.unread(ch);
						
						continue;
					} 
					
					_in.unread(ch);
					ch = 'u';
				}

				if (ch == '*') {
					return new RtfToken(RtfToken.ASTERISK);
				}

				if (ch == '\'') {
					char ch1 = (char) _in.read();
					
					if (Character.digit(ch1, 16) != -1) {
						char ch2 = (char) _in.read();

						if (Character.digit(ch2, 16) != -1) {
							ch = Character.digit(ch1, 16) * 16 + Character.digit(ch2, 16);
							
							if (_buf.length() < maxBufSize)
								_buf.append((char)ch);
							
							String data = _buf.toString();
							
							return new RtfToken(data);
						}
						
						_in.unread(ch2);
					} else {
						_in.unread(ch1);
					}
				}
				else if (ch == '\\') {
					return new RtfToken("\\");
				}
				else if (ch == '~') {
					return new RtfToken("\u00A0");
				}
				else if (ch == '-') {
					return new RtfToken("\u2010");
				}
				else if (ch == '_') {
					return new RtfToken("\u2011");
				}
				else if (ch == '{') {
					return new RtfToken("{");
				}
				else if (ch == '}') {
					return new RtfToken("}");
				}

				while (Character.isLetter((char)ch)) {
					if (_buf.length() < maxBufSize)
						_buf.append((char)ch);
					ch = _in.read();
				}
				String name = _buf.toString();
				_buf.setLength(0);

				if (ch == '-') {
					if (_buf.length() < maxBufSize) 
						_buf.append((char)ch);
					ch = _in.read();
				}

				while (Character.isDigit((char)ch)) {
					if (_buf.length() < maxBufSize) 
						_buf.append((char)ch);
					ch = _in.read();
				}

				if (! Character.isSpaceChar((char)ch)) {
					_in.unread(ch);
				}
				
				String data = _buf.toString();
				_buf.setLength(0);

				return new RtfToken(RtfToken.CONTROLWORD, name, data);
			}
			else if (ch == '{') {
				if (_buf.length() > 0) {
					_in.unread(ch);
					String data = _buf.toString();
					return new RtfToken(data);
				}

				_depth++;
				unicodeIgnoreCounter = 1;

				return new RtfToken(RtfToken.OPENGROUP);
			}
			else if (ch == '}') {
				if (_buf.length() > 0) {
					_in.unread(ch);
					String data = _buf.toString();
					return new RtfToken(data);
				}

				_depth--;
				unicodeIgnoreCounter = 1;

				return new RtfToken(RtfToken.CLOSEGROUP);
			}
			else if (ch == '\r') {
			}
			else if (ch == '\n') {
			}
			else {
				if (_buf.length() < maxBufSize) 
					_buf.append((char)ch);
			}
		}
	}

	public int getDepth()
	{
		return _depth;
	}

	public long getTokenCount()
	{
		return _nbtoken;
	}

	public void close()
	{
		if (_in != null) {
			try {
				_in.close();
			}
			catch(IOException e) {
				System.out.println("Exception when closing " + _filename);
			}
			_in = null;
			_buf = null;
			_filename = null;
		}
	}

	public String getFileName()
	{
		return _filename;
	}
}