/******************************************
 * Shape2XML.java
 * Uses the NVS shapefile library
 *  to the read the specified shapefile 
 *  and translate into an XML description
 *
 *****************************************/


import java.io.*;
import com.nvs.shapefile.*;
import java.util.zip.*;
import java.io.*;
import java.util.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;
import org.apache.xerces.parsers.*;

public class Shape2XML 
{
	private static String strXMLFile;
	private static String strShapefile;
	
	public static void main(String args[])
	{
		if(args.length < 2)
		{
			System.out.println("Usage: XML2Shape <shape_file> <xml_file>");
			return;
		}
		
		strShapefile = args[0];
		strXMLFile = args[1];
		
		new Shape2XML();
	}
	
	public Shape2XML()
	{	
		Shapefile shp = null;
		try
		{	
			shp = new Shapefile(strShapefile);
			
			FileOutputStream fos = new FileOutputStream(strXMLFile);
			
			Element elRoot = new Element("shapefile");
			
			// Set the shape type
			switch(shp.getType())
			{
				case Shapefile.SHAPETYPE_POINT :
					elRoot.setAttribute("type", "points");
				break;
				
				case Shapefile.SHAPETYPE_POLYLINE :
					elRoot.setAttribute("type", "lines");
				break;
				
				case Shapefile.SHAPETYPE_POLYGON :
					elRoot.setAttribute("type", "polygons");
				break;
			}
			
			// Write the table
			TableDescription tableDesc = shp.getTableDescription();
			if(tableDesc != null)
			{
				elRoot.addContent(translateTable(tableDesc));	
			}
			
			
			// Write bounding box
			BoundingBox box = shp.getBoundingBox();
			
			if(box != null)
			{
				elRoot.addContent(translateBox(box));
			}
			
			// Write shape objects
			Iterator itrShapeObjects = shp.getShapeObjects().iterator();
			while(itrShapeObjects.hasNext())
			{
				ShapeObject obj = (ShapeObject)itrShapeObjects.next();
				
				if(obj.getType() == ShapeObject.POINT)
				{
					if(obj.getType() != shp.getType())
					{
						// throw some sort of exception
					}
					elRoot.addContent(translatePointObject(obj));
				}
				
				else if(obj.getType() == ShapeObject.POLYLINE)
				{
					if(obj.getType() != shp.getType())
					{
						// throw some sort of exception
					}
					elRoot.addContent(translateLineObject(obj));
				}			
				
				else if(obj.getType() == ShapeObject.POLYGON)
				{
					if(obj.getType() != shp.getType())
					{
						// throw some sort of exception
					}
					elRoot.addContent(translatePolygonObject(obj));
				}
			}
			
			XMLOutputter fmt = new XMLOutputter();
			fmt.setIndent("   ");
			fmt.setNewlines(true);
			
			DocType xhtml = new DocType("shapefile", "file:shapefile.dtd");

			Document doc = new Document(elRoot);
			doc.setDocType(xhtml);

			fmt.output(doc, fos);
			
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	
	
	private Element translatePointObject(ShapeObject obj)
	{
		Element elShape = new Element("shape");
		elShape.setAttribute("type", "point");
		
		
		Point pt = obj.getPoint(0);
		Element elPoint = new Element("point");
		elPoint.setAttribute("x", String.valueOf(pt.getX()));
		elPoint.setAttribute("y", String.valueOf(pt.getY()));
		
		elShape.addContent(elPoint);
		
		
		Record rec = obj.getRecord();
		Iterator itrFields = rec.getFields().iterator();
		while(itrFields.hasNext())
		{
			RecordField recField = (RecordField)itrFields.next();
			Element elField = new Element("field");
			elField.setAttribute("name", recField.getName().trim());
			elField.setAttribute("value", recField.getValue().trim());
			elShape.addContent(elField);
		}
		
		return elShape;
	}
	
	
	
	private Element translateLineObject(ShapeObject obj)
	{
		Element elShape = new Element("shape");
		elShape.setAttribute("type", "line");
		
		Iterator itrPoints = obj.getPoints().iterator();
		while(itrPoints.hasNext())
		{
			Point pt = (Point)itrPoints.next();
			Element elPoint = new Element("point");
			elPoint.setAttribute("x", String.valueOf(pt.getX()));
			elPoint.setAttribute("y", String.valueOf(pt.getY()));
		
			elShape.addContent(elPoint);
		}
		
		Record rec = obj.getRecord();
		Iterator itrFields = rec.getFields().iterator();
		while(itrFields.hasNext())
		{
			RecordField recField = (RecordField)itrFields.next();
			Element elField = new Element("field");
			elField.setAttribute("name", recField.getName().trim());
			elField.setAttribute("value", recField.getValue().trim());
			elShape.addContent(elField);
		}
		
		return elShape;
	}
	
	private Element translatePolygonObject(ShapeObject obj)
	{
		Element elShape = new Element("shape");
		elShape.setAttribute("type", "polygon");
		
		Iterator itrPoints = obj.getPoints().iterator();
		while(itrPoints.hasNext())
		{
			Point pt = (Point)itrPoints.next();
			Element elPoint = new Element("point");
			elPoint.setAttribute("x", String.valueOf(pt.getX()));
			elPoint.setAttribute("y", String.valueOf(pt.getY()));
		
			elShape.addContent(elPoint);
		}
		
		Record rec = obj.getRecord();
		Iterator itrFields = rec.getFields().iterator();
		while(itrFields.hasNext())
		{
			RecordField recField = (RecordField)itrFields.next();
			Element elField = new Element("field");
			elField.setAttribute("name", recField.getName().trim());
			elField.setAttribute("value", recField.getValue().trim());
			elShape.addContent(elField);
		}
		
		return elShape;
	}
	
	
	private Element translateBox(BoundingBox box)
	{
		Element elBox = new Element("bounding-box");
		elBox.setAttribute("xmin", String.valueOf(box.getXMin()));
		elBox.setAttribute("xmax", String.valueOf(box.getXMax()));
		elBox.setAttribute("ymin", String.valueOf(box.getYMin()));
		elBox.setAttribute("ymax", String.valueOf(box.getYMax()));
		
		return elBox;
	}
	
	
	
	private Element translateTable(TableDescription tableDesc)
	{
		Element elTable = new Element("table");
		Iterator itrDescriptors = tableDesc.getTableDescriptors().iterator();
		while(itrDescriptors.hasNext())
		{
			TableDescriptor td = (TableDescriptor)itrDescriptors.next();
			Element elTD = new Element("entry");
			elTD.setAttribute("name", td.getName().trim());
			switch(td.getType())
			{
				case Shapefile.FIELDTYPE_CHARACTER :
					elTD.setAttribute("datatype", "string");
				break;
				
				default :
					elTD.setAttribute("datatype", "string");
				break;
			}
			
			elTable.addContent(elTD);
		}
		
		return elTable;
	}
}