/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.lib.cvsclient.file;

import java.io.*;

import org.netbeans.lib.cvsclient.*;
import org.netbeans.lib.cvsclient.admin.*;
import org.netbeans.lib.cvsclient.command.*;

/**
 * A utility class for file based operations.
 *
 * @author Thomas Singer
 */
public final class FileUtils {

	// Static =================================================================

	/**
	 * Copies the specified sourceFile to the specified targetFile.
	 */
	public static void copyFile(File sourceFile, File targetFile) throws IOException {
		if (sourceFile == null || targetFile == null) {
			throw new NullPointerException("sourceFile and targetFile must not be null");
		}

		// ensure existing parent directories
		final File directory = targetFile.getParentFile();
		if (!directory.exists() && !directory.mkdirs()) {
			throw new IOException("Could not create directory '" + directory + "'");
		}

		InputStream inputStream = null;
		OutputStream outputStream = null;
		try {
			inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
			outputStream = new BufferedOutputStream(new FileOutputStream(targetFile));

			final byte[] buffer = new byte[32768];
			for (int readBytes = inputStream.read(buffer);
			     readBytes > 0;
			     readBytes = inputStream.read(buffer)) {
				outputStream.write(buffer, 0, readBytes);
			}
		}
		finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				}
				catch (IOException ex) {
					// ignore
				}
			}
			if (outputStream != null) {
				try {
					outputStream.close();
				}
				catch (IOException ex) {
					// ignore
				}
			}
		}
	}

	public static String ensureLeadingSlash(String filePath) {
		if (filePath.startsWith("/")) {
			return filePath;
		}
		return '/' + filePath;
	}

	public static String removeLeadingSlash(String filePath) {
		if (filePath.startsWith("/")) {
			return filePath.substring(1);
		}
		return filePath;
	}

	public static String ensureTrailingSlash(String path) {
		if (path.endsWith("/")) {
			return path;
		}
		return path + '/';
	}

	public static String removeTrailingSlash(String path) {
		if (path.endsWith("/")) {
			return path.substring(0, path.length() - 1);
		}
		return path;
	}

	public static String replaceMultipleSlashs(String path) {
		final StringBuilder buffer = new StringBuilder(path);
		char prevChr = 0;
		int i = 0;
		while (i < buffer.length()) {
			final char chr = buffer.charAt(i);
			if (chr == '/' && prevChr == '/') {
				buffer.delete(i, i + 1);
				continue;
			}

			prevChr = chr;
			i++;
		}
		return buffer.toString();
	}

	public static String concatPaths(String prefix, String suffix) {
		final String prefixWithTrailingSlash = removeLeadingDot(prefix);
		final String suffixWithTrailingSlash = removeLeadingDot(suffix);
		return ensureLeadingSlash(removeTrailingSlash(prefixWithTrailingSlash + removeLeadingSlash(suffixWithTrailingSlash)));
	}

	public static String readLineFromFile(File file) throws IOException {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(file));
			final String line = reader.readLine();
			if (line == null) {
				throw new IOException("Could not read content from " + file);
			}
			return line;
		}
		finally {
			if (reader != null) {
				reader.close();
			}
		}
	}

	public static String readPathLineFromFile(File file) throws IOException {
		final String pathLine = readLineFromFile(file);
		if (pathLine == null) {
			throw new IOException("Empty file " + file.getAbsolutePath());
		}

		return replaceMultipleSlashs(pathLine);
	}

	public static String getUnixRepositoryPath(IClientEnvironment clientEnvironment, FsFilePath filePath) throws IOCommandException {
		return toUnixPath(getRelativeRepositoryPath(filePath, clientEnvironment), false);
	}

	public static FsFilePath getRelativeRepositoryPath(FsFilePath filePath, IClientEnvironment clientEnvironment) throws IOCommandException {
		return FsFilePath.createInstance(getRelativeRepositoryPath(clientEnvironment), filePath.getPath());
	}

	public static FsDirectoryPath getRelativeRepositoryPath(FsDirectoryPath directoryPath, IClientEnvironment clientEnvironment) throws IOCommandException {
		return FsDirectoryPath.createRelativeInstance(getRelativeRepositoryPath(clientEnvironment), directoryPath.getPath());
	}

	public static String toUnixPath(String path, boolean usePeriodForRoot) {
		final String pathWithoutLeadingSlash = path.startsWith("/") ? path.substring(1) : path;
		if (usePeriodForRoot && pathWithoutLeadingSlash.length() == 0) {
			return ".";
		}
		return pathWithoutLeadingSlash;
	}

	public static String toUnixPath(FsPath fsPath, boolean usePeriodForRoot) {
		return toUnixPath(fsPath.getPath(), usePeriodForRoot);
	}

	// Setup ==================================================================

	/**
	 * This utility class needs not to be instantiated anywhere.
	 */
	private FileUtils() {
	}

	// Utils ==================================================================

	private static String removeLeadingDot(String prefix) {
		String prefixWithTrailingSlash = ensureTrailingSlash(prefix);
		if (prefixWithTrailingSlash.startsWith("./")) {
			prefixWithTrailingSlash = prefixWithTrailingSlash.substring(2);
		}
		return prefixWithTrailingSlash;
	}

	private static FsDirectoryPath getRelativeRepositoryPath(IClientEnvironment clientEnvironment) throws IOCommandException {
		final ICvsFileSystem cvsFileSystem = clientEnvironment.getCvsFileSystem();
		final IAdminReader adminReader = clientEnvironment.getAdminReader();

		try {
			return cvsFileSystem.getRelativeRepositoryRootPath(adminReader);
		}
		catch (IOException ex) {
			throw new IOCommandException(ex);
		}
	}
}
