using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Cryville.Common.Network {
	public class HttpResponse {
		static readonly char[] spchar = new char[]{ ' ' };
		public string HttpVersion { get; private set; }
		public string StatusCode { get; private set; }
		public string ReasonPhase { get; private set; }
		public Dictionary<string, string> Headers { get; private set; }
		public HttpResponseStream MessageBody { get; private set; }
		internal HttpResponse(Stream stream) {
			var reader = new BinaryReader(stream, Encoding.ASCII);
			var statu_line = ReadLine(reader).Split(spchar, 3);
			HttpVersion = statu_line[0];
			StatusCode = statu_line[1];
			ReasonPhase = statu_line[2];
			Logger.Log("main", 0, "Network", "Receive Response: {0} {1} {2}", HttpVersion, StatusCode, ReasonPhase);
			Headers = new Dictionary<string, string>();
			while (ParseHeader(reader, Headers)) ;
			if (Headers.ContainsKey("content-length")) {
				int length = int.Parse(Headers["content-length"]);
				MessageBody = new HttpResponseBlockStream(reader, length);
			}
			else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") {
				MessageBody = new HttpResponseChunkedStream(reader);
			}
		}

		public override string ToString() {
			return string.Format("<{0} {1} {2}>", HttpVersion, StatusCode, ReasonPhase);
		}

		internal static bool ParseHeader(BinaryReader reader, Dictionary<string, string> headers) {
			// TODO Multiline header
			var header = ReadLine(reader);
			if (header == "") return false;
			var s = header.Split(':');
			string field_name = s[0].Trim().ToLower();
			string field_value = s[1].Trim();
			if (headers.ContainsKey(field_name)) headers[field_name] += "," + field_value;
			else headers.Add(field_name, field_value);
			Logger.Log("main", 0, "Network", "Receive Header {0}: {1}", field_name, field_value);
			return true;
		}

		internal static string ReadLine(BinaryReader reader) {
			StringBuilder result = new StringBuilder();
			char c;
			while (true) {
				c = reader.ReadChar();
				if (c == '\r') break;
				result.Append(c);
			}
			// TODO Unseekable
			reader.ReadByte();
			return result.ToString();
		}
	}
}
