// This file is part of TagSoup and is Copyright 2002-2008 by John Cowan.
//
// TagSoup is licensed under the Apache License,
// Version 2.0.  You may obtain a copy of this license at
// http://www.apache.org/licenses/LICENSE-2.0 .  You may also have
// additional legal rights not granted by this license.
//
// TagSoup is distributed in the hope that it will be useful, but
// unless required by applicable law or agreed to in writing, TagSoup
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
// OF ANY KIND, either express or implied; not even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// 
// 
// PYX Writer
// FIXME: does not do escapes in attribute values
// FIXME: outputs entities as bare '&' character

package org.ccil.cowan.tagsoup;
import java.io.*;
import org.xml.sax.*;
import org.xml.sax.ext.LexicalHandler;

/**
A ContentHandler that generates PYX format instead of XML.
Primarily useful for debugging.
**/
public class PYXWriter
	implements ScanHandler, ContentHandler, LexicalHandler {

	private PrintWriter theWriter;		// where we write to
	private static char[] dummy = new char[1];
	private String attrName;		// saved attribute name

	// ScanHandler implementation

	public void adup(char[] buff, int offset, int length) throws SAXException {
		theWriter.println(attrName);
		attrName = null;
		}

	public void aname(char[] buff, int offset, int length) throws SAXException {
		theWriter.print('A');
		theWriter.write(buff, offset, length);
		theWriter.print(' ');
		attrName = new String(buff, offset, length);
		}

	public void aval(char[] buff, int offset, int length) throws SAXException {
		theWriter.write(buff, offset, length);
		theWriter.println();
		attrName = null;
		}

	public void cmnt(char [] buff, int offset, int length) throws SAXException {
//		theWriter.print('!');
//		theWriter.write(buff, offset, length);
//		theWriter.println();
		}

	public void entity(char[] buff, int offset, int length) throws SAXException { }

	public int getEntity() { return 0; }

	public void eof(char[] buff, int offset, int length) throws SAXException {
		theWriter.close();
		}

	public void etag(char[] buff, int offset, int length) throws SAXException {
		theWriter.print(')');
		theWriter.write(buff, offset, length);
		theWriter.println();
		}

	public void decl(char[] buff, int offset, int length) throws SAXException {
        }

	public void gi(char[] buff, int offset, int length) throws SAXException {
		theWriter.print('(');
		theWriter.write(buff, offset, length);
		theWriter.println();
		}

	public void cdsect(char[] buff, int offset, int length) throws SAXException {
		pcdata(buff, offset, length);
		}

	public void pcdata(char[] buff, int offset, int length) throws SAXException {
		if (length == 0) return;	// nothing to do
		boolean inProgress = false;
		length += offset;
		for (int i = offset; i < length; i++) {
			if (buff[i] == '\n') {
				if (inProgress) {
					theWriter.println();
					}
				theWriter.println("-\\n");
				inProgress = false;
				}
			else {
				if (!inProgress) {
					theWriter.print('-');
					}
				switch(buff[i]) {
				case '\t':
					theWriter.print("\\t");
					break;
				case '\\':
					theWriter.print("\\\\");
					break;
				default:
					theWriter.print(buff[i]);
					}
				inProgress = true;
				}
			}
		if (inProgress) {
			theWriter.println();
			}
		}

	public void pitarget(char[] buff, int offset, int length) throws SAXException {
		theWriter.print('?');
		theWriter.write(buff, offset, length);
		theWriter.write(' ');
		}

	public void pi(char[] buff, int offset, int length) throws SAXException {
		theWriter.write(buff, offset, length);
		theWriter.println();
		}

	public void stagc(char[] buff, int offset, int length) throws SAXException {
//		theWriter.println("!");			// FIXME
		}

	public void stage(char[] buff, int offset, int length) throws SAXException {
		theWriter.println("!");			// FIXME
		}

	// SAX ContentHandler implementation

	public void characters(char[] buff, int offset, int length) throws SAXException {
		pcdata(buff, offset, length);
		}

	public void endDocument() throws SAXException {
		theWriter.close();
		}

	public void endElement(String uri, String localname, String qname) throws SAXException {
		if (qname.length() == 0) qname = localname;
		theWriter.print(')');
		theWriter.println(qname);
		}

	public void endPrefixMapping(String prefix) throws SAXException { }

	public void ignorableWhitespace(char[] buff, int offset, int length) throws SAXException {
		characters(buff, offset, length);
		}

	public void processingInstruction(String target, String data) throws SAXException {
		theWriter.print('?');
		theWriter.print(target);
		theWriter.print(' ');
		theWriter.println(data);
		}

	public void setDocumentLocator(Locator locator) { }

	public void skippedEntity(String name) throws SAXException { }

	public void startDocument() throws SAXException { }

	public void startElement(String uri, String localname, String qname,
			Attributes atts) throws SAXException {
		if (qname.length() == 0) qname=localname;
		theWriter.print('(');
		theWriter.println(qname);
		int length = atts.getLength();
		for (int i = 0; i < length; i++) {
			qname = atts.getQName(i);
			if (qname.length() == 0) qname = atts.getLocalName(i);
			theWriter.print('A');
//			theWriter.print(atts.getType(i));	// DEBUG
			theWriter.print(qname);
			theWriter.print(' ');
			theWriter.println(atts.getValue(i));
			}
		}

	public void startPrefixMapping(String prefix, String uri) throws SAXException { }

	// Default LexicalHandler implementation

	public void comment(char[] ch, int start, int length) throws SAXException {
		cmnt(ch, start, length);
		}
	public void endCDATA() throws SAXException { }
	public void endDTD() throws SAXException { }
	public void endEntity(String name) throws SAXException { }
	public void startCDATA() throws SAXException { }
	public void startDTD(String name, String publicId, String systemId) throws SAXException { }
	public void startEntity(String name) throws SAXException { }

	// Constructor

	public PYXWriter(Writer w) {
		if (w instanceof PrintWriter) {
			theWriter = (PrintWriter)w;
			}
		else {
			theWriter = new PrintWriter(w);
			}
		}
	}
