package org.bench4q.agent.storage;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.bench4q.share.models.agent.CleanTestResultModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class DoubleBufferStorage {
	private static final int THRESHOLD = 1024;
	private static Charset charset = Charset.forName("utf-8");
	private static int BUFFER_SIZE = 48 * 1024;
	private List<Buffer> bufferList;
	private int currentBufferIndex;
	private LocalStorage localStorage;
	public CleanTestResultModel forTest = new CleanTestResultModel();

	private int getCurrentBufferIndex() {
		return currentBufferIndex;
	}

	private void setCurrentBufferIndex(int currentBuffer) {
		this.currentBufferIndex = currentBuffer;
	}

	private List<Buffer> getBufferList() {
		return bufferList;
	}

	private void setBufferList(List<Buffer> bufferList) {
		this.bufferList = bufferList;
	}

	private LocalStorage getLocalStorage() {
		return localStorage;
	}

	@Autowired
	private void setLocalStorage(LocalStorage localStorage) {
		this.localStorage = localStorage;
	}

	public DoubleBufferStorage() {
		this.setBufferList(new ArrayList<Buffer>());
		this.getBufferList().add(Buffer.createBuffer(BUFFER_SIZE));
		this.getBufferList().add(Buffer.createBuffer(BUFFER_SIZE));
		this.setCurrentBufferIndex(0);
	}

	public String readFiles(String pathPrefix) {
		int pos = pathPrefix.lastIndexOf(System.getProperty("file.separator"));
		String dirPath = pathPrefix.substring(0, pos);
		final String prefix = pathPrefix.substring(pos + 1);
		String result = new String();

		File dirFile = new File(dirPath);
		if (!dirFile.exists()) {
			return "";
		}
		File[] files = dirFile.listFiles(new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.contains(prefix);
			}
		});
		for (File file : files) {
			if (!file.exists()) {
				continue;
			}
			result += this.getLocalStorage().readFile(file.getAbsolutePath());
		}
		return result;
	}

	public boolean writeFile(String content, String path) {
		ByteArrayInputStream inputStream = new ByteArrayInputStream(
				content.getBytes(charset));
		int size = -1;
		byte[] cache = new byte[THRESHOLD];
		while ((size = inputStream.read(cache, 0, THRESHOLD)) != -1) {
			if (isCurrentBufferFull(size)) {
				doSave(calculateSavePath(path));
				changeToTheMaxRemainBuffer();
			}
			this.getCurrentBuffer().writeToCurrentBuffer(size, cache);
		}
		return true;
	}

	private boolean isCurrentBufferFull(int size) {
		return getCurrentBuffer().getRemainSize() <= THRESHOLD + size;
	}

	public String calculateSavePath(String path, int index) {
		return path.substring(0, path.lastIndexOf(".")) + "_" + index + ".xml";
	}

	private String calculateSavePath(String path) {
		return calculateSavePath(path, this.getCurrentBufferIndex());
	}

	private void doSave(final String path) {
		final Buffer bufferUnderSave = this.getCurrentBuffer();
		final String writeContent = this.getMeaningfulContent();
		Runnable runnable = new Runnable() {
			public void run() {
				getLocalStorage().writeFile(writeContent, path);
				bufferUnderSave.reset();
				forTest.setSuccess(true);
			}
		};
		ExecutorService service = Executors.newFixedThreadPool(1);
		service.execute(runnable);
		service.shutdown();

	}

	private String getMeaningfulContent() {
		byte[] meaningfulContent = new byte[getCurrentBuffer().getCurrentPos()];
		System.arraycopy(getCurrentBuffer().getContent(), 0, meaningfulContent,
				0, getCurrentBuffer().getCurrentPos());
		return new String(meaningfulContent);
	}

	private void changeToTheMaxRemainBuffer() {
		int maxRemainSize = 2 * THRESHOLD;
		int maxRemainSizeBufferIndex = -1;
		for (int i = 0; i < this.getBufferList().size(); ++i) {
			System.out.println(i + " remain : "
					+ this.getBufferList().get(i).getRemainSize());
			if (this.getBufferList().get(i).getRemainSize() > maxRemainSize) {
				maxRemainSize = this.getBufferList().get(i).getRemainSize();
				maxRemainSizeBufferIndex = i;
			}
		}
		if (maxRemainSizeBufferIndex == -1) {
			this.getBufferList().add(Buffer.createBuffer(BUFFER_SIZE));
			maxRemainSizeBufferIndex = this.getBufferList().size() - 1;
		}
		this.setCurrentBufferIndex(maxRemainSizeBufferIndex);
	}

	private Buffer getCurrentBuffer() {
		return this.getBufferList().get(this.getCurrentBufferIndex());
	}

	public void flush() {

	}
}
