Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/FormatAction.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/FormatAction.java	(revision 23488)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/FormatAction.java	(revision 23489)
@@ -55,4 +55,5 @@
 	
 	String coll = (String)params.get(GSParams.COLLECTION); //SYSTEM_CLUSTER);
+    //String subaction = (String)params.get(GSParams.SUBACTION);
     String service = (String)params.get(GSParams.SERVICE);
     String classifier = (String)params.get("cl");
@@ -60,4 +61,5 @@
 
     logger.error("Collection="+coll);
+    logger.error("Subaction="+subaction);
     logger.error("Service="+service);
     logger.error("Classifier="+classifier);
@@ -72,7 +74,8 @@
 	Element mr_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_FORMAT_STRING, to, lang, uid);
 
-    request.setAttribute("service", service);
-    if(classifier != null)
-        request.setAttribute("classifier", classifier);
+    mr_request.setAttribute("service", service);
+    mr_request.setAttribute("subaction", subaction);
+    //if(classifier != null)
+    mr_request.setAttribute("classifier", classifier);
 
 	mr_request_message.appendChild(mr_request);
@@ -98,27 +101,12 @@
             InputSource is = new InputSource( new StringReader( input ) );
             Document d = (Document) builder.parse( is );
-            //Element e = d.getDocumentElement();
-            //Node d2 = this.doc.importNode(e,true); 
+            //Node n1 = d.getFirstChild();            
+            //Document d2 = (Document) this.doc.importNode(e, true);
 
-            //Document format_doc = this.converter.newDOM();
-            //doc.appendChild(d2);
-
-            //File interface_config_file = new File(GSFile.interfaceConfigFile(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String)this.config_params.get(GSConstants.INTERFACE_NAME))));
-            //if (!interface_config_file.exists()) {
-            //  logger.error(" interface config file: "+interface_config_file.getPath()+" not found!");
-            //}
-            //Document config_doc = this.converter.getDOM(interface_config_file, "utf-8");
-            //if (config_doc == null) {
-            //  logger.error(" could not parse interface config file: "+interface_config_file.getPath());
-            //}
-        
-            //Element config_elem = config_doc.getDocumentElement();
-            //String base_interface = config_elem.getAttribute("baseInterface");
-
+            //Element format_statement = this.doc.importNode(d, true);
 
             // Call XSLT to transform document to xml format string
             XMLTransformer transformer = new XMLTransformer();
-            //String stylesheet = GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(), (String)this.config_params.get(GSConstants.SITE_NAME), coll, (String)this.config_params.get(GSConstants.INTERFACE_NAME), "oran", "FormatAction");
-            //logger.error(stylesheet);
+            // HOW DO I DO THIS PROPERLY?
             Document style_doc = this.converter.getDOM(new File("/home/sam/greenstone3/web/interfaces/oran/transform/formatString.xsl"), "UTF-8");
 
@@ -127,10 +115,23 @@
 
             // not sure what to do here - some code from Transforming Receptionist
-            String transformed = transformer.transformToString(style_doc, d);
-            //Node transformed = transformer.transform(style_doc, d);
-           
+            //String transformed = transformer.transformToString(style_doc, d);
+            logger.error("About to transform");
+            Node transformed = (Node) transformer.transform(style_doc, d);  // Failing org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted. ; SystemID: file:///home/sam/greenstone3/packages/tomcat/bin/dummy.xsl
+
+            logger.error("Transform successful?");
+         
+            if(transformed==null)  // not null
+                logger.error("TRANSFORMED IS NULL");
+
+            logger.error("begin import"); 
+            Node imported = this.doc.importNode(transformed, true); // There was an exception org.w3c.dom.DOMException: NOT_SUPPORTED_ERR: The implementation does not support the requested type of object or operation.
+            logger.error("finished import"); 
+
+            String format_string2 = GSXML.xmlNodeToString(imported); // null pointer exception occuring here
+            logger.error("format string="+format_string2);
+ 
             Element format = this.doc.createElement(GSXML.FORMAT_STRING_ELEM);
