/*=============================================================================#
 # Copyright (c) 2017 Stephan Wahlbrink and others.
 # 
 # This program and the accompanying materials are made available under the
 # terms of the Eclipse Public License 2.0 which is available at
 # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
 # which is available at https://www.apache.org/licenses/LICENSE-2.0.
 # 
 # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
 # 
 # Contributors:
 #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
 #=============================================================================*/

package org.eclipse.statet.rj.server.util;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.eclipse.statet.rj.RjInvalidConfigurationException;


public class LocalREnv {
	
	
	public static final int OS_WIN= 1;
	public static final int OS_NIX= 2;
	public static final int OS_MAC= 3;
	
	
	private static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server"); //$NON-NLS-1$
	
	private static final int OS_TYPE;
	static {
		final String osname= System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
		if (osname.contains("win")) { //$NON-NLS-1$
			OS_TYPE= OS_WIN;
		}
		else if (osname.contains("mac")) { //$NON-NLS-1$
			OS_TYPE= OS_MAC;
		}
		else {
			OS_TYPE= OS_NIX;
		}
	}
	
	private static final Pattern PATH_SPLITTER= Pattern.compile(Pattern.quote(File.pathSeparator));
	
	private static final String DEFAULT_HOME_TEMPLATE= "${R_HOME}"; //$NON-NLS-1$
	
	private static final List<String> DEFAULT_PATHS_TEMPLATES= Arrays.asList(
			"${R_LIBS}", //$NON-NLS-1$
			"${R_LIBS_USER}", //$NON-NLS-1$
			"${R_LIBS_SITE}" , //$NON-NLS-1$
			"${R_HOME}/library" ); //$NON-NLS-1$
	
	
	private static void add(final List<Path> paths, final Path pathToAdd) {
		if (pathToAdd != null && !paths.contains(pathToAdd)) {
			paths.add(pathToAdd);
		}
	}
	
	private static void addAll(final List<Path> paths, final List<Path> pathsToAdd) {
		if (pathsToAdd != null) {
			pathsToAdd.forEach((path) -> add(paths, path));
		}
	}
	
	
	/**
	 * R home path.
	 */
	private final Path rHomePath;
	
	/**
	 * R library path (list with directories containing R packages).
	 */
	private final List<Path> rLibPaths;
	
	
	public LocalREnv(final String rHomeTemplate, final List<String> rLibPathsTemplates,
			Function<String, String> varResolver)
			throws RjInvalidConfigurationException {
		if (rHomeTemplate == null) {
			throw new NullPointerException("rHomeTemplate"); //$NON-NLS-1$
		}
		if (rLibPathsTemplates == null) {
			throw new NullPointerException("rLibPathsTemplates"); //$NON-NLS-1$
		}
		if (varResolver == null) {
			varResolver= System::getenv;
		}
		this.rHomePath= checkPath(resolveTemplate(rHomeTemplate, varResolver));
		this.rLibPaths= resolveRLibPaths(rLibPathsTemplates, varResolver);
		
		checkSpec();
	}
	
	public LocalREnv() throws RjInvalidConfigurationException {
		this(DEFAULT_HOME_TEMPLATE, DEFAULT_PATHS_TEMPLATES, null);
	}
	
	public LocalREnv(final Function<String, String> varResolver)
			throws RjInvalidConfigurationException {
		this(DEFAULT_HOME_TEMPLATE, DEFAULT_PATHS_TEMPLATES, varResolver);
	}
	
	
	public LocalREnv(final String rHome, final List<String> rLibPaths)
			throws RjInvalidConfigurationException {
		if (rHome == null) {
			throw new NullPointerException("rHome"); //$NON-NLS-1$
		}
		if (rLibPaths == null) {
			throw new NullPointerException("rLibPaths"); //$NON-NLS-1$
		}
		this.rHomePath= checkPath(rHome);
		this.rLibPaths= resolveRLibPaths(rLibPaths, null);
		
		checkSpec();
	}
	
