//
//  NSPathUtilities.java
//  sPearCat
//
//  Created by Pierre Frisch on 16/09/05.
//  Copyright 2005 __MyCompanyName__. All rights reserved.
//
package com.webobjects.foundation;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.jar.*;

public class NSPathUtilities {
	private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(NSPathUtilities.class);
	public static final Class _CLASS = _NSUtilities._classWithFullySpecifiedName("com.webobjects.foundation.NSPathUtilities");
	public static String _fileURLPrefix;
	
	
	private NSPathUtilities() {
		throw new IllegalStateException("Can't instantiate an instance of class " + getClass().getName());
	}
	
	public static String homeDirectory() {
		return System.getProperty("user.home");
	}
	
	public static String _fileSeparatorStandardizedPath(String path) {
		return (path != null ? (File.separatorChar != '/' ? path : path.replace(File.separatorChar, '/')) : "");
	}
	
	public static String _normalizedPath(String path) {
		return (path != null ? (File.separatorChar != '/' ? path.replace('/', File.separatorChar) : path) : "");
	}
	
	public static String _standardizedPath(String path) {
		if (path == null) path = "";
		int pathLength = path.length();
		if(pathLength > 0) {
			path = _fileSeparatorStandardizedPath(path);
			while(path.indexOf("//") > 0) {
				path = path.replaceAll("//", "/");
			}
		}
		return path;
	}
	
	public static String pathExtension(String path) {
		String extension = "";
		if (path == null) path = "";
		int pathLength = path.length();
		if(pathLength > 0) {
			String pathFragment = _fileSeparatorStandardizedPath(path);
			int j = pathFragment.lastIndexOf('.');
			if(j >= 0) {
				int k = pathFragment.lastIndexOf('/');
				int l = pathLength - 1;
				int i1 = pathLength;
				if(k == l) {
					k = pathFragment.lastIndexOf('/', l - 1);
					i1 = l;
				}
				if((k < 0 || j > k) && j < pathLength - 1)
					extension = pathFragment.substring(j + 1, i1);
			}
		}
		return extension;
	}
	
	public static String lastPathComponent(String path) {
		String filename = path;
		if (path == null) path = "";
		int pathLength = path.length();
		if (pathLength > 0) {
			String s2 = _fileSeparatorStandardizedPath(path);
			int j = s2.lastIndexOf('/');
			int k = pathLength - 1;
			if(j == k) {
				j = s2.lastIndexOf('/', k - 1);
				filename = (j >= 0 && j < k ? path.substring(j + 1, k) : path.substring(0, k));
			} else if(j >= 0 && j < k) {
				filename = path.substring(j + 1);
			}
			if(path.startsWith(filename) && filename.length() == 2 && Character.isLetter(filename.charAt(0)) && filename.endsWith(":") && File.separatorChar == '\\' && File.pathSeparatorChar == ';')
				filename = "";
		}
		return filename;
	}
	
	public static String stringByDeletingLastPathComponent(String s) {
		if(s != null) {
			int i = s.length();
			if(i > 0) {
				String s1 = _fileSeparatorStandardizedPath(s);
				int j = s1.lastIndexOf('/');
				byte byte0 = 0;
				int k = i - 1;
				if(Character.isLetter(s1.charAt(0)))
					if(s1.indexOf(":/") == 1 || s1.indexOf(":\\") == 1) {
						byte0 = 2;
						if(j == -1)
							j = s1.lastIndexOf('\\');
					} else
						if(s1.indexOf(":") == 1)
							j = byte0 = 1;
				if(j > -1 && j == byte0)
					return s.substring(0, byte0 + 1);
				if(j == k)
					j = s1.lastIndexOf('/', k - 1);
				if(j > -1 && j == byte0)
					return s.substring(0, byte0 + 1);
				if(j > 0)
					return s.substring(0, j);
			}
		}
		return "";
	}
	
	public static String stringByDeletingPathExtension(String s) {
		String s1 = _fileSeparatorStandardizedPath(s);
		int i = s1.length();
		int j;
		for(j = i - 1; j >= 0 && s1.charAt(j) == '/'; j--);
		if(j == -1)
			if(i == 0)
				return "";
			else
				return File.separator;
		int k = j;
		for(; j >= 0 && s1.charAt(j) != '.'; j--);
		String s2;
		if(j == -1)
			s2 = s.substring(0, k + 1);
		else
			s2 = s.substring(0, j);
		return s2;
	}
	