-            GSXML.setNodeText(format, transformed);
-            //format.appendChild(this.doc.createTextNode(transformed));
+            //GSXML.setNodeText(format, transformed);
+            format.appendChild(transformed);
             //format.setNodeValue(transformed);
             mr_request.appendChild(format); 
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/Collection.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/Collection.java	(revision 23488)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/Collection.java	(revision 23489)
@@ -30,4 +30,5 @@
 import org.w3c.dom.NodeList; 
 
+import java.io.*;
 import java.io.File;
 import java.util.HashMap;
@@ -299,4 +300,203 @@
     } 
 
+ /** handles requests made to the ServiceCluster itself 
+     *
+     * @param req - the request Element- <request>
+     * @return the result Element - should be <response>
+     */
+    protected Element processMessage(Element request) {
+
+    Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+    response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
+    String type = request.getAttribute(GSXML.TYPE_ATT);
+    String lang = request.getAttribute(GSXML.LANG_ATT);
+    response.setAttribute(GSXML.TYPE_ATT, type);
+
+    if (type.equals(GSXML.REQUEST_TYPE_FORMAT_STRING)) {
+        logger.error("Received format string request");
+
+        String subaction = request.getAttribute("subaction");
+        logger.error("Subaction is " + subaction);
+
+        String service = request.getAttribute("service");
+        logger.error("Service is " + service);
+
+        String classifier = null;
+        if(service.equals("ClassifierBrowse"))
+        {
+            classifier = request.getAttribute("classifier");
+            logger.error("Classifier is " + classifier);
+        }
+
+        Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
+        //String format_string = GSXML.getNodeText(format_element);
+        Element format_statement = (Element) format_element.getFirstChild();
+
+        //logger.error("Format string: " + format_string);
+        logger.error("Config file location = " + GSFile.collectionConfigFile(this.site_home, this.cluster_name));
+
+        // check for version file
+
+        String directory = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name)).getParent() + File.separator;
+        logger.error("Directory is " + directory);
+
+        String version_filename = "";
+        if(service.equals("ClassifierBrowse"))
+            version_filename = directory + "browse_"+classifier+"_format_statement_version.txt";
+        else
+            version_filename = directory + "query_format_statement_version.txt";
+
+        File version_file = new File(version_filename);
+        logger.error("Version filename is " + version_filename);
+
+
+        if(subaction.equals("update"))
+        {
+            String version_number = "1";
+            BufferedWriter writer;
+
+            try{
+
+                if(version_file.exists())
+                {
+                    // Read version
+                    BufferedReader reader = new BufferedReader(new FileReader(version_filename));
+                    version_number = reader.readLine();
+                    int aInt = Integer.parseInt(version_number) + 1;
+                    version_number = Integer.toString(aInt);
+                    reader.close();
+                }
+                else{
+                    // Create
+                    version_file.createNewFile();
+                    writer = new BufferedWriter(new FileWriter(version_filename));
+                    writer.write(version_number);
+                    writer.close();
+                }
+
+                // Write version file
+                String format_statement_filename = "";
+
+                if(service.equals("ClassifierBrowse"))
+                    format_statement_filename = directory + "browse_"+classifier+"_format_statement_v" + version_number + ".txt";
+                else
+                    format_statement_filename = directory + "query_format_statement_v" + version_number + ".txt";
+
+                logger.error("Format statement filename is " + format_statement_filename);
+
+                // Write format statement
+                String format_string = GSXML.xmlNodeToString(format_statement);
+                writer = new BufferedWriter(new FileWriter(format_statement_filename));
+                writer.write(format_string);
+                writer.close();
+
+                // Update version number
+                writer = new BufferedWriter(new FileWriter(version_filename));
+                writer.write(version_number);
+                writer.close();
+
+            } catch (IOException e) {
+                logger.error("IO Exception "+e);
+            }
+        }
+
+        if(subaction.equals("save"))
+        {
+            logger.error("SAVE format statement");
+
+            // open collectionConfig.xml and read in to w3 Document
+            String collection_config = directory + "collectionConfig.xml";
+            Document config = this.converter.getDOM(new File(collection_config), "UTF-8");
+           
+            //String tag_name = "";
+            int k;
+            int index;
+            Element elem;
+            Node current_node = GSXML.getChildByTagName(config, "CollectionConfig");
+            NodeList current_node_list;
+
+            if(service.equals("ClassifierBrowse"))
+            {
+                //tag_name = "browse";
+                // if CLX then need to look in <classifier> X then <format>
+                // default is <browse><format>
+
+                current_node = GSXML.getChildByTagName(current_node, "browse");
+
+                // find CLX
+                if(classifier != null)
+                {
+                    current_node_list = GSXML.getChildrenByTagName(current_node, "classifier");
+                    index = Integer.parseInt(classifier.substring(2)) - 1;
+                    // index should be given by X-1
+                    current_node = current_node_list.item(index);
+                    current_node = GSXML.getChildByTagName(current_node, "format");
+                }
+                else{
+                    current_node = GSXML.getChildByTagName(current_node, "format");
+                }
+            }
+            else
+            {
+                // look in <format> with no attributes
+            
+                current_node_list = GSXML.getChildrenByTagName(current_node, "search");
+                for(k=0; k<current_node_list.getLength(); k++) 
+                {
+                    current_node = current_node_list.item(k);
+                    // if current_node has no attributes then break
+                    elem = (Element) current_node;
+                    if(elem.hasAttribute("name")==false)
+                        break;
+                }
+            }
+
+            // Current_node should be a format tag
+            elem = (Element) current_node;
+
+            logger.error("Current_node = " + elem.getNodeName());
+
+            // seems we want to remove current child/ren and replace with format_statement's child/ren?
+
+            // remove existing
+            current_node_list = elem.getChildNodes();
+            for(k=0; k<current_node_list.getLength(); k++)
+            {
+                current_node = elem.removeChild(current_node_list.item(k));
+            }
+
+            // append new
+            current_node_list = format_statement.getChildNodes();
+            for(k=0; k<current_node_list.getLength(); k++)
+            {
+                current_node = elem.appendChild(current_node_list.item(k));
+            }
+
+            //String text = GSXML.getNodeText(elem);
+            //logger.error(text);
+            //text = text.replaceAll("_httpsite_", http_site);
+            //text = text.replaceAll("_httpcollection_", http_collection);
+            //GSXML.setNodeText(d, text);
+
+            // Now convert config document to string for writing to file
+            String new_config = GSXML.xmlNodeToString(config);
+
+            // Write to file (not original! for now)
+            try{
+                BufferedWriter writer = new BufferedWriter(new FileWriter(collection_config+".new"));
+                writer.write(new_config);
+                writer.close();
+            } catch (IOException e) {
+                logger.error("IO Exception "+e);
+            }
+        }
+    }
+    else { // unknown type
+        super.processMessage(request);
+
+    }
+    return response;
+    }
+
 }
 
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java	(revision 23488)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java	(revision 23489)
@@ -34,4 +34,5 @@
 import java.io.*;
 import java.io.File;
