package com.vaguehope.onosendai.storage;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import com.vaguehope.onosendai.storage.DbInterface.ColumnState;
import com.vaguehope.onosendai.storage.DbInterface.ScrollChangeType;
import com.vaguehope.onosendai.storage.DbInterface.TwUpdateListener;
import com.vaguehope.onosendai.util.LogWrapper;

public class SaveScrollNow {

	protected static final LogWrapper LOG = new LogWrapper("SSN");

	public static void requestAndWaitForUiToSaveScroll (final DbInterface db) {
		final ScrollStoreCountingListener twUpdateListener = new ScrollStoreCountingListener();
		db.addTwUpdateListener(twUpdateListener);
		try {
			final long startTime = now();
			final Set<Integer> requestedColumnIds = db.requestStoreScrollNow();
			if (requestedColumnIds.size() > 0) {
				final boolean storedSuccessfully = twUpdateListener.awaitScrollStores(requestedColumnIds, 5, TimeUnit.SECONDS);
				final long durationMillis = TimeUnit.NANOSECONDS.toMillis(now() - startTime);
				LOG.i("Request UI store %s scrolls success=%s in %d millis.", requestedColumnIds, storedSuccessfully, durationMillis);
			}
		}
		finally {
			db.removeTwUpdateListener(twUpdateListener);
		}
	}

	private static class ScrollStoreCountingListener implements TwUpdateListener {

		private final Set<Integer> storedColumnIds = Collections.synchronizedSet(new HashSet<Integer>());

		public ScrollStoreCountingListener () {}

		public boolean awaitScrollStores (final Set<Integer> waitForColumnIds, final int timeout, final TimeUnit unit) {
			final long timeoutNanos = unit.toNanos(timeout);
			final long startTime = now();
			while (true) {
				synchronized (this.storedColumnIds) {
					if (this.storedColumnIds.containsAll(waitForColumnIds)) return true;
				}
				if (now() - startTime > timeoutNanos) return false;
				try {
					Thread.sleep(100);
				}
				catch (InterruptedException e) {
					return false;
				}
			}
		}

		@Override
		public void columnChanged (final int columnId) {/* unused */}

		@Override
		public void columnStatus (final int columnId, final ColumnState state) {/* unused */}

		@Override
		public void unreadOrScrollChanged (final int columnId, final ScrollChangeType type) {/* unused */}

		@Override
		public Integer requestStoreScrollStateNow () {
			return null;
		}

		@Override
		public void scrollStored (final int columnId) {
			synchronized (this.storedColumnIds) {
				this.storedColumnIds.add(columnId);
			}
		}

	}

	private static final long NANO_ORIGIN = System.nanoTime();

	protected static long now () {
		return System.nanoTime() - NANO_ORIGIN;
	}

}