package com.syntevo.codesnippets;

import java.io.*;
import java.net.*;

/**
 * @author Marc Strapetz
 */
public class UsingSmartSVNServerMode {

	// Static =================================================================

	public static void main(String[] args) throws IOException {
		if (args.length != 1) {
			System.out.println("Please specify the SVN working copy to scan.");
			System.exit(-1);
		}

		final File workingCopy = new File(args[0]);
		final File settingsDir = getSettingsDir();
		if (settingsDir == null) {
			System.err.println("SmartSVN's settings directory couldn't be evaluated.");
			System.exit(-1);
		}

		final int port = findPort(settingsDir);
		final File modifiedFile = findModifiedFile(workingCopy, port);
		if (modifiedFile == null) {
			System.err.println("No modified file found in " + workingCopy + ".");
			System.exit(-1);
		}

		openFileCompare(modifiedFile, port);
	}

	// Utils ==================================================================

	private static File getSettingsDir() {
		if (System.getProperty("os.name").startsWith("Windows")) {
			final String appData = System.getenv("APPDATA");
			if (appData != null) {
				final File appDataFile = new File(appData);
				if (appDataFile.isAbsolute() && appDataFile.isDirectory()) {
					return new File(appDataFile, "syntevo/SmartSVN");
				}
			}
		}
		else if (System.getProperty("mrj.version", null) != null) {
			return new File(System.getProperty("user.home"), "Library/Preferences/SmartSVN");
		}

		return new File(System.getProperty("user.home"), ".smartsvn");
	}

	private static int findPort(File settingsDir) throws IOException {
		boolean running = false;
		for (File file : settingsDir.listFiles()) {
			if (file.getName().endsWith(".port.lock") && !file.delete()) {
				running = true;
				break;
			}
		}

		if (!running) {
			System.err.println("SmartSVN seems to be not running.");
			System.exit(-1);
		}

		for (File file : settingsDir.listFiles()) {
			if (!file.getName().endsWith(".port")) {
				continue;
			}

			final BufferedReader reader = new BufferedReader(new FileReader(file));
			try {
				final String port = reader.readLine();
				if (port == null) {
					break;
				}

				return Integer.parseInt(port);
			}
			finally {
				reader.close();
			}
		}

		System.err.println("Port file not found or bad.");
		System.exit(-1);
		return -1;
	}

	private static File findModifiedFile(File workingCopy, int port) throws IOException {
		final Socket socket = new Socket("127.0.0.1", port);
		try {
			final PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
			writer.println("get-states");
			for (File file : workingCopy.listFiles()) {
				if (file.isFile()) {
					writer.println(file.getAbsolutePath().replace("\\", "\\\\"));
				}
			}
			writer.println("");
			writer.flush();

			final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			for (String line = reader.readLine(); line != null && line.length() > 0; line = reader.readLine()) {
				final int index = line.indexOf("\t");
				if (index == -1) {
					continue;
				}

				final String file = line.substring(0, index).replace("\\\\", "\\");
				final String state = line.substring(index + 1);
				if (state.equals("modified")) {
					return new File(file);
				}
			}
		}
		finally {
			socket.close();
		}

		return null;
	}

	private static void openFileCompare(File file, int port) throws IOException {
		final Socket socket = new Socket("127.0.0.1", port);
		try {
			final PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
			writer.println("compare");
			writer.println(file.getAbsolutePath().replace("\\", "\\\\"));
			writer.println("");
			writer.flush();
		}
		finally {
			socket.close();
		}
	}
}
