/**
 * This file is part of the Meeds project (https://meeds.io/).
 *
 * Copyright (C) 2020 - 2025 Meeds Association contact@meeds.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package org.exoplatform.resolver;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.List;


/**
 * This abstract class provide an abstract way to retrieve different resources in different contexts (war, jar....) <br>
 * For example, to retrieve resource from an portlet, we implement <br>
 * {@link org.exoplatform.resolver.PortletResourceResolver} <br>
 * <br>
 * In gatein, we have caching machanism which use {@link org.exoplatform.resolver.ResourceKey} <br>
 * as key to determine cached resource, ResourceKey is generated by ResourceResolver.createResourceKey method <br>
 * <br>
 * By default, createResourceKey method return difference ResourceKey<br>
 * if we call that method on difference ResourceResolver instances (even with the same resource url)<br>
 * <br>
 * To make our caching machanism work properly,please make sure you use the same ResourceResolver<br>
 * or override the createResourceKey method of abstract class ResourceResolver<br>
 * and return the same ResourceKey for the same resource url<br>
 * <br>
 * Created by The eXo Platform SAS Mar 15, 2006
 */
public abstract class ResourceResolver {

    /**
     * Return URL object to resource
     *
     * @param url - String path (specific to certain context) to resource
     * @throws Exception
     */
    public abstract URL getResource(String url) throws Exception;

    /**
     * Return InputStream object to resource
     *
     * @param url - String path (specific to certain context) to resource
     * @throws Exception
     */
    public abstract InputStream getInputStream(String url) throws Exception;

    /**
     * Return List of URL object to resource
     *
     * @param url - String path (specific to certain context) to resource
     * @throws Exception
     */
    public abstract List<URL> getResources(String url) throws Exception;

    /**
     * Return List of InputStream object to resource
     *
     * @param url - String path (specific to certain context) to resource
     * @throws Exception
     */
    public abstract List<InputStream> getInputStreams(String url) throws Exception;

    @SuppressWarnings("unused")
    /**
     * Return web path to resource (/context/pathToResource)
     * You should overidde this method in case of web context
     * @param url - String path (specific to certain context) to resource
     */
    public String getWebAccessPath(String url) {
        throw new RuntimeException("This method is not supported");
    }

    public abstract String getResourceScheme();

    @SuppressWarnings("unused")
    public String getRealPath(String url) {
        throw new RuntimeException("unsupported method");
    }

    /**
     * Return {@link org.exoplatform.resolver.ResourceKey} object<br>
     * <br>
     * Default implementation will return difference ResourceKey instance<br>
     * if we call that method on difference ResourceResolver instances (even with the same resource url)<br>
     * <br>
     * If you create new ResourceResolver each time you need access to a resource, please overidde this method<br>
     * and return the same ResourceKey for the same url<br>
     *
     * @param url - String path (specific to certain context) to resource
     */
    public ResourceKey createResourceKey(String url) {
        return new ResourceKey(hashCode(), url);
    }

    /**
     * Return resource id
     *
     * @param url - String path (specific to certain context) to resource
     */
    public String createResourceId(String url) {
        return hashCode() + ":" + url;
    }

    /**
     * Return if this can resolve resource with specific url
     *
     * @param url String path to resource
     */
    public boolean isResolvable(String url) {
        return url.startsWith(getResourceScheme());
    }

    /**
     * Return resource as array of bytes
     *
     * @param url - String path (specific to certain context) to resource
     * @throws Exception
     */
    public byte[] getResourceContentAsBytes(String url) throws Exception {
        InputStream is = getInputStream(url);
        BufferedInputStream buffer = new BufferedInputStream(is);
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] data = new byte[buffer.available()];
        int available = -1;
        while ((available = buffer.read(data)) > -1) {
            output.write(data, 0, available);
        }
        return output.toByteArray();
    }

    /**
     * Return if resource has been modified since specific time
     *
     * @param url- String path (specific to certain context) to resource
     * @param lastAccess
     */
    public abstract boolean isModified(String url, long lastAccess);

    protected String removeScheme(String url) {
        String scheme = getResourceScheme();
        if (url.startsWith(scheme)) {
            return url.substring(scheme.length());
        }
        return url;
    }
}
