package net.nandgr.cba.decompile;

import com.strobel.decompiler.PlainTextOutput;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import net.nandgr.cba.cli.CliHelper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ZipEntryDecompiler implements Decompiler {

  private static final Logger logger = LoggerFactory.getLogger(ZipEntryDecompiler.class);
  private static final String CLASS_SUFFIX = ".class";
  private static final String DECOMPILED_DIR = "decompiled/";

  @Override
  public String decompile(InputStream inputStream, String entryName) throws IOException {
    logger.debug("Decompiling... {}", entryName);
    File tempFile = createTempFile(entryName, inputStream);
    tempFile.deleteOnExit();

    String decompiledFileName = getDecompiledFileName(entryName);
    File decompiledFile = new File(decompiledFileName);
    decompiledFile.getParentFile().mkdirs();

    StringWriter pw = new StringWriter();
    try {
      com.strobel.decompiler.Decompiler.decompile(tempFile.getAbsolutePath(), new PlainTextOutput(pw));
    } catch (Exception e) {
      logger.info("Error while decompiling {}. " , entryName);
      throw e;
    }
    pw.flush();

    String decompiledFileContent = pw.toString();
    FileUtils.writeStringToFile(decompiledFile, decompiledFileContent);
    return decompiledFileContent;
  }

  private static File createTempFile(String entryName, InputStream inputStream) throws IOException {
    byte[] inputStreamBytes = IOUtils.toByteArray(inputStream);
    InputStream byteArrayInputStream = new ByteArrayInputStream(inputStreamBytes);

    String prefix = entryName.replaceAll(File.separator, ".");
    final File tempFile = File.createTempFile(prefix, ".class");
    FileOutputStream outputStream = new FileOutputStream(tempFile);
    int copiedBytes = IOUtils.copy(byteArrayInputStream, outputStream);
    logger.debug("Copied {} bytes to a temp file.", copiedBytes);
    return tempFile;
  }

  private static String getDecompiledFileName(String entryName) {
    String outputDir = CliHelper.getOutputDir();
    if (!outputDir.endsWith(File.separator)) {
      outputDir += File.separator;
    }
    outputDir += DECOMPILED_DIR;
    String zipEntryName = entryName;
    if (zipEntryName.endsWith(CLASS_SUFFIX)) {
      zipEntryName = zipEntryName.substring(0, zipEntryName.length() - CLASS_SUFFIX.length());
    }
    return outputDir + zipEntryName + ".java";
  }
}