rrenkert@41: package de.intevation.mxd.writer;
rrenkert@41: 
rrenkert@41: import org.apache.log4j.Logger;
rrenkert@41: 
rrenkert@41: import org.w3c.dom.Document;
rrenkert@41: import org.w3c.dom.Element;
rrenkert@41: import org.w3c.dom.NodeList;
rrenkert@42: 
rrenkert@98: import java.io.File;
rrenkert@98: 
rrenkert@41: import javax.xml.xpath.XPathConstants;
rrenkert@41: 
rrenkert@41: import edu.umn.gis.mapscript.mapObj;
rrenkert@41: import edu.umn.gis.mapscript.layerObj;
rrenkert@42: import edu.umn.gis.mapscript.classObj;
rrenkert@42: 
rrenkert@41: import edu.umn.gis.mapscript.MS_UNITS;
rrenkert@42: import edu.umn.gis.mapscript.MS_LAYER_TYPE;
rrenkert@41: 
rrenkert@41: import de.intevation.mxd.utils.XMLUtils;
rrenkert@41: 
rrenkert@41: /**
rrenkert@43:  * The Mapfile Writer.
rrenkert@43:  * This Writer uses the MapScript Java API to create Mapfiles from a DOM.
rrenkert@41:  *
rrenkert@41:  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
rrenkert@41:  */
rrenkert@41: public class MapScriptWriter
rrenkert@41: implements IWriter
rrenkert@41: {
rrenkert@43:     /**
rrenkert@43:      * The Logger.
rrenkert@43:      */
rrenkert@43:     private static final Logger logger = Logger.getLogger(MapScriptWriter.class);
rrenkert@43: 
rrenkert@43:     /**
rrenkert@43:      * Private member.
rrenkert@43:      */
rrenkert@41:     private Document root;
rrenkert@41:     private mapObj map;
rrenkert@55:     private String mapFilename;
rrenkert@41: 
rrenkert@41:     public MapScriptWriter() {
rrenkert@55:         map = new mapObj("");
rrenkert@55:         mapFilename = "";
rrenkert@41:     }
rrenkert@41: 
rrenkert@55:     public MapScriptWriter(String templ, String filename) {
rrenkert@55:         map = new mapObj(templ);
rrenkert@55:         mapFilename = filename;
rrenkert@41:     }
rrenkert@41: 
rrenkert@43:     /**
rrenkert@43:      * Write the mapfile.
rrenkert@43:      * @param doc The root document containin the map attributes.
rrenkert@43:      *
rrenkert@43:      * @return Currently always true.
rrenkert@43:      */
rrenkert@87:     public boolean write(Document doc)
rrenkert@87:     throws Exception {
rrenkert@41:         logger.debug("write()");
rrenkert@41:         this.root = doc;
rrenkert@41: 
rrenkert@41:         //Get the filename.
rrenkert@41:         Element fileNode = (Element)XMLUtils.xpath(
rrenkert@41:             root,
rrenkert@41:             "/mxd/file",
rrenkert@41:             XPathConstants.NODE);
rrenkert@41:         //Write the map attributes.
rrenkert@41:         writeMap();
rrenkert@42:         //Write the layers.
rrenkert@42:         writeLayer();
rrenkert@41:         //Save the map.
rrenkert@42:         mapObj cloneMap = map.cloneMap();
rrenkert@55:         cloneMap.save(mapFilename);
rrenkert@41:         return true;
rrenkert@41:     }
rrenkert@41: 
rrenkert@43:     /**
rrenkert@43:      * Create the map object and set the attributes.
rrenkert@43:      */
rrenkert@41:     private void writeMap() {
rrenkert@41:         logger.debug("writeMap()");
rrenkert@41:         //Get the map.
rrenkert@41:         Element mapNode = (Element)XMLUtils.xpath(
rrenkert@41:             root,
rrenkert@41:             "/mxd/map",
rrenkert@41:             XPathConstants.NODE);
rrenkert@41: 
rrenkert@41:         //Set the name.
rrenkert@41:         map.setName(mapNode.getAttribute("name"));
rrenkert@42:         map.setMetaData("wms_title", mapNode.getAttribute("name"));
rrenkert@41:         //Set the extent.
rrenkert@41:         map.setExtent(
rrenkert@41:             Double.parseDouble(mapNode.getAttribute("extent_min_x")),
rrenkert@41:             Double.parseDouble(mapNode.getAttribute("extent_min_y")),
rrenkert@41:             Double.parseDouble(mapNode.getAttribute("extent_max_x")),
rrenkert@41:             Double.parseDouble(mapNode.getAttribute("extent_max_y")));
rrenkert@41: 
rrenkert@41:         //Set the units.
rrenkert@41:         String units = mapNode.getAttribute("units");
rrenkert@41:         MS_UNITS msu;
rrenkert@41:         if(units.equals("feet")) {
rrenkert@41:             msu = MS_UNITS.MS_FEET;
rrenkert@41:         }
rrenkert@41:         else if(units.equals("inches")) {
rrenkert@41:             msu = MS_UNITS.MS_INCHES;
rrenkert@41:         }
rrenkert@41:         else if(units.equals("kilometers")) {
rrenkert@41:             msu = MS_UNITS.MS_KILOMETERS;
rrenkert@41:         }
rrenkert@41:         else if(units.equals("meters")) {
rrenkert@41:             msu = MS_UNITS.MS_METERS;
rrenkert@41:         }
rrenkert@41:         else if(units.equals("miles")) {
rrenkert@41:             msu = MS_UNITS.MS_MILES;
rrenkert@41:         }
rrenkert@41:         else if(units.equals("nauticalmiles")) {
rrenkert@41:             msu = MS_UNITS.MS_NAUTICALMILES;
rrenkert@41:         }
rrenkert@41:         else if(units.equals("points")) {
rrenkert@41:             msu = MS_UNITS.MS_PIXELS;
rrenkert@41:         }
rrenkert@41:         else {
rrenkert@57:             msu = MS_UNITS.MS_METERS;
rrenkert@41:         }
rrenkert@41:         map.setUnits(msu);
rrenkert@41: 
rrenkert@41:         //TODO: Find out whats the correct scale value.
rrenkert@41:         //map.setScaledenom(Double.parseDouble(mapNode.getAttribute("scale")));
rrenkert@41:     }
rrenkert@41: 
rrenkert@43:     /**
rrenkert@43:      * Create layer objects and set the attributes.
rrenkert@43:      */
rrenkert@87:     private void writeLayer()
rrenkert@87:     throws Exception {
rrenkert@42:         logger.debug("writeLayer()");
rrenkert@42:         Element mapNode = (Element)XMLUtils.xpath(
rrenkert@42:             root,
rrenkert@42:             "/mxd/map",
rrenkert@42:             XPathConstants.NODE);
rrenkert@42:         NodeList list = mapNode.getElementsByTagName("layer");
rrenkert@42:         for(int i = 0; i < list.getLength(); i++) {
rrenkert@42:             Element layerElement = (Element)list.item(i);
rrenkert@42:             layerObj layer = new layerObj(map);
rrenkert@42: 
rrenkert@42:             //The layer name.
rrenkert@42:             layer.setName(layerElement.getAttribute("name"));
rrenkert@42: 
rrenkert@42:             //The layer status.
rrenkert@42:             String stat = layerElement.getAttribute("status");
rrenkert@42:             if (stat.equals("on")) {
rrenkert@42:                 layer.setStatus(1);
rrenkert@42:             }
rrenkert@42:             else {
rrenkert@42:                 layer.setStatus(0);
rrenkert@42:             }
rrenkert@42: 
rrenkert@42:             //The scale.
rrenkert@42:             double maxScale =
rrenkert@42:                 Double.parseDouble(layerElement.getAttribute("max_scale"));
rrenkert@42:             double minScale =
rrenkert@42:                 Double.parseDouble(layerElement.getAttribute("min_scale"));
rrenkert@42:             layer.setMaxscaledenom(maxScale);
rrenkert@42:             layer.setMinscaledenom(minScale);
rrenkert@42: 
rrenkert@42:             //The layer type.
rrenkert@42:             String type = layerElement.getAttribute("type");
rrenkert@42:             if(type.equals("point")) {
rrenkert@42:                 layer.setType(MS_LAYER_TYPE.MS_LAYER_POINT);
rrenkert@42:             }
rrenkert@62:             else if (type.equals("line")) {
rrenkert@62:                 layer.setType(MS_LAYER_TYPE.MS_LAYER_LINE);
rrenkert@62:             }
rrenkert@97:             else if (type.equals("polygon")) {
rrenkert@97:                 layer.setType(MS_LAYER_TYPE.MS_LAYER_POLYGON);
rrenkert@97:             }
rrenkert@102:             layer.setTileitem("");
rrenkert@42: 
rrenkert@42:             //The layer datasource.
rrenkert@98:             String datasource = "";
rrenkert@98:             if(layerElement.hasAttribute("workspace")) {
rrenkert@98:                 datasource = layerElement.getAttribute("workspace");
rrenkert@98:                 datasource += File.separator;
rrenkert@98:             }
rrenkert@98:             datasource += layerElement.getAttribute("data_source");
rrenkert@98:             layer.setData(datasource);
rrenkert@42: 
rrenkert@42:             //Write classes.
rrenkert@42:             writeClass(layer, layerElement);
rrenkert@42:         }
rrenkert@41: 
rrenkert@41:     }
rrenkert@41: 
rrenkert@42:     /**
rrenkert@42:      * Adds the classes to the layer.
rrenkert@42:      * @param layer        Mapscript layer object.
rrenkert@42:      * @param layerElement Dom element containing the class attributes.
rrenkert@42:      */
rrenkert@87:     private void writeClass(layerObj layer, Element layerElement)
rrenkert@87:     throws Exception {
rrenkert@87:         logger.debug("writeClass(layerObj, Element)");
rrenkert@42:         //Get all renderer elements (renderer in arcgis equals class in the
rrenkert@42:         //mapfile.)
rrenkert@42:         NodeList list = layerElement.getElementsByTagName("renderer");
rrenkert@41: 
rrenkert@42:         //Create all found class objects and write the symbols and styles for
rrenkert@42:         //each class.
rrenkert@42:         for(int i = 0; i < list.getLength(); i++) {
rrenkert@42:             Element classElement = (Element)list.item(i);
rrenkert@42:             classObj co = new classObj(layer);
rrenkert@99:             String name = classElement.getAttribute("name");
rrenkert@99:             if (name.equals("")) {
rrenkert@99:                 name = layerElement.getAttribute("name");
rrenkert@99:                 if (list.getLength() > 1) {
rrenkert@99:                     name += "-" + i;
rrenkert@99:                 }
rrenkert@99:             }
rrenkert@99:             co.setName (name);
rrenkert@44:             if(classElement.hasAttribute("field_count")) {
rrenkert@44:                 int count =
rrenkert@44:                     Integer.parseInt(classElement.getAttribute("field_count"));
rrenkert@44:                 String exp = "";
rrenkert@44:                 for(int j = 0; j < count; j++) {
rrenkert@44:                     //TODO Find a way to create Expressions.
rrenkert@44:                     exp = "([" + classElement.getAttribute("expression_field_" + j);
rrenkert@46:                     exp += "] " + classElement.getAttribute("expression_operator");
rrenkert@46:                     exp += " " + classElement.getAttribute("value") + ")";
rrenkert@44:                 }
rrenkert@44:                 co.setExpression(exp);
rrenkert@44:             }
rrenkert@42:             //Write symbols and styles.
rrenkert@97:             NodeList l = classElement.getChildNodes();
rrenkert@97:             for (int j = 0; j < l.getLength(); j++) {
rrenkert@97:                 Element elem = (Element)l.item(j);
rrenkert@97: 
rrenkert@97:                 String type = layerElement.getAttribute("type");
rrenkert@97:                 if(type.equals("point") && elem.getTagName().equals("symbol")) {
rrenkert@87:                     MarkerStyleWriter swriter = new MarkerStyleWriter (this.map, co);
rrenkert@97:                     swriter.write (elem);
rrenkert@87:                 }
rrenkert@97:                 else if(type.equals("line") && elem.getTagName().equals("symbol")) {
rrenkert@95:                     LineStyleWriter swriter = new LineStyleWriter (this.map, co);
rrenkert@97:                     swriter.write (elem);
rrenkert@97:                 }
rrenkert@97:                 else if(type.equals("polygon") && elem.getTagName().equals("symbol")) {
rrenkert@97:                     FillStyleWriter swriter = new FillStyleWriter (this.map, co);
rrenkert@97:                     swriter.write (elem);
rrenkert@87:                 }
rrenkert@87:             }
rrenkert@42:         }
rrenkert@41:     }
rrenkert@41: }
rrenkert@41: