package ur.a.skid;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Scanner;

import javax.swing.JOptionPane;

import SevenZip.Compression.LZMA.Decoder;

public class Main {
	public static Path dir;
	public static Path oDir;
	public static Scanner in;
	public static WatchService watch;
	public static WatchKey key;
	
	public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException
	{
		if (args.length==0)
		{
			JOptionPane.showMessageDialog(null, "Run with the batch file skid!", "Read the instructions!", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		oDir = Paths.get(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().toString().replaceAll("([a-zA-Z])+\\.jar", "").substring("file:/".length()));
		
		in = new Scanner(System.in);
		
		System.out.println("============================");
		System.out.println("=    GMOD Lua Decrypter    =");
		System.out.println("=       by fiireoxen       =");
		System.out.println("============================\n");
		
		String path = "C:/Program Files (x86)/Steam/SteamApps/common/GarrysMod/garrysmod/cache/lua";
		
		System.out.println("Where is your lua cache?");
		System.out.printf("Default: \"%s\"\n",path);
		System.out.print("> ");
		
		String path2 = in.nextLine();
		path = (path2.trim().equals("")) ? path : path2;
		
		path = path.replaceAll("\\\\", "/");
		dir = Paths.get(path);
		
		if (!Files.exists(oDir.resolve("d")))
		{
			Files.createDirectory(oDir.resolve("d"));
		}
		
		System.out.printf("Watching \"%s\"\n",path);
		System.out.printf("Decrypted files will be in \"%s\"\n",oDir.resolve("d").toString());
		System.out.println("Now go join a server and watch the proccess happen.");
		
		watch = dir.getFileSystem().newWatchService();
		dir.register(watch, StandardWatchEventKinds.ENTRY_CREATE);
		
		key = watch.take();
		
		while (true)
		{
			for (@SuppressWarnings("rawtypes") WatchEvent e : key.pollEvents())
			{
				String file = e.context().toString();
				if (file.endsWith(".lua"))
				{
					decrypt(file);
					Files.delete(dir.resolve(file+"_temp"));
				}
			}
			Thread.sleep(100);
		}
	}
	
	public static void decrypt(String luaFile) throws IOException, InterruptedException
	{
		byte[] bytes = removeJunk(getBytes(luaFile),4);
		
		Files.write(dir.resolve(luaFile+"_temp"), bytes);
		
		File f = new File(dir.resolve(luaFile+"_temp").toString());
		
		BufferedInputStream fin = new BufferedInputStream(new FileInputStream(f));
		BufferedOutputStream fo = new BufferedOutputStream(new FileOutputStream(new File(oDir.resolve("d/"+luaFile).toString())));
		
		Decoder d = new Decoder();
		
		byte[] props = new byte[5];
		
		if (fin.read(props, 0, 5)!=5)
		{
			System.out.println("File too short.");
			fin.close();
			fo.close();
			return;
		}
		if (!d.SetDecoderProperties(props))
		{
			System.out.println("Bad properties");
			fin.close();
			fo.close();
			return;
		}
		
		long outSize = 0;
		for (int i = 0; i < 8; i++)
		{
			int v = fin.read();
			if (v < 0)
			{
				System.out.println("Can't read size");
				fin.close();
				fo.close();
				return;
			}
			outSize |= ((long)v) << (8 * i);
		}
		
		if (!d.Code(fin, fo, outSize))
		{
			System.out.println("Nope."+outSize);
			fin.close();
			fo.close();
			return;
		}
		
		fo.flush();
		fo.close();
		fin.close();

		System.out.println("Decrypted " + luaFile);
	}
	public static byte[] removeJunk(byte[] bytes, int junk)
	{
		if (junk > 0)
		{
			byte[] newb = new byte[bytes.length - junk];
			for (int i = 0; i < newb.length; i++)
			{
				newb[i] = bytes[i+junk];
			}
			return newb;
		}
		
		return bytes;
	}
	public static byte[] getBytes(String luaFile) throws IOException
	{	
		return Files.readAllBytes(dir.resolve(luaFile));
	}
}
