/**
* Created on 10-Jan-2006
* Created by Allan Crooks
* Copyright (C) 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.core3.xml.util;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.TreeSet;
public class XMLElement {
protected Object single_content;
protected Map attributes;
protected Collection contents;
protected String tag_name;
protected boolean auto_order;
public XMLElement(String tag_name) {
this(tag_name, false);
}
public XMLElement(String tag_name, boolean auto_order) {
this.single_content = null;
this.attributes = null;
this.contents = null;
this.tag_name = tag_name;
this.auto_order = auto_order;
}
public String getTag() {
return tag_name;
}
public String getAttribute(String key) {
if (this.attributes == null) {return null;}
return (String)this.attributes.get(key);
}
public void addAttribute(String key, String value) {
if (attributes == null) {
this.attributes = new TreeMap(ATTRIBUTE_COMPARATOR);
}
this.attributes.put(key, value);
}
public void addAttribute(String key, int value) {
this.addAttribute(key, String.valueOf(value));
}
public void addAttribute(String key, boolean value) {
this.addAttribute(key, (value) ? "yes" : "no");
}
public void addContent(String s) {addContent((Object)s);}
public void addContent(XMLElement e) {addContent((Object)e);}
protected void addContent(Object o) {
if (o == null)
throw new NullPointerException();
if (this.contents == null) {
if (this.single_content != null) {
if (!this.auto_order) {
this.contents = new ArrayList();
}
else {
this.contents = new TreeSet(CONTENT_COMPARATOR);
}
this.contents.add(this.single_content);
this.single_content = null;
}
}
if (this.contents == null) {
this.single_content = o;
}
else {
this.contents.add(o);
}
}
public void printTo(PrintWriter pw) {
printTo(pw, 0, false);
}
public void printTo(PrintWriter pw, boolean spaced_out) {
printTo(pw, 0, spaced_out);
}
public void printTo(PrintWriter pw, int indent) {
printTo(pw, indent, false);
}
public void printTo(PrintWriter pw, int indent, boolean spaced_out) {
for (int i=0; i<indent; i++) {pw.print(" ");}
if (this.attributes == null && this.contents == null && this.single_content == null) {
if (!spaced_out) {
pw.print("<");
pw.print(this.tag_name);
pw.print(" />");
}
return;
}
pw.print("<");
pw.print(this.tag_name);
Iterator itr = null;
if (this.attributes != null) {
itr = this.attributes.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry entry = (Map.Entry)itr.next();
pw.print(" ");
pw.print(entry.getKey());
pw.print("=\"");
pw.print(quote((String)entry.getValue()));
pw.print("\"");
}
}
boolean needs_indented_close = (this.contents != null || this.single_content instanceof XMLElement);
boolean needs_close_tag = needs_indented_close || this.single_content != null;
needs_indented_close = needs_indented_close || spaced_out;
needs_close_tag = needs_close_tag || spaced_out;
if (needs_indented_close) {pw.println(">");}
else if (needs_close_tag) {pw.print(">");}
else {pw.print(" />");}
itr = null;
if (this.contents != null) {
itr = this.contents.iterator();
}
else if (this.single_content != null) {
itr = Collections.singletonList(this.single_content).iterator();
}
else {
itr = Collections.singletonList("").iterator();
}
Object content_element = null;
if (itr != null) {
while (itr.hasNext()) {
content_element = itr.next();
if (content_element instanceof XMLElement) {
((XMLElement)content_element).printTo(pw, indent+2, spaced_out);
}
else if (spaced_out) {
for (int i=0; i<indent+2; i++) {pw.print(" ");}
pw.print(quote((String)content_element));
pw.println();
}
else {
pw.print(quote((String)content_element));
}
}
}
if (needs_indented_close) {
for (int i=0; i<indent; i++) {pw.print(" ");}
}
if (needs_close_tag) {
pw.print("</");
pw.print(this.tag_name);
pw.println(">");
}
}
private String quote(String text) {
text = text.replaceAll( "&", "&" );
text = text.replaceAll( ">", ">" );
text = text.replaceAll( "<", "<" );
text = text.replaceAll( "\"", """ );
text = text.replaceAll( "--", "--" );
return text;
}
public XMLElement makeContent(String tag_name) {
return this.makeContent(tag_name, false);
}
public XMLElement makeContent(String tag_name, boolean auto_order) {
XMLElement content = new XMLElement(tag_name, auto_order);
this.addContent(content);
return content;
}
public void clear() {
this.single_content = null;
this.attributes = null;
this.contents = null;
}
public void setAutoOrdering(boolean mode) {
if (mode == this.auto_order) return;
this.auto_order = mode;
if (this.contents == null) return;
Collection previous_contents = contents;
if (this.auto_order) {
this.contents = new TreeSet(CONTENT_COMPARATOR);
this.contents.addAll(previous_contents);
}
else {
this.contents = new ArrayList(previous_contents);
}
}
public String toString() {
return "XMLElement[" + this.tag_name + "]@" + Integer.toHexString(System.identityHashCode(this));
}
private static Comparator ATTRIBUTE_COMPARATOR = String.CASE_INSENSITIVE_ORDER;
private static class ContentComparator implements java.util.Comparator {
public int compare(Object o1, Object o2) {
if (o1 instanceof XMLElement) {
if (o2 instanceof XMLElement) {
XMLElement xe1 = (XMLElement)o1;
XMLElement xe2 = (XMLElement)o2;
int result = String.CASE_INSENSITIVE_ORDER.compare(xe1.getTag(), xe2.getTag());
if (result == 0) {
int xe1_index = 0, xe2_index = 0;
try {
xe1_index = Integer.parseInt(xe1.getAttribute("index"));
xe2_index = Integer.parseInt(xe2.getAttribute("index"));
}
catch (NullPointerException ne) {
xe1_index = xe2_index = 0;
}
catch (NumberFormatException ne) {
xe1_index = xe2_index = 0;
}
if (xe1_index != xe2_index) {
return xe1_index - xe2_index;
}
throw new RuntimeException("Shouldn't be using sorting for contents if you have tags with same name and no index attribute! (e.g. " + o1 + ")");
}
return result;
}
else {
return -1; // XMLElements before strings.
}
}
else {
if (o2 instanceof XMLElement) {
return 1; // XMLElements before strings.
}
else {
// Can't allow the returning of 0.
int result = String.CASE_INSENSITIVE_ORDER.compare((String)o1, (String)o2);
if (result == 0) {return -1;}
return result;
}
}
}
}
private static Comparator CONTENT_COMPARATOR = new ContentComparator();
}