package com.prolixtech.jaminid;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;

/**
 * The response class encapsulates an HTTP response. It contains the response
 * data (headers, etc) as well as functions to publish cookies, send files, etc.
 * 
 * @author Constantinos Michael
 * 
 * 
 * 
 * TODO
 */
public class Response {

    private String statusLine;

    private Protocol protocol;

    private OutputStream out;

    private Request masterRequest;

    private boolean headerPublished;

    private Map<String, String> activeHeader = new java.util.HashMap<String, String>();

    public Response(int statusCode, Protocol protocol, OutputStream out,
            Request masterRequest) {
        this.masterRequest = masterRequest;
        this.out = out;
        this.protocol = protocol;
        String statusDescription = Protocol.getHeaderResponseStatus(statusCode);
        if (statusDescription == null)
            statusCode = Protocol.INTERNAL_SERVER_ERROR;

        statusLine = Protocol.HTTP_VERSION + " " + statusCode + " "
                + Protocol.getHeaderResponseStatus(statusCode);
    }

    /**
     * sets the status of the response to a certain HTTP status code
     * 
     * @param statusCode
     *            the code to set the status to
     */
    public void setStatus(int statusCode) {
        if (Protocol.getHeaderResponseStatus(statusCode) != null) {
            statusLine = Protocol.HTTP_VERSION + " " + statusCode + " "
                    + Protocol.getHeaderResponseStatus(statusCode);
        } else {
            throw new java.lang.IllegalArgumentException("No such status code");
        }
    }

    /**
     * sets a fifteen day cookie
     * 
     * @param name
     *            the field name
     * @param value
     *            the field value
     */
    public void sendCookie15DG(String name, String value) {

        // public void setCookie(String name, String value, String path,
        // java.util.Date expires){
        Date d15G = new Date(System.currentTimeMillis() + 15 * 24 * 60 * 60
                * 1000);
        setCookie(name, value, "/", d15G);
    }

    /**
     * sets a cookie
     * 
     * @param name
     *            the field name
     * @param value
     *            the field vaLUE
     * @param path
     *            the relevant path
     * @param expires
     *            the cookie activation day
     */
    public void setCookie(String name, String value, String path,
            java.util.Date expires) {

        // "Set-Cookie:"

        String cookieVal = name + "=" + value + "; expires="
                + Connection.getGMTString(expires) + ";path=" + path + ";"; // domain=DOMAIN_NAME;
        // secure

        this.setHeaderLine(ProtocolResponseHeader.Set_Cookie, cookieVal);
    }

    /**
     * Sends the header to the client. After this, no more headers can be set,
     * no more cookies can be send
     * 
     * @throws IOException
     */
    public void publishHeader() throws IOException {
        if (headerPublished)
            return;
        out.write(statusLine.getBytes());

        for(String x : activeHeader.keySet()){
            out.write(this.CRLF());

            out.write(x.getBytes());
            out.write(':');
            out.write(' ');
            out.write((activeHeader.get(x)).getBytes());
        }

        out.write(this.CRLF());
        out.write(this.CRLF());
        this.headerPublished = true;

    }

    /**
     * sets one particular header line
     * 
     * @param header
     * @param value
     */
    public void setHeaderLine(ProtocolResponseHeader header, String value) {

            activeHeader.put(header.toString(), value);
        
    }

    public byte[] CRLF() {
        return "\r\n".getBytes();
    }

    /**
     * sends a file to the client. Sets the MIME type accordingly
     * 
     * @param cFile
     *            the file to send
     * 
     * @throws IOException
     */
    public void sendFile(File cFile) throws Exception {
        String lastModifiedGMT = Connection.getGMTString(new Date(cFile
                .lastModified()));
        String modifiedCondition = (String) this.masterRequest.getHeader().get(
                Protocol.HQ_IFMODSINCE);

        if (lastModifiedGMT.equals(modifiedCondition)) {
            setStatus(Protocol.NOT_MODIFIED);
            setHeaderLine(ProtocolResponseHeader.Content_Length, "0");
        } else {

            String canonFile = cFile.getCanonicalPath();
            String fileExt = canonFile.substring(canonFile.lastIndexOf("."));
            String type = Protocol.getMIME(fileExt);
            setHeaderLine(ProtocolResponseHeader.Content_Type, type);

            setHeaderLine(ProtocolResponseHeader.Content_Length, "" + cFile.length());
            setHeaderLine(ProtocolResponseHeader.Last_Modified, lastModifiedGMT);

            publishHeader();

            java.io.BufferedInputStream bfin = new java.io.BufferedInputStream(
                    new java.io.FileInputStream(cFile));
            int in;
            byte[] bin = new byte[4096];
            while (true) {
                int bytesRead = bfin.read(bin);
                if (bytesRead < 0)
                    break;
                out.write(bin, 0, bytesRead);
            }

        }
    }

}