	public static String stringByAppendingPathComponent(String s, String s1) {
		if(s == null)
			return s1 == null ? "" : s1;
		if(s1 == null)
			return s == null ? "" : s;
		int i = s.length();
		int j = s1.length();
		if(i == 0)
			return s1;
		if(j == 0)
			return s;
		boolean flag = s.endsWith(File.separator);
		boolean flag1 = s1.startsWith(File.separator);
		if(flag && flag1) {
			StringBuffer stringbuffer = new StringBuffer((i + j) - 1);
			stringbuffer.append(s.substring(0, i - 1));
			stringbuffer.append(s1);
			return new String(stringbuffer);
		}
		if(flag || flag1) {
			StringBuffer stringbuffer1 = new StringBuffer(i + j);
			stringbuffer1.append(s);
			stringbuffer1.append(s1);
			return new String(stringbuffer1);
		} else {
			StringBuffer stringbuffer2 = new StringBuffer(i + j + 1);
			stringbuffer2.append(s);
			stringbuffer2.append(File.separator);
			stringbuffer2.append(s1);
			return new String(stringbuffer2);
		}
	}
	
	public static String stringByAppendingPathExtension(String s, String s1) {
		if(s == null)
			if(s1 != null) {
				StringBuffer stringbuffer = new StringBuffer(s1.length() + 1);
				stringbuffer.append('.');
				stringbuffer.append(s1);
				return new String(stringbuffer);
			} else {
				return "";
			}
				if(s1 == null)
					return s == null ? "" : s;
		int i = s.length();
		if(s.endsWith("/") && i > 1) {
			StringBuffer stringbuffer1 = new StringBuffer(i + s1.length());
			stringbuffer1.append(s.substring(0, i - 1));
			stringbuffer1.append('.');
			stringbuffer1.append(s1);
			return new String(stringbuffer1);
		} else {
			StringBuffer stringbuffer2 = new StringBuffer(i + s1.length() + 1);
			stringbuffer2.append(s);
			stringbuffer2.append('.');
			stringbuffer2.append(s1);
			return new String(stringbuffer2);
		}
	}
	
	public static String stringByNormalizingExistingPath(String path) {
		String nomalizedPath = "";
		if (path != null) {
			try {
				File target = new File(path);
				if (target.exists()) {
					nomalizedPath = target.getCanonicalPath();
				}
			} catch (Exception exception) {
				if (logger.isEnabledFor(org.apache.log4j.Level.ERROR)) {
					logger.error("stringByNormalizingExistingPath() Exception while getting canonical path " + path , exception);
				}
			}
		}
		return nomalizedPath;
	}
	
	/**
	 * @deprecated Method stringByStandardizingPath is deprecated
	 */
	public static String stringByStandardizingPath(String path) {
		return _stringByStandardizingPath(path);
	}
	
	public static String _stringByStandardizingPath(String s) {
		if(s == null)
			return "";
		boolean flag = File.separatorChar == '/' ? false : s.indexOf(File.separatorChar) >= 0;
		s = _standardizedPath(s);
		int i = s.length();
		if(s.startsWith("~")) {
			String s1 = homeDirectory();
			s = i != 1 ? s1 + s.substring(1) : s1;
		}
		if(s.endsWith("/") && i > 1)
			s = s.substring(0, --i);
		int j = 0;
		for(int k = s.indexOf("..", j); k >= 0;) {
			if(k == 0)
				throw new IllegalArgumentException("<NSPathUtilities> Unable to resolve path starting with ..");
			if(s.charAt(k - 1) == '/') {
				int l = s.lastIndexOf('/', k - 2);
				if(k + 2 >= i) {
					if(l < 0)
						s = "";
					else
						if(l == 0)
							s = "/";
					else
						s = s.substring(0, l);
				} else
					if(s.charAt(k + 2) == '/') {
						if(l < 0)
							s = s.substring(k + 3);
						else
							if(l == 0)
								s = s.substring(k + 2);
						else
							s = s.substring(0, l + 1) + s.substring(k + 3);
					} else {
						j = k + 2;
					}
			} else {
				j = k + 2;
			}
			k = s.indexOf("..", j);
			i = s.length();
		}
		
		if(flag)
			s = s.replace('/', File.separatorChar);
		return s;
	}
	
	/**
	 * @deprecated Method pathIsEqualToString is deprecated
	 */
	public static boolean pathIsEqualToString(String sourcePath, String destinationPath) {
		if((sourcePath == null) || (destinationPath == null) ) return false;
		if (sourcePath.equals(destinationPath)) return true;
		return (new File(sourcePath)).equals(new File(destinationPath));
	}
	
