package com.capgemini.framework.common;

import com.capgemini.reports.exceptions.FileLoadingException;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

/** Helper clas which can load resource files in various forms. */
@Slf4j
public final class ResourceHelper {

    /**
     * 4 double-dots: starting at src / main / resources / com / capgemini/ framework / common.<br>
     * After that, the Resource Loader will be at the root of src/main/resources
     */
    private static final String PATH_TO_SRC_MAIN_RESOURCES = "../../../..";

    /** Private constructor to make the class "static". */
    private ResourceHelper() {

    }

    /**
     * Returns a URL to a resource in src/main/resources/*ABSOLUTEPATH*.
     * 
     * @param absolutePath the path with the src/main/resources
     * @return the {@link URL}
     * @throws FileLoadingException if the file could not be loaded
     */
    private static URL getResourceAsURL(final String absolutePath) throws FileLoadingException {
        URL resource = ResourceHelper.class.getResource(PATH_TO_SRC_MAIN_RESOURCES + absolutePath);
        if (resource == null) {
            throw new FileLoadingException("Could not find file at  : " + absolutePath);
        }
        return resource;
    }

    /**
     * Returns the {@link InputStream} for a resource in src/main/resources/*ABSOLUTEPATH*.
     * 
     * @param absolutePath the path with the src/main/resources
     * @return the {@link InputStream}
     * @throws FileLoadingException if the file could not be loaded
     */
    public static InputStream getResourceAsStream(final String absolutePath) throws FileLoadingException {
        InputStream resourceAsStream = ResourceHelper.class.getResourceAsStream(PATH_TO_SRC_MAIN_RESOURCES + absolutePath);
        if (resourceAsStream == null) {
            throw new FileLoadingException("Could not load InputStream : " + absolutePath);
        }
        return resourceAsStream;
    }

    /**
     * Returns a {@link URI} to a resource in src/main/resources/*ABSOLUTEPATH*.
     * 
     * @param absolutePath the path with the src/main/resources
     * @return the {@link URI}
     * @throws FileLoadingException thrown when the file could not be read.
     */
    private static URI getResourceAsURI(final String absolutePath) throws FileLoadingException {
        try {
            return getResourceAsURL(absolutePath).toURI();
        } catch (URISyntaxException e) {
            throw new FileLoadingException("Could not load URI " + absolutePath, e);
        }
    }

    /**
     * Returns a {@link File} linking to a resource in src/main/resources/*ABSOLUTEPATH*.
     * 
     * @param absolutePath the path with the src/main/resources
     * @return the {@link File}
     * @throws FileLoadingException thrown when the file could not be read.
     */
    public static File getResourceAsFile(final String absolutePath) throws FileLoadingException {
        return new File(getResourceAsURI(absolutePath));

    }

    /**
     * Returns a String with the full content of a resource in src/main/resources/*ABSOLUTEPATH*.
     * 
     * @param absolutePath the path with the src/main/resources
     * @return the content
     * @throws FileLoadingException if the file could not be loaded
     */
    public static String getResourceContent(final String absolutePath) throws FileLoadingException {
        try (InputStream stream = getResourceAsStream(absolutePath); InputStreamReader reader = new InputStreamReader(stream)) {
            return FileHelper.read(reader);
        } catch (IOException e) {
            throw new FileLoadingException("Something happened while trying to close a reader to " + absolutePath, e);
        }
    }

    /**
     * Returns an image ({@link BufferedImage}) located in resource in src/main/resources/*IMAGEPATH*.
     * 
     * @param imagePath the path with the src/main/resources
     * @return the content
     * @throws FileLoadingException if the file could not be loaded
     */
    public static BufferedImage loadImage(final String imagePath) throws FileLoadingException {
        try (InputStream imageStream = ResourceHelper.getResourceAsStream(imagePath)) {
            return readImage(imageStream);
        } catch (IOException e) {
            throw new FileLoadingException("Could not close an image resource properly", e);
        }
    }

    /**
     * Reads the content of a Stream, expecting an image and generating a {@link BufferedImage}.<br>
     * This does NOT close the inputStream, it is the responsibility of the caller to perform the close.
     * 
     * @param imageStream
     * @return the {@link BufferedImage}
     * @throws FileLoadingException if the stream could not be read as an image
     */
    private static BufferedImage readImage(final InputStream imageStream) throws FileLoadingException {
        try {
            return ImageIO.read(imageStream);
        } catch (IOException e) {
            throw new FileLoadingException("Unable to read InputStream into an image", e);
        }
    }

}
