/*
 * This file is part of NixNote/NeighborNote 
 * Copyright 2009 Randy Baumgarte
 * 
 * This file may be licensed under the terms of of the
 * GNU General Public License Version 2 (the ``GPL'').
 *
 * Software distributed under the License is distributed
 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
 * express or implied. See the GPL for the specific language
 * governing rights and limitations.
 *
 * You should have received a copy of the GPL along with this
 * program. If not, go to http://www.gnu.org/licenses/gpl.html
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
*/
package cx.fbn.nevernote.xml;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import cx.fbn.nevernote.Global;

public class XMLNoteRepair {
	public boolean saveInvalidXML;
	
	public String parse(String xmlData, boolean validate) {
		saveInvalidXML = false;
		InputSource is = new InputSource();
		is.setCharacterStream(new StringReader(xmlData));
		XMLNoteRepairHandler handler = new XMLNoteRepairHandler();
		
		// Replace DTD with local copy in case we are not connected
		File dtdFile = Global.getFileManager().getXMLDirFile("enml2.dtd");
		String dtd = dtdFile.toURI().toString();
		xmlData = xmlData.replace("<!DOCTYPE en-note SYSTEM \'http://xml.evernote.com/pub/enml2.dtd'>", 
				"<!DOCTYPE en-note SYSTEM \"" +dtd +"\">");
		xmlData = xmlData.replace("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">", 
				"<!DOCTYPE en-note SYSTEM \"" +dtd +"\">");
		
		handler.setXml(xmlData);
		is.setCharacterStream(new StringReader(handler.getXml()));
        
		boolean fixed = false;
		int i=0;
		int max = 10;
		if (validate)
			max = 10000;
		while (!fixed && i<max) {
			try {
				i++;
				SAXParserFactory factory = SAXParserFactory.newInstance();
				factory.setValidating(validate);
				SAXParser parser = factory.newSAXParser();
				parser.parse(is, handler);
				fixed = true;
			} catch (EnmlException e) { 
				String message = e.getMessage();
				saveInvalidXML = true;
				//System.out.println("ENML Exception: " +message);
				boolean found = false;
				int endAttribute = message.indexOf(" must be declared for element type ");
				if (message.startsWith("Attribute ") && endAttribute > -1) {
					String attribute = message.substring(11, endAttribute-1);
					String element = message.substring(message.indexOf("\"", endAttribute+3));
					element = element.replace("\"", "");
					element = element.substring(0,element.length()-1);
					Global.addInvalidAttribute(element, attribute);
					handler.stripAttribute(attribute, e.getLineNumber(), e.getColumnNumber());
					is.setCharacterStream(new StringReader(handler.getXml()));
					found = true;
				}
				int endElement = message.indexOf(" must be declared.");
				if (message.startsWith("Element type") && endElement > -1) {
					String element = message.substring(14,endElement-1);
					Global.addInvalidElement(element);
					handler.renameElement(element, e.getLineNumber(), e.getColumnNumber());
					is.setCharacterStream(new StringReader(handler.getXml()));
					found = true;
				}
				if (!found)
					System.err.println("New enml validation error: " +e.getMessage() +" Line:" +e.getLineNumber() +" Column:" +e.getColumnNumber());
			} catch (SAXParseException e) {
				System.err.println("SAXParse Exception - Attempt #"+i +" "+e.getMessage());
				handler.repair(e.getLineNumber(), e.getColumnNumber());
				is.setCharacterStream(new StringReader(handler.getXml()));
				if (validate) {
					System.err.println("Error validating ENML2 DTD");
					return null;
				}
			} catch (SAXException e) {
				System.err.append("SAXException");
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				System.err.println("Parser Config Error");
				e.printStackTrace();
			} catch (IOException e) {
				System.err.println("IO Exception");
				e.printStackTrace();
			}
		}
		if (!fixed)
			return null;
		else {
			// Replace DTD with online copy
			xmlData = handler.getXml();
			xmlData = xmlData.replace("<!DOCTYPE en-note SYSTEM \"" +dtd +"\">", "<!DOCTYPE en-note SYSTEM \'http://xml.evernote.com/pub/enml2.dtd'>");
			return xmlData;			
		}
	}
}
