/*
 * Delivered to the U.S. Government in Accordance with Contract FA8650-10-C-7080.
 *
 * EXPORT CONTROLLED
 * ECCN#   EAR99  
 * Warning:  This document contains technical data which is controlled under the
 * Bureau of Industry & Security’s Export Administration Regulations and may not be
 * exported or re-exported without authorization by the Bureau of Industry & Security.
 * Diversion contrary to US law is prohibited.
 *
 * (c) 2011 United Technologies Corp.
 * Developed with the sponsorship of the Defense Advanced Research Projects Agency (DARPA).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this data,
 * including any software or models in source or binary form, as well as any drawings, 
 * specifications, and documentation (collectively "the Data"), to deal in the Data without 
 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Data, and to permit persons to whom the Data
 * is furnished to do so, subject to the following conditions:
 *  
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Data.
 *  
 * THE DATA IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, SPONSORS, DEVELOPERS, CONTRIBUTORS, OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DATA OR THE
 * USE OR OTHER DEALINGS IN THE DATA.
 */

package meta.repository.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;

import meta.rmi.Log;

/**
 * Platform name/PLATFORM/L0 Platform name/ARCHITECTURE/L0
 */
public class RepositoryImpl implements Repository {
	private static String ROOT;
	private static final String RESULT_PATH_FMT   = "%s%s%s%sRESULTS%sL%d";
	private static final String ARCH_PATH_FMT     = "%s%s%s%sARCHITECTURES%sL%d";
	private static final String PLATFORM_PATH_FMT = "%s%s%s%sPLATFORM%sL%d";
	private static final String MISSION_PATH_FMT  = "%s%sMISSION";
	static {
		ROOT = System.getProperty("REPOSITORY_DIR");
		Log.info(String.format("Repository: %s", ROOT)); 
	}
	
	public RepositoryImpl() {
	}

