/*******************************************************************************
 * Copyright (c) 2005, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Rational Software - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;

import java.io.File;

/**
 * @author jcamelon
 */
public class ScannerUtility {
	static final char DOT    = '.';  
	static final char SLASH  = '/';
	static final char BSLASH = '\\'; 
	static final char QUOTE  = '\"'; 

	/**
	 * This method is quick 1-pass path reconciler.
	 * Functions:
	 *   - replace "/" or "\" by system's separator
	 *   - replace multiple separators by single one
	 *   - skip "/./" 
	 *   - skip quotes
	 * 
	 * Note: "/../" is left untouched on purpose in order to work properly under
	 * circumstances such as this:
	 * 
	 * header file at include_1/vector:
	 *   // Is supposed to find the STL vector header:
	 *   #include <ext/../vector>
	 *   
	 * GCC include tree 
	 *   include_gcc/ext/...
	 *              /vector
	 * 
	 * (ls include_1/ext/../vector does not work either).
	 * 
	 * @param originalPath - path to process
	 * @return             - reconciled path   
	 */
	public static String reconcilePath(String originalPath ) {
		int len = originalPath.length();
		int len1 = len - 1;         // to avoid multiple calculations
		int j = 0;                  // index for output array
		boolean noSepBefore = true; // to avoid duplicate separators
		
		char[] ein = new char[len];
		char[] aus = new char[len + 1];
		
		originalPath.getChars(0, len, ein, 0);
		
		// allow double backslash at beginning for windows UNC paths, bug 233511
		// also allow Unix UNC paths
		if (ein.length >= 2) {
			if (ein[0] == BSLASH && ein[1] == BSLASH && File.separatorChar == BSLASH) {
				aus[j++] = BSLASH;
			} else if (ein[0] == SLASH && ein[1] == SLASH && File.separatorChar == SLASH) {
				aus[j++] = SLASH;
			}
		}

		for (int i= 0; i < len; i++) {
			char c = ein[i]; 
			switch (c) {
			case QUOTE:	  // quotes are removed
				noSepBefore = true;
				break;
			case SLASH:     // both separators are processed  
			case BSLASH:    // in the same way
				if (noSepBefore) {
					noSepBefore = false;
					aus[j++] = File.separatorChar;
				}
				break;
			case DOT:
				// No separator before, not a 1st string symbol. 
				if (noSepBefore && j > 0) {
					aus[j++] = c;
				} else { // Separator before "."
					if (i < len1) {
						c = ein[i + 1]; // Check for next symbol
						// Check for "/./" case
						if (c == SLASH || c == BSLASH) {
							// Write nothing to output, skip the next symbol
							i++;
							noSepBefore = false;
						} else {  // Process as usual
							i++;
							noSepBefore = true;
							aus[j++] = DOT;
							aus[j++] = c;
						}
					}
				}
				break;
			default: 
				noSepBefore = true;
				aus[j++] = c;
			}
		}
		return new String(aus, 0, j);
	}

	/**
	 * @param path     - include path
	 * @param fileName - include file name
	 * @return         - reconciled path
	 */
	public static String createReconciledPath(String path, String fileName) {
		boolean pathEmpty = (path == null || path.length() == 0);
		return pathEmpty ? fileName : reconcilePath(path + File.separatorChar + fileName);
	}
}
