package org.ethereum.vm;

import org.ethereum.config.SystemProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterOutputStream;

import static java.lang.String.format;
import static java.lang.System.getProperty;
import static java.util.Base64.getDecoder;
import static java.util.Base64.getEncoder;
import static org.springframework.util.StringUtils.isEmpty;

public final class VMUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger("VM");
    private static final SystemProperties CONFIG = new SystemProperties();
    
    private VMUtils() {
    }

    public static void closeQuietly(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (IOException ioe) {
            // ignore
        }
    }
    
    private static File createProgramTraceFile(String txHash) {
        File result = null;
        
        if (CONFIG.vmTrace() && !isEmpty(CONFIG.vmTraceDir())) {
            
            String pathname = format("%s/%s/%s/%s.json", getProperty("user.dir"), CONFIG.databaseDir(), CONFIG.vmTraceDir(), txHash);
            File file = new File(pathname);

            if (file.exists()) {
                if (file.isFile() && file.canWrite()) {
                    result = file;
                }
            } else {
                try {
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                    result = file;
                } catch (IOException e) {
                    // ignored
                }
            }
        }
        
        return result;
    }

    private static void writeStringToFile(File file, String data) {
        OutputStream out = null;
        try {
            out = new FileOutputStream(file);
            if (data != null) {
                out.write(data.getBytes("UTF-8"));
            }
        } catch (Exception e){
            LOGGER.error(format("Cannot write to file '%s': ", file.getAbsolutePath()), e);
        } finally {
            closeQuietly(out);
        }
    }
    
    public static void saveProgramTraceFile(String txHash, String content) {
        File file = createProgramTraceFile(txHash);
        if (file != null) {
            writeStringToFile(file, content);
        }
    }

    private static final int BUF_SIZE = 4096;

    private static void write(InputStream in, OutputStream out, int bufSize) throws IOException {
        try {
            byte[] buf = new byte[bufSize];
            for (int count = in.read(buf); count != -1; count = in.read(buf)) {
                out.write(buf, 0, count);
            }
        } finally {
            closeQuietly(in);
            closeQuietly(out);
        }
    }

    private static byte[] compress(String content) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ByteArrayInputStream in = new ByteArrayInputStream(content.getBytes("UTF-8"));
        DeflaterOutputStream out = new DeflaterOutputStream(baos, new Deflater(), BUF_SIZE);

        write(in, out, BUF_SIZE);

        return baos.toByteArray();
    }

    private static String decompress(byte[] data) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length);

        ByteArrayInputStream in = new ByteArrayInputStream(data);
        InflaterOutputStream out = new InflaterOutputStream(baos, new Inflater(), BUF_SIZE);

        write(in, out, BUF_SIZE);

        return new String(baos.toByteArray(), "UTF-8");
    }

    public static String zipAndEncode(String content) {
        try {
            return getEncoder().encodeToString(compress(content));
        } catch (Exception e) {
            LOGGER.error("Cannot zip or encode: ", e);
            return content;
        }
    }

    public static String unzipAndDecode(String content) {
        try {
            return decompress(getDecoder().decode(content));
        } catch (Exception e) {
            LOGGER.error("Cannot unzip or decode: ", e);
            return content;
        }
    }
}

@@ -386,33 +386,55 @@
  static 
-java.util
+org.apache.commons.codec.binary
 .Base64.
 getDecod
@@ -425,26 +425,28 @@
 .Base64.
-getD
+d
 ecode
-r
+Base64
 ;%0Aimport
@@ -457,25 +457,47 @@
 tic 
-java.util
+org.apache.commons.codec.binary
 .Base64.
 getE
@@ -492,26 +492,34 @@
 .Base64.
-getE
+e
 ncode
-r
+Base64String
 ;%0Aimport
@@ -750,21 +750,17 @@
 ties();%0A
-    
 %0A
+
     priv
@@ -1011,29 +1011,25 @@
     %7D%0A    %7D%0A
-    
 %0A
+
     private 
@@ -1108,25 +1108,17 @@
 = null;%0A
-        
 %0A
+
         
@@ -1178,21 +1178,9 @@
 ) %7B%0A
-            
 %0A
+
     
@@ -1786,17 +1786,9 @@
   %7D%0A
-        
 %0A
+
     
@@ -2265,13 +2265,9 @@
   %7D%0A
-    
 %0A
+
     
@@ -3816,29 +3816,20 @@
 urn 
-getE
+e
 ncode
-r().encodeTo
+Base64
 Stri
@@ -4089,27 +4089,20 @@
 ess(
-getD
+d
 ecode
-r().decode
+Base64
 (con

Fix avoiding java 8 methods