package nl.tudelft.watchdog.logic.interval;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import nl.tudelft.watchdog.logic.interval.intervaltypes.IntervalBase;
import nl.tudelft.watchdog.logic.network.JsonTransferer;
import nl.tudelft.watchdog.logic.network.NetworkUtils.Connection;
import nl.tudelft.watchdog.ui.UIUtils;
import nl.tudelft.watchdog.ui.preferences.Preferences;
import nl.tudelft.watchdog.util.WatchDogGlobals;
import nl.tudelft.watchdog.util.WatchDogLogger;

/**
 * This manager takes care of the repeated transferal of all closed intervals to
 * the server. When the transfer to the server was successful, the intervals are
 * immediately deleted from the local database. Furthermore, it allows the
 * immediate execution of this regularly scheduled task, e.g. when it is needed
 * on exiting.
 */
public class IntervalTransferManager {

	private static final int UPDATE_RATE = 3 * 60 * 1000;

	private Timer timer;

	private IntervalsTransferTimerTask task;

	/**
	 * Constructor. Tries to immediately transfer all remaining intervals, and
	 * sets up a scheduled timer to run every {@value #UPDATE_RATE}
	 * milliseconds.
	 */
	public IntervalTransferManager(final IntervalPersister intervalPersister) {
		task = new IntervalsTransferTimerTask(intervalPersister);
		task.run();
		timer = new Timer(true);
		timer.scheduleAtFixedRate(task, 0, UPDATE_RATE);
	}

	/** Immediately synchronizes the intervals with the server. */
	public void sendIntervalsImmediately() {
		task.run();
	}

	private static class IntervalsTransferTimerTask extends TimerTask {
		private final IntervalPersister intervalPersister;
		private Preferences preferences;

		private IntervalsTransferTimerTask(IntervalPersister intervalPersister) {
			this.intervalPersister = intervalPersister;
			this.preferences = Preferences.getInstance();
		}

		/**
		 * Transfers all intervals from the persistence storage that are not yet
		 * on the server, to the server.
		 */
		@Override
		public void run() {
			List<IntervalBase> intervalsToTransfer = new ArrayList<IntervalBase>(
					intervalPersister.readIntervals());

			if (intervalsToTransfer.isEmpty()) {
				return;
			}

			transferIntervals(intervalsToTransfer);
			resetDatabase();

			UIUtils.refreshCommand(UIUtils.COMMAND_SHOW_INFO);
		}

		private void transferIntervals(List<IntervalBase> intervalsToTransfer) {
			JsonTransferer intervalTransferer = new JsonTransferer();

			Connection connection = intervalTransferer
					.sendIntervals(intervalsToTransfer);
			switch (connection) {
			case SUCCESSFUL:
				intervalPersister.removeIntervals(intervalsToTransfer);
				preferences.setLastTransferedInterval();
				preferences.addTransferedIntervals(intervalsToTransfer.size());
				WatchDogGlobals.lastTransactionFailed = false;
				break;

			case UNSUCCESSFUL:
			case NETWORK_ERROR:
				WatchDogGlobals.lastTransactionFailed = true;
				int intervals = intervalsToTransfer.size();

				if (intervals == 1) {
					if (connection == Connection.UNSUCCESSFUL) {
						WatchDogLogger
								.getInstance()
								.logSevere(
										"Could not transfer interval and removed permanently!");
						intervalPersister.removeIntervals(intervalsToTransfer);
					}
					return;
				}

				// divide and conquer
				int halfOfIntervals = (int) Math.floor(intervals / 2);
				List<IntervalBase> firstHalfIntervals = intervalsToTransfer
						.subList(0, halfOfIntervals);
				List<IntervalBase> secondHalfIntervals = intervalsToTransfer
						.subList(halfOfIntervals, intervals);
				transferIntervals(firstHalfIntervals);
				transferIntervals(secondHalfIntervals);
				break;
			}

		}

		private void resetDatabase() {
			if (intervalPersister.getSize() <= 0) {
				intervalPersister.clearAndResetMap();
			}
		}
	}
}

@@ -2860,43 +2860,105 @@
 ase 
-UNSUCCESSFUL:%0A%09%09%09case NETWORK_ERROR
+NETWORK_ERROR:%0A%09%09%09%09WatchDogGlobals.lastTransactionFailed = true;%0A%09%09%09%09break;%0A%0A%09%09%09case UNSUCCESSFUL
 :%0A%09%09
@@ -3084,59 +3084,8 @@
 ) %7B%0A
-%09%09%09%09%09if (connection == Connection.UNSUCCESSFUL) %7B%0A%09
 %09%09%09%09
@@ -3107,17 +3107,16 @@
 %0A%09%09%09%09%09%09%09
-%09
 .getInst
@@ -3129,17 +3129,16 @@
 %0A%09%09%09%09%09%09%09
-%09
 .logSeve
@@ -3141,17 +3141,16 @@
 Severe(%0A
-%09
 %09%09%09%09%09%09%09%09
@@ -3207,17 +3207,16 @@
 tly!%22);%0A
-%09
 %09%09%09%09%09int
@@ -3272,15 +3272,8 @@
 r);%0A
-%09%09%09%09%09%7D%0A
 %09%09%09%09

Abort sending of intervals in case of Network Error.