	public LocalREnv(final Path rHomePath, final List<Path> rLibPaths)
			throws RjInvalidConfigurationException {
		if (rHomePath == null) {
			throw new NullPointerException("rHome"); //$NON-NLS-1$
		}
		if (rLibPaths == null) {
			throw new NullPointerException("rLibPaths"); //$NON-NLS-1$
		}
		this.rHomePath= rHomePath;
		this.rLibPaths= rLibPaths;
		
		checkSpec();
	}
	
	
	protected List<Path> resolveRLibPaths(final List<String> rLibPathsTemplates,
			final Function<String, String> varResolver) {
		final List<Path> paths= new ArrayList<>();
		for (final String template : rLibPathsTemplates) {
			final String value= (varResolver != null) ?
					resolveTemplate(template, varResolver) :
					template;
			try {
				addAll(paths, checkPathList(value));
			}
			catch (final Exception e) {
				LOGGER.log(Level.WARNING, "An error occurred when adding '" + template + "' to R library paths.", e);
			}
		}
		
		return paths;
	}
	
	protected String resolveTemplate(final String s, final Function<String, String> varResolver) {
		if (s != null && s.indexOf('$') >= 0) {
			final StringBuilder sb= new StringBuilder();
			int startIdx= 0;
			int endIdx= 0;
			while (true) {
				startIdx= s.indexOf("${", endIdx);
				if (startIdx >= 0) {
					sb.append(s, endIdx, startIdx);
					startIdx+= 2;
					endIdx= s.indexOf('}', startIdx);
					if (endIdx >= 0) {
						final String value= varResolver.apply(s.substring(startIdx, endIdx));
						if (value != null) {
							sb.append(value);
							endIdx++;
							continue;
						}
					}
					break;
				}
				else {
					sb.append(s, endIdx, s.length());
					return sb.toString();
				}
			}
		}
		return null;
	}
	
	protected void checkSpec() throws RjInvalidConfigurationException {
		if (LOGGER.isLoggable(Level.CONFIG)) {
			final StringBuilder sb= new StringBuilder();
			sb.append("RJClassLoader - R home path= "); //$NON-NLS-1$
			if (this.rHomePath != null) {
				sb.append(this.rHomePath);
			}
			else {
				sb.append("<missing>"); //$NON-NLS-1$
			}
			sb.append("RJClassLoader - R library paths= "); //$NON-NLS-1$
			if (this.rLibPaths != null) {
				if (this.rLibPaths.isEmpty()) {
					sb.append("<empty>"); //$NON-NLS-1$
				}
				else {
					ServerUtils.prettyPrint(this.rLibPaths, sb);
				}
			}
			else {
				sb.append("<missing>"); //$NON-NLS-1$
			}
			LOGGER.log(Level.CONFIG, sb.toString());
		}
		
		if (this.rHomePath == null) {
			throw new RjInvalidConfigurationException("Spec of R home path is missing."); //$NON-NLS-1$
		}
		if (this.rLibPaths.isEmpty()) {
			throw new RjInvalidConfigurationException("Spec of R library paths is empty"); //$NON-NLS-1$
		}
	}
	
	
	public Path checkPath(String path) {
		if (path != null) {
			path= path.trim();
			if (!path.isEmpty()) {
				return Paths.get(path).normalize();
			}
		}
		return null;
	}
	
	public List<Path> checkPathList(String pathList) {
		if (pathList != null) {
			pathList= pathList.trim();
			if (!pathList.isEmpty()) {
				final String[] split= PATH_SPLITTER.split(pathList);
				final ArrayList<Path> list= new ArrayList<>(split.length);
				for (int i= 0; i < split.length; i++) {
					final Path path= checkPath(split[i]);
					if (path != null) {
						list.add(path);
					}
				}
				return list;
			}
		}
		return null;
	}
	
	
	public int getOSType() {
		return OS_TYPE;
	}
	
	public Path getRHomePath() {
		return this.rHomePath;
	}
	
	public List<Path> getRLibPaths() {
		return Collections.unmodifiableList(this.rLibPaths);
	}
	
	
	public Path searchRPkg(final String name) {
		for (final Path path : this.rLibPaths) {
			try {
				final Path packagePath= path.resolve(name);
				if (Files.isRegularFile(packagePath.resolve("DESCRIPTION"))) {
					return packagePath;
				}
			}
			catch (final Exception e) {}
		}
		return null;
	}
	
}
