package ts.nodejs;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import ts.TypeScriptException;
import ts.utils.FileUtils;

public abstract class AbstractNodejsProcess implements INodejsProcess {

	/**
	 * The node.js base dir.
	 */
	protected final File nodejsFile;

	/**
	 * The project dir where tsconfig.json is hosted.
	 */
	protected final File projectDir;

	private final INodejsLaunchConfiguration launchConfiguration;

	/**
	 * Process listeners.
	 */
	protected final List<INodejsProcessListener> listeners;

	private boolean hasError;

	public AbstractNodejsProcess(File nodejsFile, File projectDir) throws TypeScriptException {
		this(nodejsFile, projectDir, null);
	}

	/**
	 * Nodejs process constructor.
	 * 
	 * @param nodejsFile
	 *            the node.exe file.
	 * @param projectDir
	 *            the project base dir where tsconfig.json is hosted.
	 * @throws TernException
	 */
	public AbstractNodejsProcess(File nodejsFile, File projectDir, INodejsLaunchConfiguration launchConfiguration)
			throws TypeScriptException {
		this.projectDir = checkProjectDir(projectDir);
		this.nodejsFile = checkNodejsFile(nodejsFile);
		this.listeners = new ArrayList<INodejsProcessListener>();
		this.hasError = false;
		this.launchConfiguration = launchConfiguration;
	}

	private File checkProjectDir(File projectDir) throws TypeScriptException {
		if (projectDir == null) {
			throw new TypeScriptException("project directory cannot be null");
		}
		if (!projectDir.exists()) {
			throw new TypeScriptException("Cannot find project directory " + FileUtils.getPath(projectDir));
		}
		return projectDir;
	}

	private File checkNodejsFile(File nodejsFile) throws TypeScriptException {
		if (nodejsFile == null) {
			throw new TypeScriptException("node file cannot be null");
		}
		if (!nodejsFile.exists()) {
			throw new TypeScriptException("Cannot find node file " + FileUtils.getPath(nodejsFile));
		}
		return nodejsFile;
	}

	protected List<String> createNodeArgs() {
		if (launchConfiguration == null) {
			return null;
		}
		return launchConfiguration.createNodeArgs();
	}

	/**
	 * return the project dir where tsconfig.json is hosted.
	 * 
	 * @return
	 */
	public File getProjectDir() {
		return projectDir;
	}

	/**
	 * Add the given process listener.
	 * 
	 * @param listener
	 */
	public void addProcessListener(INodejsProcessListener listener) {
		synchronized (listeners) {
			listeners.add(listener);
		}
	}

	/**
	 * Remove the given process listener.
	 * 
	 * @param listener
	 */
	public void removeProcessListener(INodejsProcessListener listener) {
		synchronized (listeners) {
			listeners.remove(listener);
		}
	}

	/**
	 * Notify start process.
	 */
	protected void notifyCreateProcess(List<String> commands, File projectDir) {
		synchronized (listeners) {
			for (INodejsProcessListener listener : listeners) {
				listener.onCreate(this, commands, projectDir);
			}
		}
	}

	/**
	 * Notify start process.
	 * 
	 * @param startTime
	 *            time when node.js process is started.
	 */
	protected void notifyStartProcess(long startTime) {
		synchronized (listeners) {
			for (INodejsProcessListener listener : listeners) {
				listener.onStart(this);
			}
		}
	}

	/**
	 * Notify stop process.
	 */
	protected void notifyStopProcess() {
		synchronized (listeners) {
			for (INodejsProcessListener listener : listeners) {
				listener.onStop(this);
			}
		}
	}

	/**
	 * Notify data process.
	 * 
	 * @param jsonObject
	 */
	protected void notifyMessage(String message) {
		synchronized (listeners) {
			for (INodejsProcessListener listener : listeners) {
				listener.onMessage(this, message);
			}
		}
	}

	/**
	 * Notify error process.
	 */
	protected void notifyErrorProcess(String line) {
		this.hasError = true;
		synchronized (listeners) {
			for (INodejsProcessListener listener : listeners) {
				listener.onError(AbstractNodejsProcess.this, line);
			}
		}
	}

}

@@ -1,8 +1,411 @@
+/**%0D%0A *  Copyright (c) 2015-2016 Angelo ZERR.%0D%0A *  All rights reserved. This program and the accompanying materials%0D%0A *  are made available under the terms of the Eclipse Public License v1.0%0D%0A *  which accompanies this distribution, and is available at%0D%0A *  http://www.eclipse.org/legal/epl-v10.html%0D%0A *%0D%0A *  Contributors:%0D%0A *  Angelo Zerr %3Cangelo.zerr@gmail.com%3E - initial API and implementation%0D%0A */%0D%0A
 package 
@@ -473,38 +473,8 @@
 t;%0D%0A
-import java.util.LinkedList;%0D%0A
 impo
@@ -557,16 +557,70 @@
 ils;%0D%0A%0D%0A
+/**%0D%0A * Abstract class for node.js process.%0D%0A *%0D%0A */%0D%0A
 public a
@@ -717,16 +717,51 @@
 ase dir.
+ If null, it uses installed node.js
 %0D%0A%09 */%0D%0A
@@ -1064,38 +1064,8 @@
 %0D%0A%0D%0A
-%09private boolean hasError;%0D%0A%0D%0A
 %09pub
@@ -1737,34 +1737,8 @@
 );%0D%0A
-%09%09this.hasError = false;%0D%0A
 %09%09th
@@ -2250,65 +2250,101 @@
 %0A%09%09%09
-throw new TypeScriptException(%22node file cannot be null%22)
+// node.js file cannot be null. In this case it uses installed%0D%0A%09%09%09// node.js%0D%0A%09%09%09return null
 ;%0D%0A%09
@@ -4327,32 +4327,32 @@
 process.%0D%0A%09 */%0D%0A
+
 %09protected void 
@@ -4390,33 +4390,8 @@
  %7B%0D%0A
-%09%09this.hasError = true;%0D%0A
 %09%09sy

Fix https://github.com/angelozerr/typescript.java/issues/14