package aQute.libg.remote.sink;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.File;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import aQute.lib.io.IO;
import aQute.libg.cryptography.SHA1;
import aQute.libg.remote.Delta;
import aQute.libg.remote.Source;

public class SinkFS {
	final Map<File,String>	shas	= new ConcurrentHashMap<File,String>();
	final Map<String,File>	files	= new ConcurrentHashMap<String,File>();
	private Source[]		sources;
	private File			shacache;

	public SinkFS(Source[] sources, File shacache) {
		this.shacache = shacache;
		setSources(sources);
	}

	public void setSources(Source[] sources) {
		this.sources = sources;
	}

	public boolean delta(File cwd, Collection<Delta> deltas) {
		for (Delta delta : deltas) {
			try {
				delta(cwd, delta);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return true;
	}

	private void delta(File cwd, Delta delta) throws Exception {
		File file = new File(delta.path);
		if (file.isAbsolute())
			throw new IllegalArgumentException("Absolute paths are not allowed " + delta.path);

		file = new File(cwd, delta.path);
		if (delta.delete)
			IO.delete(file);
		else {
			if (delta.sha != null) {
				String existing = shas.get(file);
				if (existing == null || !delta.sha.equals(existing)) {
					byte[] data = getData(delta.sha);
					if (data != null) {
						copy(data, file, delta.sha);
					} else
						shas.remove(file);
				}
			} else if (delta.content != null) {
				byte[] bytes = delta.content.getBytes(UTF_8);
				String sha = SHA1.digest(bytes).asHex();
				copy(bytes, file, sha);
			}
		}
	}

	private void copy(byte[] data, File file, String sha) throws Exception {
		IO.mkdirs(file.getParentFile());
		IO.copy(data, file);
		shas.put(file, sha);
	}

	private byte[] getData(String sha) throws Exception {
		File shaf = new File(shacache, sha);
		if (shaf.isFile()) {
			return IO.read(shaf);
		}
		for (Source source : sources) {
			byte[] data = source.getData(sha);
			if (data != null) {
				File tmp = IO.createTempFile(shacache, "shacache", null);
				IO.copy(data, tmp);
				IO.rename(tmp, shaf);
				return data;
			}
		}
		return null;
	}

}
