#include "hashimpl.hpp"
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <stdexcept>

std::string md5(const std::string & input)
{
    unsigned char digest[MD5_DIGEST_LENGTH] = {0};
    MD5(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), digest);
    
    return std::string(reinterpret_cast<char*>(digest), MD5_DIGEST_LENGTH);
}


std::string sha256(const std::string& input)
{
    unsigned char digest[SHA256_DIGEST_LENGTH] = {0};
    SHA256(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), digest);
    return std::string(reinterpret_cast<char*>(digest), SHA256_DIGEST_LENGTH);
}


enum{
    BUFFER_SIZE = 8192
};

std::string md5withfile(const std::string & file_path)
{
    FILE *file = fopen(file_path.c_str(), "rb");

    if (file == NULL) {
        throw std::runtime_error("Error opening file.");
    }

    int bytes = 0;
    MD5_CTX context;
    MD5_Init(&context);

    unsigned char buffer[BUFFER_SIZE] = {0};
    while ((bytes = fread(buffer, 1, BUFFER_SIZE, file)) != 0) {
        MD5_Update(&context, buffer, bytes);
    }
    
    unsigned char digest[MD5_DIGEST_LENGTH] = {0};
    MD5_Final(digest, &context);

    fclose(file);
    return std::string(reinterpret_cast<char*>(digest), MD5_DIGEST_LENGTH);
}


std::string sha256withfile(const std::string& file_path)
{
    FILE *file = fopen(file_path.c_str(), "rb");
    if (file == NULL) {
        throw std::runtime_error("Error opening file.");
    }

    SHA256_CTX context;
    SHA256_Init(&context);
    int bytes = 0 ;
    unsigned char buffer[BUFFER_SIZE] = {0};
    while ((bytes = fread(buffer, 1, BUFFER_SIZE, file)) != 0) {
        SHA256_Update(&context, buffer, bytes);
    }

    unsigned char digest[SHA256_DIGEST_LENGTH]= {0};
    SHA256_Final(digest, &context);
    fclose(file);

    return std::string(reinterpret_cast<char*>(digest), SHA256_DIGEST_LENGTH);
}

