package com.madeorsk.smartnotes;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import com.madeorsk.smartnotes.notes.Note;

public class SavesManager
{
	private static final String KEY = "Vivre et grandir à travers le commun";
	private static final File SAVE_FOLDER = new File("saves");

	public SavesManager()
	{
		if (!SAVE_FOLDER.exists())
			SAVE_FOLDER.mkdirs();
	}

	public void saveIndex(Map<Integer, Note> notes)
	{
		File indexFile = new File(SAVE_FOLDER, "index");
		if (indexFile.exists())
			indexFile.delete();

		if (!notes.isEmpty())
		{
			String indexString = "";
			for (int key : notes.keySet())
				indexString += key + ":" + notes.get(key).getClass().getName() + "\n";

			indexString = indexString.substring(0, indexString.length() - 1);
			this.writeFile(indexFile, indexString);
		}
	}

	public Map<Integer, Note> loadIndex()
	{
		File indexFile = new File(SAVE_FOLDER, "index");
		if (indexFile.exists())
		{
			Map<Integer, Note> notes = new HashMap<Integer, Note>();
			String indexString = this.readFile(indexFile);
			String[] notesString = indexString.split("\n");
			for (String noteString : notesString)
			{
				String[] decomposed = noteString.split(":");
				if (decomposed.length == 2)
				{
					try
					{
						Note note = (Note) this.getClass().getClassLoader().loadClass(decomposed[1]).newInstance();
						if (note.load(this, Integer.parseInt(decomposed[0])))
							notes.put(Integer.parseInt(decomposed[0]), note);
					}
					catch (InstantiationException | IllegalAccessException | ClassNotFoundException e)
					{
						e.printStackTrace();
					}
				}
			}
			return notes;
		}
		else
			return new HashMap<Integer, Note>();
	}

	public File getSaveFile(int id)
	{
		return new File(SAVE_FOLDER, id + "");
	}
	public String readFile(File file)
	{
		try
		{
			FileInputStream fis = new FileInputStream(file);
			byte[] buffer = new byte[1024 * 8];
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			int n;
			while ((n = fis.read(buffer)) > 0)
				baos.write(buffer, 0, n);
			fis.close();

			ByteArrayOutputStream stringBaos = new ByteArrayOutputStream();
			GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(this.byteFpeDecryption(baos.toByteArray(), KEY)));
			while ((n = gzip.read(buffer)) > 0)
				stringBaos.write(buffer, 0, n);
			return new String(stringBaos.toByteArray());
		}
		catch (IOException e)
		{
			e.printStackTrace();
			file.delete();
			return null;
		}
	}
	public void writeFile(File file, String content)
	{
		try
		{
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			GZIPOutputStream gzip = new GZIPOutputStream(baos);
			gzip.write(content.getBytes(), 0, content.getBytes().length);
			gzip.close();
			byte[] bytes = baos.toByteArray();

			FileOutputStream fos = new FileOutputStream(file);
			fos.write(this.byteFpeEncryption(bytes, KEY));
			fos.flush();
			fos.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	private static String createCipherFromKey(String key, int bytesLength)
	{
		String cipher = "";
		int i = 0;
		while (cipher.getBytes().length < bytesLength)
		{
			cipher += key.getBytes()[i];
			i++;
			if (i >= key.getBytes().length)
				i = 0;
		}
		return cipher;
	}
	private byte[] byteFpeEncryption(byte[] bytes, String key)
	{
		String cipher = createCipherFromKey(key, bytes.length);

		byte[] encryptedBytes = new byte[bytes.length];
		for (int i = 0; i < bytes.length; i++)
			encryptedBytes[i] = (byte) (bytes[i] + cipher.getBytes()[i]);

		return encryptedBytes;
	}
	private byte[] byteFpeDecryption(byte[] bytes, String key)
	{
		String cipher = createCipherFromKey(key, bytes.length);

		byte[] decryptedBytes = new byte[bytes.length];
		for (int i = 0; i < bytes.length; i++)
			decryptedBytes[i] = (byte) (bytes[i] - cipher.getBytes()[i]);

		return decryptedBytes;
	}
}
