/*
 * Created on 2004/11/05
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.jware.util.crypt;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;


/**
 * @author jrmt
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class EncryptUtils implements Serializable{

    private static final int iterations = 10;
    private static final String cipherName = "PBEWithMD5AndDES";
    private static final byte salt[] = { -86, -69, -52, -35, 34, 68, -85, 18 };

    private static String password = "$$$jWare common utilities - 2004 $$$";

    private static Cipher dcipher = null;
    private static Cipher ecipher = null;

    
    public EncryptUtils() {

        super();
        try
        {
            dcipher = computePBECipher(2);
            ecipher = computePBECipher(1);
        }
        catch(Exception e) { ; }
        
    }

    public EncryptUtils( String passwd ) {

        super();

        password = passwd;

        try
        {
            dcipher = computePBECipher(2);
            ecipher = computePBECipher(1);
        }
        catch(Exception e) { ; }
        
    }

    private Cipher computePBECipher(int mode) throws Exception
	{
	    PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, iterations);
	    PBEKeySpec pbeKeySpec = new PBEKeySpec( password.toCharArray() );
	    SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
	    javax.crypto.SecretKey key = keyFac.generateSecret(pbeKeySpec);
	    Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
	    cipher.init(mode, key, pbeParamSpec);
	    return cipher;
	}
	
    private byte[] EncryptDecrypt(byte sb[], Cipher cipher)
    {
        ByteArrayOutputStream baos = null;
        try
        {
            baos = new ByteArrayOutputStream();
            CipherOutputStream cos = new CipherOutputStream(baos, cipher);
            cos.write(sb, 0, sb.length);
            cos.flush();
            cos.flush();
            cos.close();
        }
        catch(Exception ex)
        {
            System.err.println("Encrypt Error!");
            return null;
        }
        return baos.toByteArray();
    }

    public byte[] encrypt(byte b[])
    {
        return EncryptDecrypt(b, ecipher);
    }

    public byte[] decrypt(byte b[])
    {
        return EncryptDecrypt(b, dcipher);
    }
    
    public boolean encryptFile(String fn)
    {
        String bak = fn + ".bak";
        renameto(fn, bak);
        File fl = new File(bak);
        byte bytedat[] = new byte[(int)fl.length()];
        try
        {
            FileInputStream fis = new FileInputStream(fl);
            int size = fis.read(bytedat);
            fis.close();
            byte bb[] = encrypt(bytedat);
            FileOutputStream fos = new FileOutputStream(fn);
            fos.write(bb);
            fos.flush();
            fos.flush();
            fos.close();
        }
        catch(IOException e)
        {
            return false;
        }
        fl = new File(bak);
        fl.delete();
        return true;
    }
    
    public boolean decryptFile(String fn)
    {
        String bak = fn + ".bak";
        renameto(fn, bak);
        File fl = new File(bak);
        byte bytedat[] = new byte[(int)fl.length()];
        try
        {
            FileInputStream fis = new FileInputStream(fl);
            int size = fis.read(bytedat);
            fis.close();
            byte bb[] = decrypt(bytedat);
            FileOutputStream fos = new FileOutputStream(fn);
            fos.write(bb);
            fos.flush();
            fos.flush();
            fos.close();
        }
        catch(IOException e)
        {
            e.printStackTrace();
            return false;
        }
        fl = new File(bak);
        fl.delete();
        return true;
    }

    public String getRandomFileName(String basepath)
    {
        String base = basepath + "temp";
        File f = new File(base);
        if(!f.exists())
            f.mkdirs();
        long l;
        for(l = System.currentTimeMillis(); l == System.currentTimeMillis(););
        l = System.currentTimeMillis();
        return base + File.separator + l;
    }

    private static void renameto(String src, String dest)
    {
        File sf = new File(src);
        File df = new File(dest);
        sf.renameTo(df);
    }

    public static String changePathSeparator(String path)
    {
        String sep = File.separator;
        path = path.replaceAll("\\", sep);
        path = path.replaceAll("/", sep);
        return path;
    }


    public static byte[] compress(byte whatToCompress[])
        throws IOException
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ZipOutputStream gzos = new ZipOutputStream(baos);
        gzos.setMethod(8);
        gzos.putNextEntry(new ZipEntry(whatToCompress.length + ""));
        gzos.write(whatToCompress);
        gzos.closeEntry();
        gzos.finish();
        gzos.close();
        return baos.toByteArray();
    }

    public static byte[] uncompress(byte whatToUncompress[])
        throws IOException
    {
        ByteArrayInputStream bais = new ByteArrayInputStream(whatToUncompress);
        ZipInputStream gzis = new ZipInputStream(bais);
        ZipEntry zipentry = gzis.getNextEntry();
        int len = Integer.parseInt(zipentry.getName());
        ByteArrayOutputStream baos = new ByteArrayOutputStream(len);
        byte buf[] = new byte[512];
        int bread;
        while((bread = gzis.read(buf)) != -1) 
            baos.write(buf, 0, bread);
        gzis.closeEntry();
        gzis.close();
        return baos.toByteArray();
    }

    public String compressFiles(String basepath, ArrayList objs)
    {
        String fn = getRandomFileName(basepath);
        boolean bret = Zip.ZipFile(fn, objs);
        
        
        
        if(!bret)
            return null;
        else
            return fn;
    }

    
    /**
     * @return Returns the password.
     */
    public static String getPassword() {
        return password;
    }
    /**
     * @param password The password to set.
     */
    public static void setPassword(String password) {
        EncryptUtils.password = password;
    }
    
    
}
