package tk.fusselrulezz.ets2editor.format.sii;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.zip.InflaterInputStream;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class SIIDecrypter {
	
	private static final byte[] HEADER_ENCRYPTED = "ScsC".getBytes(Charset.forName("UTF-8"));
	private static final byte[] HEADER_DECRYPTED = "SiiNunit".getBytes(Charset.forName("UTF-8"));
	
	private static final byte[] AES_KEY = new byte[] {
		(byte) 0x2a, (byte) 0x5f, (byte) 0xcb, (byte) 0x17,
		(byte) 0x91, (byte) 0xd2, (byte) 0x2f, (byte) 0xb6,
		(byte) 0x02, (byte) 0x45, (byte) 0xb3, (byte) 0xd8,
		(byte) 0x36, (byte) 0x9e, (byte) 0xd0, (byte) 0xb2,
		(byte) 0xc2, (byte) 0x73, (byte) 0x71, (byte) 0x56,
		(byte) 0x3f, (byte) 0xbf, (byte) 0x1f, (byte) 0x3c,
		(byte) 0x9e, (byte) 0xdf, (byte) 0x6b, (byte) 0x11,
		(byte) 0x82, (byte) 0x5a, (byte) 0x5d, (byte) 0x0a,
	};
	
	private SIIDecrypter() {}
	
	private static boolean isHeader(byte[] bytes, byte[] header) {
		if(bytes.length >= header.length) {
			byte[] compare = new byte[header.length];
			System.arraycopy(bytes, 0, compare, 0, compare.length);
			
			for(int i = 0; i < header.length; i++) {
				if(header[i] != compare[i]) {
					return false;
				}
			}
			
			return true;
		} else {
			return false;
		}
	}
	
	public static boolean isEncrypted(byte[] bytes) {
		return isHeader(bytes, HEADER_ENCRYPTED);
	}
	
	public static boolean isDecrypted(byte[] bytes) {
		return isHeader(bytes, HEADER_DECRYPTED);
	}
	
	public static boolean isValid(byte[] bytes) {
		return (isEncrypted(bytes) || isDecrypted(bytes));
	}
	
	private static byte[] decrypt(byte[] bytes, byte[] key, byte[] iv) {
		try {
			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
			SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
			cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
			return cipher.doFinal(bytes);
		} catch(Exception e) {
			return null;
		}
	}
	
	public static byte[] decrypt(byte[] bytes) {
		byte[] cipher = new byte[bytes.length - 0x38];
		byte[] iv = new byte[0x10];
		
		System.arraycopy(bytes, 0x38, cipher, 0, cipher.length);
		System.arraycopy(bytes, 0x24, iv, 0, iv.length);
		
		return decrypt(cipher, AES_KEY, iv);
	}
	
	public static byte[] decompress(byte[] bytes) {
		try {
			ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
			InflaterInputStream iis = new InflaterInputStream(bis);
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			
			int read = 0;
			byte[] buffer = new byte[1024 * 8];
			
			while((read = iis.read(buffer, 0, buffer.length)) != -1) {
				bos.write(buffer, 0, read);
			}
			
			bos.flush();
			
			return bos.toByteArray();
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}
