package org.squiddev.cctweaks.lua.lib;

import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IComputerAccess;
import org.squiddev.cctweaks.api.lua.IArguments;
import org.squiddev.cctweaks.api.lua.ILuaAPI;
import org.squiddev.cctweaks.api.lua.ILuaAPIFactory;
import org.squiddev.cctweaks.api.lua.ILuaObjectWithArguments;
import org.squiddev.cctweaks.lua.Config;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterOutputStream;

/**
 * Adds inflate/deflate APIs
 */
public class DataAPI implements ILuaAPI, ILuaObjectWithArguments, ILuaAPIFactory {
	@Override
	public void startup() {

	}

	@Override
	public void shutdown() {

	}

	@Override
	public void advance(double timestep) {
	}

	@Override
	public String[] getMethodNames() {
		return new String[]{"inflate", "deflate"};
	}

	@Override
	public ILuaAPI create(IComputerAccess computer) {
		return Config.APIs.Data.enabled ? this : null;
	}

	@Override
	public String[] getNames() {
		return new String[]{"data"};
	}


	public byte[] getStringBytes(Object[] args) throws LuaException {
		if (args.length == 0 || !(args[0] instanceof String)) throw new LuaException("Expected string");

		return BinaryConverter.toBytes((String) args[0]);
	}

	@Override
	public Object[] callMethod(ILuaContext context, int method, Object[] args) throws LuaException, InterruptedException {
		switch (method) {
			case 0:
				return inflate(getStringBytes(args));

			case 1:
				return deflate(getStringBytes(args));
		}

		return null;
	}

	@Override
	public Object[] callMethod(ILuaContext context, int method, IArguments args) throws LuaException, InterruptedException {
		switch (method) {
			case 0:
				return inflate(args.getStringBytes(0));

			case 1:
				return deflate(args.getStringBytes(0));
		}

		return null;
	}

	private Object[] inflate(byte[] data) throws LuaException {
		if (data.length >= Config.APIs.Data.limit) throw new LuaException("Data is too long");

		ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
		InflaterOutputStream inos = new InflaterOutputStream(baos);
		try {
			inos.write(data);
			inos.finish();
		} catch (IOException e) {
			throw LuaHelpers.rewriteException(e, "Inflating error");
		}

		return new Object[]{baos.toByteArray()};
	}

	private Object[] deflate(byte[] data) throws LuaException {
		if (data.length >= Config.APIs.Data.limit) throw new LuaException("Data is too long");

		ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
		DeflaterOutputStream inos = new DeflaterOutputStream(baos);
		try {
			inos.write(data);
			inos.finish();
		} catch (IOException e) {
			throw LuaHelpers.rewriteException(e, "Deflating error");
		}

		return new Object[]{baos.toByteArray()};
	}
}

@@ -539,28 +539,90 @@
 Deflater
-OutputStream
+;%0Aimport java.util.zip.DeflaterOutputStream;%0Aimport java.util.zip.Inflater
 ;%0Aimport
@@ -2263,32 +2263,52 @@
 utputStream(baos
+, new Inflater(true)
 );%0A%09%09try %7B%0A%09%09%09in
@@ -2754,16 +2754,66 @@
 eam(baos
+, new Deflater(Deflater.DEFAULT_COMPRESSION, true)
 );%0A%09%09try

Fix DEFLATE/INFLATE being broken