//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
using System;
using System.Net;
using System.Text;
using System.IO;
using System.Threading;

public class AsyncResponseData
{
	public AsyncResponseData (WebRequest webRequest)
	{
		this.webRequest = webRequest;
		this.responseDone = new ManualResetEvent(false);
	}
	public WebRequest Request
	{
		get
		{
			return webRequest;
		}
	}
	public ManualResetEvent ResponseEvent
	{
		get
		{
			return responseDone;
		}
	}
	private WebRequest webRequest;
	private ManualResetEvent responseDone;
}
public class AsyncReadData
{
	public AsyncReadData (Stream stream)
	{
		this.stream = stream;
		bytesRead = -1;
		readDone = new ManualResetEvent(false);
		page = new StringBuilder();
	}
	public Stream GetStream
	{
		get
		{
			return stream;
		}
	}
	public byte [] Buffer
	{
		get
		{
			return buffer;
		}
		set
		{
			buffer = value;
		}
	}
	public int ReadCount
	{
		get
		{
			return bytesRead;
		}
		set
		{
			bytesRead = value;
		}
	}
	public StringBuilder Page
	{
		get
		{
			return page;
		}
		set
		{
			page = value;
		}
	}
	public ManualResetEvent ReadEvent
	{
		get
		{
			return readDone;
		}
	}
	private Stream stream;
	private byte[] buffer = new byte[4096];
	private int bytesRead = 0;
	private StringBuilder page;
	private ManualResetEvent readDone;
}

public class WebAsynch
{
	public static void Main(string[] args) 
	{
		try
		{
			string address = "http://localhost/QuickStart/HowTo/";
			if(args.Length == 1)
				address = args[0];

			WebRequest request = WebRequest.Create(address);

			AsyncResponseData ad = new AsyncResponseData (request);
			IAsyncResult responseResult = request.BeginGetResponse(new AsyncCallback(ResponseCallback),
																   ad);
			ad.ResponseEvent.WaitOne();
		}
		catch(Exception ex)
		{
			Console.WriteLine(ex.ToString());
		}		
	}
	private static void ResponseCallback(IAsyncResult result)
	{
		AsyncResponseData ar = (AsyncResponseData)result.AsyncState;
		WebRequest request = ar.Request;
		WebResponse response = request.EndGetResponse(result);
		Stream stream = response.GetResponseStream();
		AsyncReadData ad = new AsyncReadData(stream);
		IAsyncResult readResult = stream.BeginRead(ad.Buffer,
			                                       0,
			                                       ad.Buffer.Length,
			                                       new AsyncCallback(ReadCallback),
			                                       ad);
		ad.ReadEvent.WaitOne();
		ar.ResponseEvent.Set();
	}
	private static void ReadCallback(IAsyncResult result)
	{
		AsyncReadData ad = (AsyncReadData)result.AsyncState;
		Stream stream = ad.GetStream;
		int bytesRead = stream.EndRead(result);
		if(bytesRead == 0)
		{
			// Koniec odczytu.
			Console.WriteLine(ad.Page.ToString());
			ad.ReadEvent.Set();
		}
		else
		{
			ad.Page.Append(Encoding.ASCII.GetString(ad.Buffer, 0, bytesRead));
			IAsyncResult readResult = stream.BeginRead(ad.Buffer,
				                                       0,
				                                       ad.Buffer.Length,
				                                       new AsyncCallback(ReadCallback),
				                                       ad);
		}
	}
}
