//
//  ========================================================================
//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.http;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.jetty.http.MimeTypes.Type;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.resource.Resource;

/**
 * HttpContent created from a {@link Resource}.
 * <p>The HttpContent is used to server static content that is not
 * cached. So fields and values are only generated as need be an not
 * kept for reuse</p>
 */
public class ResourceHttpContent implements HttpContent
{
    final Resource _resource;
    final String _contentType;
    final int _maxBuffer;
    Map<CompressedContentFormat, HttpContent> _precompressedContents;
    String _etag;

    public ResourceHttpContent(final Resource resource, final String contentType)
    {
        this(resource, contentType, -1, null);
    }

    public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer)
    {
        this(resource, contentType, maxBuffer, null);
    }

    public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer, Map<CompressedContentFormat, HttpContent> precompressedContents)
    {
        _resource = resource;
        _contentType = contentType;
        _maxBuffer = maxBuffer;
        if (precompressedContents == null)
        {
            _precompressedContents = null;
        }
        else
        {
            _precompressedContents = new HashMap<>(precompressedContents.size());
            for (Map.Entry<CompressedContentFormat, HttpContent> entry : precompressedContents.entrySet())
            {
                _precompressedContents.put(entry.getKey(), new PrecompressedHttpContent(this, entry.getValue(), entry.getKey()));
            }
        }
    }

    @Override
    public String getContentTypeValue()
    {
        return _contentType;
    }

    @Override
    public HttpField getContentType()
    {
        return _contentType == null ? null : new HttpField(HttpHeader.CONTENT_TYPE, _contentType);
    }

    @Override
    public HttpField getContentEncoding()
    {
        return null;
    }

    @Override
    public String getContentEncodingValue()
    {
        return null;
    }

    @Override
    public String getCharacterEncoding()
    {
        return _contentType == null ? null : MimeTypes.getCharsetFromContentType(_contentType);
    }

    @Override
    public Type getMimeType()
    {
        return _contentType == null ? null : MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType));
    }

    @Override
    public HttpField getLastModified()
    {
        long lm = _resource.lastModified();
        return lm >= 0 ? new HttpField(HttpHeader.LAST_MODIFIED, DateGenerator.formatDate(lm)) : null;
    }

    @Override
    public String getLastModifiedValue()
    {
        long lm = _resource.lastModified();
        return lm >= 0 ? DateGenerator.formatDate(lm) : null;
    }

    @Override
    public ByteBuffer getDirectBuffer()
    {
        if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer)
            return null;
        try
        {
            return BufferUtil.toBuffer(_resource, true);
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    @Override
    public HttpField getETag()
    {
        return new HttpField(HttpHeader.ETAG, getETagValue());
    }

    @Override
    public String getETagValue()
    {
        return _resource.getWeakETag();
    }

    @Override
    public ByteBuffer getIndirectBuffer()
    {
        if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer)
            return null;
        try
        {
            return BufferUtil.toBuffer(_resource, false);
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    @Override
    public HttpField getContentLength()
    {
        long l = _resource.length();
        return l == -1 ? null : new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH, l);
    }

    @Override
    public long getContentLengthValue()
    {
        return _resource.length();
    }

    @Override
    public InputStream getInputStream() throws IOException
    {
        return _resource.getInputStream();
    }

    @Override
    public ReadableByteChannel getReadableByteChannel() throws IOException
    {
        return _resource.getReadableByteChannel();
    }

    @Override
    public Resource getResource()
    {
        return _resource;
    }

    @Override
    public void release()
    {
        _resource.close();
    }

    @Override
    public String toString()
    {
        return String.format("%s@%x{r=%s,ct=%s,c=%b}", this.getClass().getSimpleName(), hashCode(), _resource, _contentType, _precompressedContents != null);
    }

    @Override
    public Map<CompressedContentFormat, HttpContent> getPrecompressedContents()
    {
        return _precompressedContents;
    }
}