+import java.io.RandomAccessFile;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -510,5 +511,5 @@
 	    return response;
 	}
-
+    /*
     if (type.equals(GSXML.REQUEST_TYPE_FORMAT_STRING)) {
         logger.error("Received format string request");
@@ -528,5 +529,5 @@
         // check for version file
 
-        String directory = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name)).getParent() + "/";
+        String directory = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name)).getParent() + File.pathSeparator;
         logger.error("Directory is " + directory);
 
@@ -540,5 +541,8 @@
         File version_file = new File(version_filename);
         logger.error("Version filename is " + version_filename);
+
         String version_number = "1";
+        BufferedWriter writer; // = new BufferedWriter(new FileWriter(version_filename));
+        //RandomAccessFile version_file_random_access;
 
         try{
@@ -548,8 +552,12 @@
                 // Read version
                  BufferedReader reader = new BufferedReader(new FileReader(version_filename));
+                 //version_file_random_access = new RandomAccessFile(version_file, "r");
+                 //logger.error("
+                 //version_number = version_file_random_access.readInt();
                  version_number = reader.readLine();
                  int aInt = Integer.parseInt(version_number) + 1;
                  version_number = Integer.toString(aInt);
                  reader.close();
+                 //version_file_random_access.close();
             }
             else{
@@ -557,7 +565,10 @@
                 version_file.createNewFile(); 
                 // write 1 to file
-                BufferedWriter writer = new BufferedWriter(new FileWriter(version_filename));
+                writer = new BufferedWriter(new FileWriter(version_filename));
+                //version_file_random_access = new RandomAccessFile(version_file, "w");
+                //version_file_random_access.writeInt(version_number);
                 writer.write(version_number);
                 writer.close();
+                //version_file_random_access.close();
             }
 
@@ -572,9 +583,20 @@
             logger.error("Format statement filename is " + format_statement_filename);
 
-            BufferedWriter writer = new BufferedWriter(new FileWriter(format_statement_filename));
+            writer = new BufferedWriter(new FileWriter(format_statement_filename));
             writer.write(format_string);
             writer.close();
 
             // Update version number
+            //version_file_random_access = new RandomAccessFile(version_file, "w");
+            //version_file_random_access.writeInt(version_number);
+            //version_file_random_access.close();
+
+            writer = new BufferedWriter(new FileWriter(version_filename));
+            //version_file_random_access = new RandomAccessFile(version_file, "w");
+            //version_file_random_access.writeInt(version_number);
+            writer.write(version_number);
+            writer.close();
+
+
 
         } catch (IOException e) {
@@ -584,5 +606,5 @@
 
 
-    }
+    }*/
 	if (type.equals(GSXML.REQUEST_TYPE_SYSTEM)) {
 	    response = processSystemRequest(request);
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXML.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXML.java	(revision 23488)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXML.java	(revision 23489)
@@ -921,11 +921,14 @@
     sb.append(e.getNodeName());
     NamedNodeMap attrs = e.getAttributes();
-    for (int i = 0; i < attrs.getLength(); i++) {
-      Node attr = attrs.item(i);
-      sb.append(' ');
-      sb.append(attr.getNodeName());
-      sb.append("=\"");
-      sb.append(attr.getNodeValue());
-      sb.append('"');
+    if(attrs != null)
+    {
+        for (int i = 0; i < attrs.getLength(); i++) {
+            Node attr = attrs.item(i);
+            sb.append(' ');
+            sb.append(attr.getNodeName());
+            sb.append("=\"");
+            sb.append(attr.getNodeValue());
+            sb.append('"');
+        }
     }
     
Index: /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/XMLTransformer.java
===================================================================
--- /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/XMLTransformer.java	(revision 23488)
+++ /main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/XMLTransformer.java	(revision 23489)
@@ -177,4 +177,5 @@
 			// Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
 			Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
+            logger.error("XMLTransformer transformer is " + transformer);
 			transformer.setErrorListener(new TransformErrorListener());
 			if (parameters != null) {
Index: /main/trunk/greenstone3/web/interfaces/oran/js/gui_div.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/oran/js/gui_div.js	(revision 23488)
+++ /main/trunk/greenstone3/web/interfaces/oran/js/gui_div.js	(revision 23489)
@@ -4,44 +4,77 @@
 var initialised_iframe = "false";
 
-function createFormatStatement()
-{
-
+//function createFormatStatement()
+//{
+
+    //var formatDiv = document.getElementById('formatStatement');
+    //var formatStatement = innerXHTML(formatDiv);
+    //console.log(formatStatement);
+
+    // find collection name
+
+    //var myurl = document.URL;
+    //console.log(myurl);
+    //var first = myurl.indexOf("&c")+3;
+    //var last = myurl.indexOf("&", first);
+    
+    //var collection_name = getSubstring(myurl, "&c", "&"); //myurl.substring(first,last); ///&c=(.*)&/.exec(myurl);
+    //console.log(collection_name);
+
+    //first = myurl.indexOf("&s")+3;
+    //last = myurl.indexOf("&", first);
+
+    //var service_name = myurl.substring(first,last);
+    //console.log(service_name);
+
+    //var classifier_name = null;
+
+    //if(service_name == "ClassifierBrowse")
+    //{
+    //    first = myurl.indexOf("&cl")+4;
+    //    last = myurl.indexOf("&", first);
+
+    //    classifier_name = myurl.substring(first,last);
+    //    console.log(classifier_name);
+    //}
+
+    //var myurl = 'http://localhost:8080/greenstone3/format?a=s&sa=s&t='+formatStatement;
+
+    //jQuery.post( url, [ data ], [ success(data, textStatus, XMLHttpRequest) ], [ dataType ] )
+
+    // How do I find out my collection name?
+
+function getSubstring(str, first, last)
+{
+    var first_index = str.indexOf(first)+first.length+1;
+    var last_index = str.indexOf(last, first_index);
+
+    var substring = str.substring(first_index, last_index);
+
+    console.log(substring);
+
+    return substring;
+}
+    
+function getFormatStatement()
+{
     var formatDiv = document.getElementById('formatStatement');
     var formatStatement = innerXHTML(formatDiv);
-    //console.log(formatStatement);
-
-    // find collection name
+    return formatStatement;
+}
+
+function updateFormatStatement()
+{
+    var formatStatement = getFormatStatement();
 
     var myurl = document.URL;
-    console.log(myurl);
-    var first = myurl.indexOf("&c")+3;
-    var last = myurl.indexOf("&", first);
-    
-    var collection_name = myurl.substring(first,last); ///&c=(.*)&/.exec(myurl);
-    console.log(collection_name);
-
-    first = myurl.indexOf("&s")+3;
-    last = myurl.indexOf("&", first);
-
-    var service_name = myurl.substring(first,last);
-    console.log(service_name);
-
+
+    var collection_name = getSubstring(myurl, "&c", "&");
+    var service_name = getSubstring(myurl, "&s", "&");
     var classifier_name = null;
 
     if(service_name == "ClassifierBrowse")
-    {
-        first = myurl.indexOf("&cl")+4;
-        last = myurl.indexOf("&", first);
-
-        classifier_name = myurl.substring(first,last);
-        console.log(classifier_name);
-    }
-
-    //var myurl = 'http://localhost:8080/greenstone3/format?a=s&sa=s&t='+formatStatement;
-
-    //jQuery.post( url, [ data ], [ success(data, textStatus, XMLHttpRequest) ], [ dataType ] )
-
-    // How do I find out my collection name?
-    var post_url = "http://localhost:8080/greenstone3/format?a=f&c=" + collection_name +"&s=" + service_name;
+        classifier_name = getSubstring(myurl, "&cl", "&");
+
+    var post_url = "http://localhost:8080/greenstone3/format?a=f&sa=update&c=" + collection_name +"&s=" + service_name;
 
     if(classifier_name != null)
@@ -53,4 +86,30 @@
         console.log(data);
         }, 'html');
+}
+
+function saveFormatStatement()
+{
+    var formatStatement = getFormatStatement();
+
+    var myurl = document.URL;
+
+    var collection_name = getSubstring(myurl, "&c", "&");
+    var service_name = getSubstring(myurl, "&s", "&");
+    var classifier_name = null;
+
+    if(service_name == "ClassifierBrowse")
+        classifier_name = getSubstring(myurl, "&cl", "&");
+
+    var post_url = "http://localhost:8080/greenstone3/format?a=f&sa=save&c=" + collection_name +"&s=" + service_name;
+
+    if(classifier_name != null)
+        post_url = post_url + "&cl=" + classifier_name;
+
+    $.post(post_url, {data: formatStatement}, function(data) {
+        //$('.result').innerHTML = data; //html(data);
+        console.log("Success, we have received data");
+        console.log(data);
+        }, 'html');
+}
 
 /*
@@ -104,5 +163,5 @@
         */
     //}
-}
+//}
 
 function traverse(node, formatstring)
Index: /main/trunk/greenstone3/web/interfaces/oran/transform/layouts/main.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/oran/transform/layouts/main.xsl	(revision 23488)
+++ /main/trunk/greenstone3/web/interfaces/oran/transform/layouts/main.xsl	(revision 23489)
@@ -177,5 +177,6 @@
     <td width="75%">
 
-    <button id="updateFormatStatement" type="button" onclick="createFormatStatement()">Update Format Statement</button>
+    <button id="updateFormatStatement" type="button" onclick="updateFormatStatement()">Update Format Statement</button>
+    <button id="saveFormatStatement" type="button" onclick="saveFormatStatement()">Save Format Statement</button>
 
     <div id="formatStatement">
