package se.unlogic.standardutils.crypto;

import se.unlogic.standardutils.operation.ProgressMeter;
import se.unlogic.standardutils.streams.StreamUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class EncryptionUtils {

   public static String hash(String string, String algorithm) throws UnsupportedEncodingException{

      return hash(string, algorithm, Charset.defaultCharset().toString());
   }

   public static String hash(String string, String algorithm, String encoding) throws UnsupportedEncodingException{

      try {
         MessageDigest digest = MessageDigest.getInstance(algorithm);

         digest.update(string.getBytes(encoding));

         byte[] encodedPassword = digest.digest();

         return new BigInteger(1, encodedPassword).toString(16);

         //TODO fix if hash starts with zeroes!

      } catch (NoSuchAlgorithmException e) {

         throw new RuntimeException(e);
      }
   }

   public static String hash(File file, String algorithm) throws IOException{

      return hash(file, algorithm, null);
   }

   public static String hash(File file, String algorithm, ProgressMeter progressMeter) throws IOException{

      FileInputStream fileInputStream = null;

      try {
         MessageDigest digest = MessageDigest.getInstance(algorithm);
         fileInputStream = new FileInputStream(file);

         DigestInputStream digestInputStream = new DigestInputStream(fileInputStream, digest);

         if(progressMeter != null){

            progressMeter.setStartTime();
            progressMeter.setFinish(file.length());
         }

         byte[] buffer = new byte[8192];

         int bytesRead = 1;

         if(progressMeter != null){

            while ((bytesRead = digestInputStream.read(buffer)) != -1){

               progressMeter.incrementCurrentPosition(bytesRead);
            }

         }else{

            while ((bytesRead = digestInputStream.read(buffer)) != -1){}
         }

         byte[] hash = digest.digest();

         if(progressMeter != null){

            progressMeter.setEndTime();
         }

         return new BigInteger(1, hash).toString(16);

      } catch (NoSuchAlgorithmException e) {

         throw new RuntimeException(e);

      }finally{

         StreamUtils.closeStream(fileInputStream);
      }
   }

   public static String mysqlPasswordHash(String string) {

      try {
         MessageDigest digest = MessageDigest.getInstance(HashAlgorithms.SHA1);

         digest.update(string.getBytes(StandardCharsets.UTF_8));

         byte[] encodedPassword = digest.digest();

         digest.update(encodedPassword);

         encodedPassword = digest.digest();

         String hash = new BigInteger(1, encodedPassword).toString(16).toUpperCase();

         while(hash.length() < 40){

            hash = "0" + hash;
         }

         return "*" + hash;

      } catch (NoSuchAlgorithmException e) {

         throw new RuntimeException(e);
      }
   }
}
