package me.chyxion.tigon.webmvc;

import java.io.File;
import org.slf4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.http.MediaType;
import org.springframework.core.io.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;

/**
 * @version 0.0.1
 * @since 0.0.1
 * @author Shaun Chyxion <br>
 * chyxion@163.com <br>
 * Jan 16, 2015 5:33:30 PM
 */
public class ResourceModel {
    private static final Logger log = 
        LoggerFactory.getLogger(ResourceModel.class);

    private String contentType;
    private long contentLength;
    private String name;
    private Resource resource;

    public ResourceModel(Resource resource, 
        String contentType, long contentLength, String name) throws IOException {
        Assert.notNull(resource);
        Assert.state(!(InputStreamResource.class == 
            resource.getClass() && contentLength <= 0), 
            "Input Stream Resource Content Length Must Provide.");
        this.resource = resource;
        this.contentType = contentType;
        this.contentLength = contentLength > 0 ? 
            contentLength : resource.contentLength();
        this.name = name;
    }

    public ResourceModel(File file, String contentType, String name) {
        this.resource = new FileSystemResource(file);
        this.contentType = contentType;
        this.contentLength = file.length();
        this.name = StringUtils.defaultIfBlank(name, file.getName());
    }
    
    public ResourceModel(InputStream inputStream, 
        String contentType, long contentLength, String name) {
        Assert.notNull(inputStream);
        Assert.state(contentLength > 0, 
            "Input Stream Resource Content Length Must Provide.");
        this.contentType = contentType;
        this.contentLength = contentLength;
        this.resource = new InputStreamResource(inputStream);
    }

    public ResourceModel(byte[] data, String contentType, String name) {
        Assert.notNull(data);
        this.resource = new ByteArrayResource(data);
        this.contentType = contentType;
        this.contentLength = data.length;
        this.name = name;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     * @return 
     */
    public ResourceModel setName(String name) {
        this.name = name;
        return this;
    }

    /**
     * @return the resource
     */
    public Resource getResource() {
        return resource;
    }

    /**
     * @param resource the resource to set
     * @return 
     */
    public ResourceModel setResource(Resource resource) {
        this.resource = resource;
        return this;
    }

    /**
     * @return the contentType
     */
    public String getContentType() {
        if (StringUtils.isBlank(contentType)) {
            log.debug("Resource Content Type Is Blank, Try To Guess From Name [{}].", name);
            // from file name
            if (StringUtils.isNotBlank(name)) {
                contentType = URLConnection.guessContentTypeFromName(name);
                log.debug("Guess Content Type [{}] From File Name [{}].", contentType, name);
            }
            // use default
            if (StringUtils.isBlank(contentType)) {
                contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
                log.debug("Use Default Content Type [{}].", contentType);
            }
        }
        return contentType;
    }

    /**
     * @param contentType the contentType to set
     * @return 
     */
    public ResourceModel setContentType(String contentType) {
        this.contentType = contentType;
        return this;
    }

    /**
     * @return the contentLength
     * @throws IOException 
     */
    public long getContentLength() throws IOException {
        return contentLength;
    }
}
