package net.sourceforge.phpdt.internal.launching;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.SAXParserFactory;

import org.eclipse.core.runtime.IPath;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class PHPRuntime {
	protected static PHPRuntime runtime;

	protected List installedInterpreters;

	protected PHPInterpreter selectedInterpreter;

	protected PHPRuntime() {
		super();
	}

	public static PHPRuntime getDefault() {
		if (runtime == null) {
			runtime = new PHPRuntime();
		}
		return runtime;
	}

	public PHPInterpreter getSelectedInterpreter() {
		if (selectedInterpreter == null) {
			loadRuntimeConfiguration();
		}
		return selectedInterpreter;
	}

	public PHPInterpreter getInterpreter(String installLocation) {
		Iterator interpreters = getInstalledInterpreters().iterator();
		while (interpreters.hasNext()) {
			PHPInterpreter each = (PHPInterpreter) interpreters.next();
			if (each.getInstallLocation().toString().equals(installLocation))
				return each;
		}

		return getSelectedInterpreter();
	}

	public void setSelectedInterpreter(PHPInterpreter anInterpreter) {
		selectedInterpreter = anInterpreter;
		saveRuntimeConfiguration();
	}

	public void addInstalledInterpreter(PHPInterpreter anInterpreter) {
		getInstalledInterpreters().add(anInterpreter);
		if (getInstalledInterpreters().size() == 1)
			setSelectedInterpreter((PHPInterpreter) getInstalledInterpreters()
					.get(0));

		saveRuntimeConfiguration();
	}

	public List getInstalledInterpreters() {
		if (installedInterpreters == null)
			loadRuntimeConfiguration();
		return installedInterpreters;
	}

	public void setInstalledInterpreters(List newInstalledInterpreters) {
		installedInterpreters = newInstalledInterpreters;
		if (installedInterpreters.size() > 0)
			setSelectedInterpreter((PHPInterpreter) installedInterpreters
					.get(0));
		else
			setSelectedInterpreter(null);
	}

	protected void saveRuntimeConfiguration() {
		writeXML(getRuntimeConfigurationWriter());
	}

	protected Writer getRuntimeConfigurationWriter() {
		try {
			OutputStream stream = new BufferedOutputStream(
					new FileOutputStream(getRuntimeConfigurationFile()));
			return new OutputStreamWriter(stream);
		} catch (FileNotFoundException e) {
		}

		return null;
	}

	protected void loadRuntimeConfiguration() {
		installedInterpreters = new ArrayList();
		try {
			File file = getRuntimeConfigurationFile();
			if (file.exists()) {
				XMLReader reader = SAXParserFactory.newInstance()
						.newSAXParser().getXMLReader();
				reader
						.setContentHandler(getRuntimeConfigurationContentHandler());
				reader.parse(new InputSource(
						getRuntimeConfigurationReader(file)));
			}
		} catch (Exception e) {
			PHPLaunchingPlugin.log(e);
		}
	}

	protected Reader getRuntimeConfigurationReader(File file) {
		try {
			return new FileReader(file);
		} catch (FileNotFoundException e) {
		}
		return new StringReader("");
	}

	protected void writeXML(Writer writer) {
		try {
			writer
					.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><runtimeconfig>");
			Iterator interpretersIterator = installedInterpreters.iterator();
			while (interpretersIterator.hasNext()) {
				writer.write("<interpreter name=\"");

				PHPInterpreter entry = (PHPInterpreter) interpretersIterator
						.next();
				// writer.write(entry.getName());
				writer.write("\" path=\"");
				writer.write(entry.getInstallLocation().toString());
				writer.write("\"");
				if (entry.equals(selectedInterpreter))
					writer.write(" selected=\"true\"");

				writer.write("/>");
			}
			writer.write("</runtimeconfig>");
			writer.flush();
		} catch (IOException e) {
			PHPLaunchingPlugin.log(e);
		}
	}

	protected ContentHandler getRuntimeConfigurationContentHandler() {
		return new ContentHandler() {
			public void setDocumentLocator(Locator locator) {
			}

			public void startDocument() throws SAXException {
			}

			public void endDocument() throws SAXException {
			}

			public void startPrefixMapping(String prefix, String uri)
					throws SAXException {
			}

			public void endPrefixMapping(String prefix) throws SAXException {
			}

			public void startElement(String namespaceURI, String localName,
					String qName, Attributes atts) throws SAXException {
				if ("interpreter".equals(qName)) {
					String interpreterName = atts.getValue("name");
					java.io.File installLocation;
					if (interpreterName != null) {
						installLocation = new File(atts.getValue("path")
								+ File.separatorChar + interpreterName);
					} else {
						installLocation = new File(atts.getValue("path"));
					}
					PHPInterpreter interpreter = new PHPInterpreter(
							installLocation);
					installedInterpreters.add(interpreter);
					if (atts.getValue("selected") != null)
						selectedInterpreter = interpreter;
				}
			}

			public void endElement(String namespaceURI, String localName,
					String qName) throws SAXException {
			}

			public void characters(char[] ch, int start, int length)
					throws SAXException {
			}

			public void ignorableWhitespace(char[] ch, int start, int length)
					throws SAXException {
			}

			public void processingInstruction(String target, String data)
					throws SAXException {
			}

			public void skippedEntity(String name) throws SAXException {
			}
		};
	}

	protected File getRuntimeConfigurationFile() {
		IPath stateLocation = PHPLaunchingPlugin.getDefault()
				.getStateLocation();
		IPath fileLocation = stateLocation.append("runtimeConfiguration.xml");
		return new File(fileLocation.toOSString());
	}
}