	/**
	 * Report the number of architectures. These are found by counting the
	 * number of "a.n" files in the PLATFORM/ARCHITECTURES/Llevel directory The only
	 * files in the directory are architectures.
	 */
	public int getNumberOfArchitectures(String platform, int level) {

		String dir = getPath(ARCH_PATH_FMT, platform, level);
		File d = new File(dir);
		String files[] = d.list(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				return name.startsWith("a.");
			}
		});
		if (files == null)
			return 0;
		return files.length;
	}

	/**
	 * Report the platform file for platform, and level
	 */
	public String getPlatform(String platform, int level) {
		String path = getPath(PLATFORM_PATH_FMT, platform, level);
		return readFile(path, "p.xml");
	}

	/**
	 * Report the architecture with id, platform, and level
	 */
	public String getArchitecture(int id, String platform, int level) {
		String path = getPath(ARCH_PATH_FMT, platform, level);
		String file = String.format("a.%d", id);
		return readFile(path, file);
	}

	/* (non-Javadoc)
	 * @see meta.repository.service.Repository#getResult(java.lang.String, int, java.lang.String)
	 */
	@Override
	public String getResult(String platform, int level, String id) {
		String path = getPath(RESULT_PATH_FMT, platform, level);
		String file = String.format("a.%s", id);
		return readFile(path, file);
	}

	/* (non-Javadoc)
	 * @see meta.repository.service.Repository#getMarkedArch(java.lang.String, int)
	 */
	@Override
	public String getMarkedArch(String platform, int level) {
		String path = getPath(RESULT_PATH_FMT, platform, level);
		return readFile(path, "ma.xml");
	}

	/* (non-Javadoc)
	 * @see meta.repository.service.Repository#getMission(java.lang.String)
	 */
	public String getMission(String name) {
		String path = getMissionPath();
		String file = String.format("m-%s.xml", name);
		return readFile(path, file);
	}

	/**
	 * Save a platform to the repository return true on success and false
	 * otherwise platforms are named 'p.xml' in the file system.
	 */
	public boolean savePlatform(String contents, String platform, int level) {
		String path = getPath(PLATFORM_PATH_FMT, platform, level);
		return writeFile(contents, path, "p.xml");
	}

	/**
	 * Save an architecture to the repository return true on success and false
	 * otherwise architectures are named 'a.'id in the file system.
	 */
	public boolean saveArchitecture(String contents, int id, String platform,
			int level) {
		String path = getPath(ARCH_PATH_FMT, platform, level);
		String file = String.format("a.%d", id);
		return writeFile(contents, path, file);
	}

	/* (non-Javadoc)
	 * @see meta.repository.service.Repository#saveResult(java.lang.String, java.lang.String, int, java.lang.String)
	 */
	@Override
	public boolean saveResult(String contents, String platform, int level, String id) {
		String path = getPath(RESULT_PATH_FMT, platform, level);
		String file = String.format("r.%s", id);
		return writeFile(contents, path, file);
	}

	/* (non-Javadoc)
	 * @see meta.repository.service.Repository#saveMarkedArch(java.lang.String, java.lang.String, int)
	 */
	@Override
	public boolean saveMarkedArch(String contents, String platform, int level) {
		String path = getPath(ARCH_PATH_FMT, platform, level);
		return writeFile(contents, path, "ma.xml");
	}

	/* (non-Javadoc)
	 * @see meta.repository.service.Repository#saveMission(java.lang.String, java.lang.String)
	 */
	public boolean saveMission(String contents, String name) {
		String path = getMissionPath();
		String file = String.format("m-%s.xml", name);
		return writeFile(contents, path, file);
	}

	/**
	 * Report the path where a file will be written or read
	 */
	private String getPath(String fmt, String platform, int level) {
		String dir = String.format(fmt, ROOT, File.separator, platform
				.toUpperCase(), File.separator, File.separator, level);
		return dir;
	}
	
	/**
	 * Report the path where a mission file will be written or read
	 */
	private String getMissionPath() {
		String dir = String.format(MISSION_PATH_FMT, ROOT, File.separator);
		return dir;
	}


	/**
	 * Report the contents of file in directory dir. return null if file not
	 * found or error reading file
	 */
	private String readFile(String dir, String file) {
		String contents = null;
		try {
			String filepath = getFilePath(dir, file);
			BufferedReader in = new BufferedReader(new FileReader(filepath));
			StringBuilder sb = new StringBuilder();
			while (true) {
				int c = in.read();
				if (c == -1)
					break;
				char ch = (char) c;
				sb.append(ch);
			}
			in.close();
			contents = sb.toString();
		} catch (FileNotFoundException e) {

		} catch (IOException e) {

		}
		return contents;
	}

	/**
	 * Write contents to file in directory dir. Create dir if dir does not
	 * exist. Overwrite file if file exists. Return true if written, false
	 * otherwise.
	 */
	private boolean writeFile(String contents, String dir, String file) {
		boolean written;
		try {
			File directory = new File(dir);
			directory.mkdirs(); // if directories doesn't yet exist
			String filepath = getFilePath(dir, file);
			PrintWriter out = new PrintWriter(new BufferedWriter(
					new FileWriter(filepath)));
			out.print(contents);
			out.flush();
			out.close();
			written = true;
		} catch (IOException e) {
			written = false;
		}
		return written;
	}

	/**
	 * utility to make a complete file path from a directory and file name.
	 */
	private String getFilePath(String dir, String file) {
		String filepath = String.format("%s%s%s", dir, File.separator, file);
		return filepath;
	}

	public static void main(String[] args) {
		RepositoryImpl repo = new RepositoryImpl();
		repo.getNumberOfArchitectures("engine", 0);
		repo.saveArchitecture("<b>", 1, "engine", 0);
		boolean b = repo.savePlatform("stuff", "junk", 3);
		System.out.print(b);
		String s = repo.getPlatform("junk", 3);
		System.out.println(s);
		s = repo.getArchitecture(1, "engine", 1);
		System.out.println(s);
	}

}
