/*
 * Copyright (C) 2015 SoftIndex LLC.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.datakernel.util;

import java.util.concurrent.TimeUnit;

import static io.datakernel.util.Preconditions.check;
import static java.util.concurrent.TimeUnit.*;

public final class Stopwatch {
	private boolean isRunning;
	private long start;
	private long nanos;

	private Stopwatch() {}

	public static Stopwatch createUnstarted() { return new Stopwatch(); }

	public static Stopwatch createStarted() {return new Stopwatch().start(); }

	public Stopwatch start() {
		check(!isRunning, "This stopwatch is already running.");
		isRunning = true;
		start = System.nanoTime();
		return this;
	}

	public Stopwatch stop() {
		long tick = System.nanoTime();
		check(isRunning, "This stopwatch is already stopped.");
		isRunning = false;
		nanos += tick - start;
		return this;
	}

	public Stopwatch reset() {
		isRunning = false;
		nanos = 0;
		return this;
	}

	private long time() {
		if (isRunning) {
			return System.nanoTime() - start + nanos;
		} else {
			return nanos;
		}
	}

	private long elapsedNanos() {
		return isRunning ? System.nanoTime() - start + nanos : nanos;
	}

	@Override
	public String toString() {
		long nanos = elapsedNanos();

		TimeUnit unit = chooseUnit(nanos);
		double value = (double) nanos / NANOSECONDS.convert(1, unit);

		return String.format("%.4g %s", value, abbreviate(unit));
	}

	public long elapsed(TimeUnit timeUnit) {
		return timeUnit.convert(time(), TimeUnit.NANOSECONDS);
	}

	private static TimeUnit chooseUnit(long nanos) {
		if (DAYS.convert(nanos, NANOSECONDS) > 0) {
			return DAYS;
		}
		if (HOURS.convert(nanos, NANOSECONDS) > 0) {
			return HOURS;
		}
		if (MINUTES.convert(nanos, NANOSECONDS) > 0) {
			return MINUTES;
		}
		if (SECONDS.convert(nanos, NANOSECONDS) > 0) {
			return SECONDS;
		}
		if (MILLISECONDS.convert(nanos, NANOSECONDS) > 0) {
			return MILLISECONDS;
		}
		if (MICROSECONDS.convert(nanos, NANOSECONDS) > 0) {
			return MICROSECONDS;
		}
		return NANOSECONDS;
	}

	private static String abbreviate(TimeUnit unit) {
		switch (unit) {
			case NANOSECONDS:
				return "ns";
			case MICROSECONDS:
				return "\u03bcs"; // μs
			case MILLISECONDS:
				return "ms";
			case SECONDS:
				return "s";
			case MINUTES:
				return "min";
			case HOURS:
				return "h";
			case DAYS:
				return "d";
			default:
				throw new AssertionError();
		}
	}
}

@@ -2682,23 +2682,12 @@
 rn %22
-%5Cu03bcs%22; // 
 %CE%BCs
+%22;
 %0A%09%09%09

Remove unnecessary unicode escape sequence