	/**
	 * @deprecated Method pathIsAbsolute is deprecated
	 */
	public static boolean pathIsAbsolute(String path) {
		return (path != null) && (new File(path)).isAbsolute();
	}
	
	/**
	 * @deprecated Method fileExistsAtPath is deprecated
	 */
	public static boolean fileExistsAtPath(String path) {
		return (path != null) && (new File(path)).exists();
	}
	
	public static boolean fileExistsAtPathURL(URL url) {
		if(url == null) return false;
		boolean result = false;
		if(_isJarProtocol(url)) {
			try {
				result = ((JarURLConnection)url.openConnection()).getJarEntry() != null;
			} catch(Exception exception) { }
		} else if(_isFileProtocol(url)) {
			try {
				result = (new File(url.getPath())).exists();
			} catch(Exception exception) { }
		}
		return result;
	}
	
	public static long _contentLengthForPathURL(URL url) {
		long contentLength = -1L;
		if(url != null) {
			if(_isJarProtocol(url)) {
				try {
					JarEntry entry = ((JarURLConnection)url.openConnection()).getJarEntry();
					if(entry != null && !entry.isDirectory())
						contentLength = entry.getSize();
				} catch(Exception exception) { }
			} else if(_isFileProtocol(url)) {
				try {
					File file = new File(url.getFile());
					if(file.exists() && !file.isDirectory())
						contentLength = file.length();
				} catch(Exception exception) { }
			}
		}
		return contentLength;
	}
	
	public static long _lastModifiedForPathURL(URL url) {
		long lastModified = 0L;
		if(url != null) {
			if(_isFileProtocol(url)) {
				File file = new File(url.getPath());
				lastModified = file.lastModified();
			}
		}
		return lastModified;
	}
	
	/**
		* @deprecated Method URLWithPath is deprecated
	 */
	
	public static URL URLWithPath(String path) {
		return _URLWithPath(path);
	}
	
	public static URL _URLWithPath(String path) {
		if (path == null) return null;
		URL url = null;
		try {
			url = new URL(_fileURLPrefix.concat(stringByNormalizingPath(path)));
		} catch(Exception exception) { 
			if (logger.isEnabledFor(org.apache.log4j.Level.ERROR)) {
				logger.error("_URLWithPath() Exception while creating URL for path " + path , exception);
			}
		}
		return url;
	}
	
	public static String stringByNormalizingPath(String path) {
		String nomalizedPath = "";
		if (path != null) {
			try {
				File target = new File(path);
				nomalizedPath = target.getCanonicalPath();
			} catch (Exception exception) {
				if (logger.isEnabledFor(org.apache.log4j.Level.ERROR)) {
					logger.error("stringByNormalizingPath() Exception while getting canonical path " + path , exception);
				}
			}
		}
		return nomalizedPath;
	}
	
	public static URL _URLWithPathURL(String path) {
		if (path == null) return null;
		URL url = null;
		try {
			url = new URL(path);
		} catch(MalformedURLException exception) {
			if (logger.isDebugEnabled()) {
				logger.debug("_isDirectoryAtPathURL() exception " , exception);
			}
		}
		if(url == null) url = _URLWithPath(path);
		return url;
	}
	
	public static URL _URLWithFile(File file) {
		URL url = null;
		if(file != null) {
			try {
				url = new URL(file.getCanonicalPath());
			} catch(Exception exception) {
				if (logger.isDebugEnabled()) {
					logger.debug("_URLWithFile() exception " , exception);
				}
			}
		}
		return url;
	}
	
	public static File _FileWithURL(URL url) {
		File file = null;
		if(_isFileProtocol(url)) {
			file = new File(url.getPath());
		}
		return file;
	}
	
	public static NSArray _directoryContentsAtPath(String path) {
		if (path == null) return NSArray.EmptyArray;
		return new NSArray((new File(path)).list());
	}
	
	public static boolean _isDirectory(String path) {
		return (path != null) && (new File(path)).isDirectory();
	}
	
