package com.limegroup.gnutella.uploader;

import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.limegroup.gnutella.http.ConstantHTTPHeaderValue;
import com.limegroup.gnutella.http.HTTPHeaderName;
import com.limegroup.gnutella.http.HTTPUtils;
import com.limegroup.gnutella.settings.UploadSettings;
import com.limegroup.gnutella.tigertree.HashTree;
import com.limegroup.gnutella.util.BandwidthThrottle;
import com.limegroup.gnutella.util.ThrottledOutputStream;

/**
 * Sends the THEX tree as an HTTP message.
 *
 * The tree is in compliance with the THEX protocol at
 * http://open-content.net/specs/draft-jchapweske-thex-02.html
 * 
 * @author Gregorio Roper
 */
public class THEXUploadState extends UploadState {
    private final HashTree TREE;
    private final StalledUploadWatchdog WATCHDOG;

    private static final Log LOG = LogFactory.getLog(THEXUploadState.class);
    
    /**
     * Throttle for the speed of THEX uploads, allow up to 0.5K/s
     */
    private static final BandwidthThrottle THROTTLE =
        new BandwidthThrottle(UploadSettings.THEX_UPLOAD_SPEED.getValue());

    /**
     * Constructs a new TigerTreeUploadState
     * 
     * @param uploader
     *            the <tt>HTTPUploader</tt> that sends this message
     */
    public THEXUploadState(HTTPUploader uploader, StalledUploadWatchdog dog) {
    	super(uploader);
    	LOG.debug("creating thex upload state");

        TREE = FILE_DESC.getHashTree();
        if(TREE == null)
            throw new NullPointerException("null TREE in THEXUploadState");
        WATCHDOG = dog;
    }

    /**
     * Write HTTP headers
     * 
     * @param os
     *            the <tt>OutputStream</tt> to write to.
     * @throws IOException
     *             if there was a problem writing to the <tt>OutputStream</tt>.
     */
    public void writeMessageHeaders(OutputStream network) throws IOException {
    	LOG.debug("writing thex headers");
        StringWriter os = new StringWriter();
        
        os.write("HTTP/1.1 200 OK\r\n");

        HTTPUtils.writeHeader(
            HTTPHeaderName.SERVER,
            ConstantHTTPHeaderValue.SERVER_VALUE,
            os);

        // write the URN in case the caller wants it
        HTTPUtils.writeHeader(
            HTTPHeaderName.GNUTELLA_CONTENT_URN,
            FILE_DESC.getSHA1Urn(),
            os);

        HTTPUtils.writeHeader(
            HTTPHeaderName.CONTENT_LENGTH,
            TREE.getOutputLength(),
            os);
            
        HTTPUtils.writeHeader(
            HTTPHeaderName.CONTENT_TYPE,
            TREE.getOutputType(),
            os);
        
        os.write("\r\n");
        
        WATCHDOG.activate(network);
        try {
            network.write(os.toString().getBytes());
        } finally {
            WATCHDOG.deactivate();
        }
    }

    /**
     * Write HTTP message body
     * 
     * @param os
     *            the <tt>OutputStream</tt> to write to.
     * @throws IOException
     *             if there was a problem writing to the <tt>OutputStream</tt>.
     */
    public void writeMessageBody(OutputStream os) throws IOException {
    	LOG.debug("writing message body");
        THROTTLE.setRate(UploadSettings.THEX_UPLOAD_SPEED.getValue());
        OutputStream slowStream = new ThrottledOutputStream(os, THROTTLE);
        // the tree might be large, but the watchdogs allows two minutes,
        // so this is okay, since if an entire tree wasn't written in two
        // minutes, there is a problem.
        WATCHDOG.activate(os);
        try {
            TREE.write(slowStream);
        } finally {
            WATCHDOG.deactivate();
        }
    }

    /**
     * @return <tt>true</tt> if the connection should be closed after writing
     *         the message.
     */
    public boolean getCloseConnection() {
        return false;
    }
}
