package org.netbeans.lib.cvsclient.file;

/**
 * @author Thomas Singer
 */
public final class FilePermissions {

	// Static =================================================================

	public static final FilePermissions DEFAULT_READABLE = new FilePermissions(false, false,
	                                                                           true, false, false,
	                                                                           true, false, false);
	public static final FilePermissions DEFAULT_WRITABLE = new FilePermissions(true, false,
	                                                                           true, false, false,
	                                                                           true, false, false);
	private static final char USER = 'u';
	private static final char GROUP = 'g';
	private static final char OTHER = 'o';
	private static final char READ = 'r';
	private static final char WRITE = 'w';
	private static final char EXECUTE = 'x';

	// u=rw,g=rw,o=rw
	public static FilePermissions parseCvsString(String mode) {
		boolean userWritable = false;
		boolean userExecutable = false;
		boolean groupReadable = false;
		boolean groupWritable = false;
		boolean groupExecutable = false;
		boolean worldReadable = false;
		boolean worldWritable = false;
		boolean worldExecutable = false;

		if (mode == null) {
			mode = "";
		}

		char group = ' ';
		for (int i = 0; i < mode.length(); i++) {
			final char chr = mode.charAt(i);
			if (chr == USER || chr == GROUP || chr == OTHER) {
				group = chr;
				continue;
			}

			if (chr == ',') {
				group = ' ';
				continue;
			}

			if (chr == READ) {
				if (group == USER) {
					// ignored
				}
				else if (group == GROUP) {
					groupReadable = true;
				}
				else if (group == OTHER) {
					worldReadable = true;
				}
				continue;
			}

			if (chr == WRITE) {
				if (group == USER) {
					userWritable = true;
				}
				else if (group == GROUP) {
					groupWritable = true;
				}
				else if (group == OTHER) {
					worldWritable = true;
				}
				continue;
			}

			if (chr == EXECUTE) {
				if (group == USER) {
					userExecutable = true;
				}
				else if (group == GROUP) {
					groupExecutable = true;
				}
				else if (group == OTHER) {
					worldExecutable = true;
				}
			}
		}
		return new FilePermissions(userWritable, userExecutable,
		                           groupReadable, groupWritable, groupExecutable,
		                           worldReadable, worldWritable, worldExecutable);
	}

	public static FilePermissions parseBitRepresentation(String bitReprentation) {
		if (bitReprentation.length() < 10) {
			return DEFAULT_WRITABLE;
		}

		final boolean userWritable = bitReprentation.charAt(2) == WRITE;
		final boolean userExecutable = bitReprentation.charAt(3) == EXECUTE;
		final boolean groupReadable = bitReprentation.charAt(4) == READ;
		final boolean groupWritable = bitReprentation.charAt(5) == WRITE;
		final boolean groupExecutable = bitReprentation.charAt(6) == EXECUTE;
		final boolean otherReadable = bitReprentation.charAt(7) == READ;
		final boolean otherWritable = bitReprentation.charAt(8) == WRITE;
		final boolean otherExecutable = bitReprentation.charAt(9) == EXECUTE;
		return new FilePermissions(userWritable, userExecutable,
		                           groupReadable, groupWritable, groupExecutable,
		                           otherReadable, otherWritable, otherExecutable);
	}

	// Fields =================================================================

	private final boolean userWritable;
	private final boolean userExecutable;
	private final boolean groupReadable;
	private final boolean groupWritable;
	private final boolean groupExecutable;
	private final boolean worldReadable;
	private final boolean worldWritable;
	private final boolean worldExecutable;

	// Setup ==================================================================

	private FilePermissions(boolean userWritable, boolean userExecutable,
	                        boolean groupReadable, boolean groupWritable, boolean groupExecutable,
	                        boolean worldReadable, boolean worldWritable, boolean worldExecutable) {
		this.userWritable = userWritable;
		this.userExecutable = userExecutable;
		this.groupReadable = groupReadable;
		this.groupWritable = groupWritable;
		this.groupExecutable = groupExecutable;
		this.worldReadable = worldReadable;
		this.worldWritable = worldWritable;
		this.worldExecutable = worldExecutable;
	}

	// Accessing ==============================================================

	public boolean isUserWritable() {
		return userWritable;
	}

	public String toUnixString() {
		final StringBuilder buffer = new StringBuilder();
		buffer.append(USER);
		buffer.append("=");
		chmod(true, userWritable, userExecutable, buffer);
		buffer.append(",");
		buffer.append(GROUP);
		buffer.append("=");
		chmod(groupReadable, groupWritable, groupExecutable, buffer);
		buffer.append(",");
		buffer.append(OTHER);
		buffer.append("=");
		chmod(worldReadable, worldWritable, worldExecutable, buffer);
		return buffer.toString();
	}

	// Utils ==================================================================

	private void chmod(boolean readable, boolean writable, boolean executable, StringBuilder buffer) {
		if (readable) {
			buffer.append(READ);
		}
		if (writable) {
			buffer.append(WRITE);
		}
		if (executable) {
			buffer.append(EXECUTE);
		}
	}
}
