/*
 *
 */

#include <iostream>
#include <windows.h>
#include <nsCOMPtr.h>
#include <nsCRT.h>
#include <nsIServiceManager.h>
#include <nsIChannel.h>
#include <nsIHTTPChannel.h>
#include <nsIInputStream.h>
#include <nsIEventQueueService.h>
#include <nsIURI.h>

#include "StreamListener.h"

using namespace std;


extern PRUint32 gNumDocs;
extern PRMonitor *gMonitor;


NS_IMPL_THREADSAFE_ISUPPORTS2(StreamListener, nsIStreamListener, nsIRunnable);


StreamListener::StreamListener()
{
	mComplete = PR_FALSE;
}


StreamListener::~StreamListener()
{
}


NS_IMETHODIMP
StreamListener::OnStartRequest(nsIChannel *request, nsISupports *context)
{
	return NS_OK;
}


NS_IMETHODIMP
StreamListener::OnStopRequest(nsIChannel *request, nsISupports *context,
	nsresult aStatus, const PRUnichar *aStatusArg)
{
	nsresult rv = NS_OK;

	mComplete = true;
	cout << "Status: 0x" << hex << aStatus
		<< " (" << aStatusArg << ")" << endl;

	return NS_OK;
}


NS_IMETHODIMP
StreamListener::OnDataAvailable(nsIChannel* request,
	nsISupports* context,
	nsIInputStream *pStream,
	PRUint32 aSourceOffset,
	PRUint32 aLength)
{
	nsresult rv = NS_OK;
	char *buf = new char[aLength + 1];
	PRUint32 amount = 0;

	cout << aLength << " bytes of data available" << endl;
	while ((aLength > 0) && NS_SUCCEEDED(rv)) {
		rv = pStream->Read(buf, aLength, &amount);
		if (NS_SUCCEEDED(rv)) {
			buf[amount] = '\0';
			/* cout << "Read " << amount << " bytes: " << endl << buf << endl; */
			cout << "Read " << amount << " bytes" << endl;
			aLength -= amount;
		}
	}
	delete [] buf;
	cout << endl;

	return NS_OK;
}


NS_IMETHODIMP
StreamListener::Run()
{
	nsresult rv = NS_OK;
	nsCOMPtr<nsIEventQueue> eventQueue;
	nsCOMPtr<nsIStreamListener> listener;
	PLEvent *event = nsnull;

	NS_ADDREF_THIS();
	rv = GetEventQueue(getter_AddRefs(eventQueue));
	if (NS_SUCCEEDED(rv)) {
		rv = QueryInterface(NS_GET_IID(nsIStreamListener),
			getter_AddRefs(listener));
	}
	if (NS_SUCCEEDED(rv)) {
		rv = mChannel->AsyncRead(listener, nsnull);
	}
	while ((! mComplete) && NS_SUCCEEDED(rv)) {
		rv = eventQueue->GetEvent(&event);
		if (NS_SUCCEEDED(rv)) {
			rv = eventQueue->HandleEvent(event);
		}
	}
	mChannel = nsnull;
	PR_EnterMonitor(gMonitor);
	gNumDocs--;
	cout << dec << gNumDocs << " docs remaining" << endl;
	PR_Notify(gMonitor);
	PR_ExitMonitor(gMonitor);
	NS_RELEASE_THIS();

	return(rv);
}


NS_IMETHODIMP
StreamListener::Init(nsIChannel *channel)
{
	NS_ENSURE_ARG_POINTER(channel);
	nsresult rv = NS_OK;

	mChannel = channel;

	return(rv);
}


NS_IMETHODIMP
StreamListener::GetEventQueue(nsIEventQueue **retval)
{
	nsresult rv = NS_OK;

	nsCOMPtr<nsIEventQueueService> eventQService =
		do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID);
	rv = eventQService->CreateMonitoredThreadEventQueue();
	if (NS_FAILED(rv)) {
		cerr << "Event Queue Service creation failed." << endl;
	}
	if (NS_SUCCEEDED(rv)) {
		rv = eventQService->GetMonitoredThreadEventQueue(NS_CURRENT_THREAD, retval);
		if (NS_FAILED(rv)) {
			cerr << "GetThreadEventQueue() failed." << endl;
		}
	}

	return(rv);
}