	public static boolean _isDirectoryAtPathURL(URL url) {
		if(url == null) return false;
		boolean result = false;
		try {
			if (_isJarProtocol(url)) {
				String path = url.getPath();
				URLConnection aConnection = url.openConnection();
				if (aConnection instanceof JarURLConnection) {
					JarFile archive = ((JarURLConnection)aConnection).getJarFile();
					int index = path.indexOf("!/");
					if (index > 0) {
						String fileName = path.substring(index+2);
						if ( ! fileName.endsWith("/")) fileName = fileName +"/";
						result = archive.getEntry(fileName) != null;
					}
				}
			} else if (_isFileProtocol(url)) {
				result = (new File(url.getPath())).isDirectory();
			} else {
				result = url.getPath().endsWith("/");
			}
		} catch(Exception exception) {
			if (logger.isDebugEnabled()) {
				logger.debug("_isDirectoryAtPathURL() exception " , exception);
			}
		}
		return result;
	}
	
	public static void _removeFileAtPath(String path) {
		if(path == null) return;
		if (fileExistsAtPath(path)) {
			if (_isDirectory(path)) {
				for(Enumeration enumeration = _directoryContentsAtPath(path).objectEnumerator(); enumeration.hasMoreElements(); _removeFileAtPath(path + File.separator + (String)enumeration.nextElement()));
			}
			(new File(path)).delete();
		}
	}
	
	public static void _movePath(String sourcePath, String destinationPath) {
		if((sourcePath == null) || (destinationPath == null) || sourcePath.equals(destinationPath)) return;
		try {
			(new File(sourcePath)).renameTo(new File(destinationPath));
		} catch(Exception exception) {
			if (logger.isEnabledFor(org.apache.log4j.Level.ERROR)) {
				logger.error("_movePath() Exception while moving path " + sourcePath + " to path " + destinationPath , exception);
			}
		}
	}
	
	public static boolean _overwriteFileWithFile(File originalFile, File newFile) {
		File parentDirectory = originalFile.getParentFile();
		if(parentDirectory != null) {
			// First check that the directory is writtable
			File backupFile = null;
			try {
				if(originalFile.exists()) {
					backupFile = File.createTempFile("backup", "tmp", parentDirectory);
					backupFile.delete();
				}
			} catch(IOException exception) {
				if (logger.isEnabledFor(org.apache.log4j.Level.ERROR)) {
					logger.error("_overwriteFileWithFile() Failed to create backup file in directory " + parentDirectory , exception);
				}
				return false;
			}
			File targetFile = new File(originalFile.getAbsolutePath());
			// Move the original file in the temp directory
			if((backupFile != null) && (! originalFile.renameTo(backupFile))) {
				if (logger.isEnabledFor(org.apache.log4j.Level.ERROR)) {
					logger.error("_overwriteFileWithFile() Failed to rename " + originalFile + " to " + backupFile);
				}
				return false;
			}
			// Rename the file
			if(newFile.renameTo(targetFile)) {
				if(backupFile != null) backupFile.delete();
				return true;
			}
			if((backupFile != null) && (! originalFile.renameTo(targetFile)) ) {
				throw new IllegalStateException("Tried to move " + newFile + " on to " + originalFile + " but failed. Attempts at restoring the original conditions have failed. The original file is at " + backupFile);
			}
		}
		return false;
	}
	
	public static boolean _createDirectory(String path) {
		return (path != null) && (new File(path)).mkdirs();
	}
	
	public static String _currentDirectoryPath() {
		return System.getProperty("user.dir");
	}
	
	public static boolean _fileAtPathIsWritable(String path) {
		return (path != null) && (new File(path)).canWrite();
	}
	
	public static void _copyPath(String sourcePath, String destinationPath, Object obj) {
		if((sourcePath == null) || (destinationPath == null) || sourcePath.equals(destinationPath)) return;
		try {
			FileInputStream fileinputstream = new FileInputStream(sourcePath);
			FileOutputStream fileoutputstream = new FileOutputStream(destinationPath);
			byte buffer[] = new byte[fileinputstream.available()];
			for(int i = fileinputstream.read(buffer); i >= 0; i = fileinputstream.read(buffer)) {
				fileoutputstream.write(buffer, 0, i);
			}
			
		} catch(Exception exception) {
			if (logger.isEnabledFor(org.apache.log4j.Level.ERROR)) {
				logger.error("_copyPath() Exception while copying path " + sourcePath + " to path " + destinationPath , exception);
			}
		}
	}
	
	public static boolean _isFileProtocol(URL url) {
		return (url != null) && "file".equals(url.getProtocol());
	}
	
	public static boolean _isJarProtocol(URL url) {
		return (url != null) && "jar".equals(url.getProtocol());
	}
	
	static  {
		_fileURLPrefix = File.pathSeparatorChar != ';' ? "file://" : "file:///";
	}
	
}
