package info.knacki.pass.git;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;

import info.knacki.pass.git.entities.GitObject;
import info.knacki.pass.git.entities.GitPackable;
import info.knacki.pass.git.entities.GitPackableUtil;

public class GitSha1 {
    private final static Logger log = Logger.getLogger(GitSha1.class.getName());

    public static byte[] StringToBytes(String hash) {
        byte[] result = new byte[20];
        int j =0;

        for (int i =0; i +1 < hash.length(); i += 2)
            result[j++] = (byte) Integer.parseInt(hash.substring(i, i+2), 16);
        return result;
    }

    public static String BytesToString(byte[] sha1Bytes) {
        return BytesToString(sha1Bytes, 0);
    }

    public static String BytesToString(byte[] sha1Bytes, int offset) {
        StringBuilder sb = new StringBuilder();
        for (int i =offset; i < Math.min(sha1Bytes.length -offset, offset +20); ++i)
            sb.append(Integer.toString((sha1Bytes[i] & 0xff) + 0x100, 16).substring(1));
        return sb.toString();
    }

    public static byte[] getRawSha1OfFile(final File f)
    {
        return getRawSha1OfPackable(new GitPackable() {
            @Override
            public eType GetPackableType() {
                return eType.eType_Blob;
            }

            @Override
            public byte[] GetPack() {
                try {
                    return GitObject.GitBlob.GetFilePack(f);
                }
                catch (FileNotFoundException e) {
                    return null;
                }
                catch (IOException e) {
                    log.log(Level.SEVERE, "Cannot compute sha1 sum for file " +f.getAbsolutePath() +": " +e.getMessage(), e);
                    return null;
                }
            }
        });
    }

    public static byte[] getRawSha1OfPackable(GitPackable obj) {
        try {
            MessageDigest sha1Builder = MessageDigest.getInstance("SHA1");
            byte[] packContent = obj.GetPack();
            if (packContent == null) {
                return new byte[]{};
            }
            sha1Builder.update((GitPackableUtil.GetObjTypeString(obj.GetPackableType()) +" " +packContent.length).getBytes());
            sha1Builder.update(new byte[] { 0 });
            sha1Builder.update(packContent);
            return sha1Builder.digest();
        }
        catch (NoSuchAlgorithmException e) {
            return new byte[]{};
        }
    }

    public static String getSha1OfPackable(GitPackable obj) {
        byte[] raw = getRawSha1OfPackable(obj);
        return raw.length == 0 ? "" : BytesToString(raw);
    }

    public static byte[] GetRawSha1OfData(GitPackable.eType type, byte[] data) {
        try {
            MessageDigest sha1Builder = MessageDigest.getInstance("SHA1");
            sha1Builder.update((GitPackableUtil.GetObjTypeString(type) +" " +data.length).getBytes());
            sha1Builder.update(new byte[] { 0 });
            sha1Builder.update(data);
            return sha1Builder.digest();
        }
        catch (NoSuchAlgorithmException e) {
            return new byte[]{};
        }
    }

    public static String GetSha1OfData(GitPackable.eType type, byte[] data) {
        byte[] raw = GetRawSha1OfData(type, data);
        return raw.length == 0 ? "" : BytesToString(raw);
    }

    public static boolean CompareChecksum(byte[] a, byte[] b) {
        return CompareChecksum(a, b, 0);
    }

    public static boolean CompareChecksum(byte[] checksum, byte[] data, int offset) {
        for (int i=0; i < checksum.length; ++i)
            if (data[offset +i] != checksum[i])
                return false;
        return true;
    }
}
