/*!
 * Copyright 2016 The ANTLR Project. All rights reserved.
 * Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information.
 */

// ConvertTo-TS run at 2016-10-04T11:26:45.0833752-07:00

export class Utils {
	static join(iter: Iterable<any>, separator: string): string {
		return join(iter.iterator(), separator);
	}

	static join<T>(array: T[], separator: string): string {
		return join(Arrays.asList(array), separator);
	}

    // Seriously: why isn't this built in to java? ugh!
    static join<T>(iter: Iterator<T>, separator: string): string {
        let buf: StringBuilder =  new StringBuilder();
        while ( iter.hasNext() ) {
            buf.append(iter.next());
            if ( iter.hasNext() ) {
                buf.append(separator);
            }
        }
        return buf.toString();
    }

	static equals(x: any, y: any): boolean {
		if (x == y) {
			return true;
		}

		if (x == null || y == null) {
			return false;
		}

		return x.equals(y);
	}

	static numNonnull(data: any[]): number {
		let n: number =  0;
		if ( data == null ) return n;
		for (let o of data) {
			if ( o!=null ) n++;
		}
		return n;
	}

	static removeAllElements<T>(data: Collection<T>, value: T): void {
		if ( data==null ) return;
		while ( data.contains(value) ) data.remove(value);
	}

	static escapeWhitespace(s: string, escapeSpaces: boolean): string {
		let buf: StringBuilder =  new StringBuilder();
		for (let c of s.toCharArray()) {
			if ( c==' ' && escapeSpaces ) buf.append('\u00B7');
			else if ( c=='\t' ) buf.append("\\t");
			else if ( c=='\n' ) buf.append("\\n");
			else if ( c=='\r' ) buf.append("\\r");
			else buf.append(c);
		}
		return buf.toString();
	}

	static writeFile(@NotNull fileName: string, @NotNull content: string): void {
		writeFile(fileName, content, null);
	}

	static writeFile(@NotNull fileName: string, @NotNull content: string, @Nullable encoding: string): void {
		let f: File =  new File(fileName);
		let fos: FileOutputStream =  new FileOutputStream(f);
		let osw: OutputStreamWriter; 
		if (encoding != null) {
			osw = new OutputStreamWriter(fos, encoding);
		}
		else {
			osw = new OutputStreamWriter(fos);
		}

		try {
			osw.write(content);
		}
		finally {
			osw.close();
		}
	}

	@NotNull
	static readFile(@NotNull fileName: string): char[] {
		return readFile(fileName, null);
	}

	@NotNull
	static readFile(@NotNull fileName: string, @Nullable encoding: string): char[] {
		let f: File =  new File(fileName);
		let size: number =  (int)f.length();
		let isr: InputStreamReader; 
		let fis: FileInputStream =  new FileInputStream(fileName);
		if ( encoding!=null ) {
			isr = new InputStreamReader(fis, encoding);
		}
		else {
			isr = new InputStreamReader(fis);
		}
		let data: char[] =  null;
		try {
			data = new char[size];
			let n: number =  isr.read(data);
			if (n < data.length) {
				data = Arrays.copyOf(data, n);
			}
		}
		finally {
			isr.close();
		}
		return data;
	}

	static removeAll<T>(@NotNull predicate: List<T> list,@NotNull Predicate<? super T>): void {
		let j: number =  0;
		for (let i = 0; i < list.size; i++) {
			let item: T =  list.get(i);
			if (!predicate.eval(item)) {
				if (j != i) {
					list.set(j, item);
				}

				j++;
			}
		}

		if (j < list.size) {
			list.subList(j, list.size).clear();
		}
	}

	static removeAll<T>(@NotNull predicate: Iterable<T> iterable,@NotNull Predicate<? super T>): void {
		if (iterable instanceof List<?>) {
			removeAll((List<T>)iterable, predicate);
			return;
		}

		for (Iterator<T> iterator = iterable.iterator(); iterator.hasNext(); ) {
			let item: T =  iterator.next();
			if (predicate.eval(item)) {
				iterator.remove();
			}
		}
	}

	/** Convert array of strings to string&rarr;index map. Useful for
	 *  converting rulenames to name&rarr;ruleindex map.
	 */
	static toMap(keys: string[]): Map<string, number> {
		let m: Map<string, number> =  new HashMap<String, Integer>();
		for (let i=0; i<keys.length; i++) {
			m.put(keys[i], i);
		}
		return m;
	}

	static toCharArray(data: IntegerList): char[] {
		if ( data==null ) return null;
		let cdata: char[] =  new char[data.size];
		for (let i=0; i<data.size; i++) {
			cdata[i] = (char)data.get(i);
		}
		return cdata;
	}

	/**
	 * @since 4.5
	 */
	@NotNull
	static toSet(@NotNull bits: BitSet): IntervalSet {
		let s: IntervalSet =  new IntervalSet();
		let i: number =  bits.nextSetBit(0);
		while ( i >= 0 ) {
			s.add(i);
			i = bits.nextSetBit(i+1);
		}
		return s;
	}
}
