text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  const buffer_util_1 = require("./buffer-util");
  class HTTPBuffer {
      constructor() {
          this._rawContent = buffer_util_1.BufferUtil.fromString("");
          this._complete = false;
      }
      static errorResponse(message) {
          const buffer = new HTTPBuffer();
          const payload = "HTTP/1.1 500 Error\r\nContent-Type: text/plain\r\n"
              + "Content-Length: " + message.length + "\r\n\r\n"
              + message;
          buffer.append(new Buffer(payload));
          return buffer;
      }
      append(data) {
          this._rawContent = Buffer.concat([this._rawContent, data]);
          if (this._headers === undefined) {
              const endIndex = buffer_util_1.BufferUtil.scan(this._rawContent, [13, 10, 13, 10]);
              if (endIndex !== -1) {
                  const headerBuffer = this._rawContent.slice(0, endIndex);
                  this.parseHeaders(headerBuffer.toString());
                  if (endIndex + 4 < this._rawContent.length) {
                      const bodyPart = this._rawContent.slice((endIndex + 4));
                      this.appendBody(bodyPart);
                  }
              }
          }
          else {
              this.appendBody(data);
          }
      }
      complete() {
          if (!this._complete) {
              if (this._headers !== undefined) {
                  const chunked = this.hasHeader("Transfer-Encoding") && this.header("Transfer-Encoding").toLowerCase() === "chunked";
                  if (chunked && this._rawBody !== undefined) {
                      const chunks = this.parseChunks();
                      if (chunks !== null && chunks.length > 0 && chunks[chunks.length - 1].lastChunk()) {
                          this._chunks = chunks;
                          this._complete = true;
                      }
                  }
                  else if (this._rawBody !== undefined) {
                      let length = this._rawBody.length;
                      if (this.hasHeader("Content-Length")) {
                          length = parseInt(this.header("Content-Length"));
                      }
                      this._complete = this._rawBody.length === length;
                  }
              }
          }
          return this._complete;
      }
      header(headerKey) {
          let value = null;
          if (this._headers !== undefined && this.hasHeader(headerKey)) {
              value = this._headers[headerKey];
          }
          return value;
      }
      hasHeader(headerKey) {
          return headerKey in this._headers;
      }
      method() {
          return this._method;
      }
      uri() {
          return this._uri;
      }
      statusCode() {
          return this._statusCode;
      }
      chunked() {
          let chunked = false;
          if (this.complete()) {
              if (this._chunks !== undefined) {
                  chunked = true;
              }
          }
          return chunked;
      }
      raw() {
          return this._rawContent;
      }
      isJSON() {
          return this.hasHeader("Content-Type") && this.header("Content-Type") === "application/json";
      }
      body() {
          let body;
          if (this.complete()) {
              body = buffer_util_1.BufferUtil.fromString("");
              if (this.chunked()) {
                  for (let chunk of this._chunks) {
                      body = Buffer.concat([body, chunk.body]);
                  }
              }
              else {
                  body = this._rawBody;
              }
          }
          return body;
      }
      bodyAsJSON() {
          let json;
          if (this.body() !== undefined) {
              json = JSON.parse(this.body().toString());
          }
          return json;
      }
      parseChunks() {
          let chunks = [];
          let body = this._rawBody;
          while (true) {
              const chunk = HTTPChunk.parse(body);
              if (chunk !== null) {
                  chunks.push(chunk);
              }
              else {
                  break;
              }
              if (chunk.lastChunk()) {
                  break;
              }
              body = body.slice(chunk.lengthWithHeaderAndTrailer());
          }
          return chunks;
      }
      appendBody(bodyPart) {
          if (this._rawBody === undefined) {
              this._rawBody = buffer_util_1.BufferUtil.fromString("");
          }
          this._rawBody = Buffer.concat([this._rawBody, bodyPart]);
      }
      parseHeaders(headersString) {
          this._headers = {};
          const lines = headersString.split("\n");
          if (lines[0].startsWith("HTTP")) {
              this._statusLine = lines[0];
              const statusLineParts = this._statusLine.split(" ");
              this._statusCode = parseInt(statusLineParts[1]);
          }
          else {
              this._requestLine = lines[0];
              const requestLineParts = this._requestLine.split(" ");
              this._method = requestLineParts[0];
              this._uri = requestLineParts[1];
          }
          for (let i = 1; i < lines.length; i++) {
              const headerLine = lines[i];
              const headerParts = headerLine.split(":");
              const key = headerParts[0];
              this._headers[key] = headerParts[1].trim();
          }
      }
  }
  exports.HTTPBuffer = HTTPBuffer;
  class HTTPChunk {
      constructor(body, lengthString) {
          this.body = body;
          this.lengthString = lengthString;
      }
      length() {
          return parseInt(this.lengthString, 16);
      }
      headerLength() {
          return (this.lengthString).length + 2;
      }
      lengthWithHeaderAndTrailer() {
          return this.length() + this.headerLength() + 2;
      }
      lastChunk() {
          return (this.length() === 0);
      }
      static parse(httpBody) {
          let chunkLengthString = HTTPChunk.parseLength(httpBody);
          if (chunkLengthString === null) {
              return null;
          }
          let chunkLength = parseInt(chunkLengthString, 16);
          let chunkStartIndex = chunkLengthString.length + 2;
          let endIndex = chunkStartIndex + chunkLength;
          if (httpBody.length < endIndex) {
              return null;
          }
          let chunkBody = httpBody.slice(chunkStartIndex, chunkStartIndex + chunkLength);
          return new HTTPChunk(chunkBody, chunkLengthString);
      }
      static parseLength(httpBody) {
          let index = buffer_util_1.BufferUtil.scan(httpBody, [13, 10]);
          if (index === -1) {
              return null;
          }
          let chunkLengthString = "";
          for (let i = 0; i < index; i++) {
              let char = String.fromCharCode(httpBody[i]);
              if (isNaN(parseInt(char, 16))) {
                  throw new RangeError("Invalid character found in chunk length - something went wrong! " + char);
              }
              chunkLengthString += String.fromCharCode(httpBody[i]);
          }
          return chunkLengthString;
      }
  }
  exports.HTTPChunk = HTTPChunk;
  //# sourceMappingURL=http-buffer.js.map