<commit_before>package textapp.server

import MessageCoding.{encode, decode}
import ccf.transport.{ClientId, ChannelId}
import com.sun.net.httpserver.{HttpHandler, HttpExchange}
import java.net.URI
import java.util.UUID
import scala.collection.mutable.{ArrayBuffer, Map}
import scala.util.matching.Regex

class TextAppRequestHandler extends HttpHandler {
  import net.liftweb.json.JsonAST
  import net.liftweb.json.JsonAST._
  import net.liftweb.json.JsonDSL._
  
  private val page404 = 
    <html>
      <head><title>404 - Page not found</title></head>
      <body>
        <h1>404 - Page not found</h1>
      </body>
    </html>

  private val page500 = 
    <html>
      <head><title>500 - Internal server error</title></head>
      <body>
        <h1>500 - Internal server error</h1>
      </body>
    </html>

  private val documentHandler = new DocumentHandler
  private val defaultChannel = ChannelId.randomId

  def handle(exchange: HttpExchange) {
    try {
      val uri = exchange.getRequestURI
      println("Serving '%s' using %s %s".format(uri, exchange.getProtocol, exchange.getRequestMethod))

      val params = new FormDecoder(exchange.getRequestBody).params
      findResource(uri, params) match {
        case Some(resource) => {
          exchange.sendResponseHeaders(200, resource.length)
          exchange.getResponseBody.write(resource.getBytes)
        }
        case None => {
          exchange.sendResponseHeaders(404, 0)
          exchange.getResponseBody.write(page404.toString.getBytes)
        }
      }
    } catch {
      case e => 
        println("=== Exception while handling request ===")
        e.printStackTrace
        exchange.sendResponseHeaders(500, 0)
        exchange.getResponseBody.write(page500.toString.getBytes)
    } finally {
      exchange.getResponseBody.close
    }
  }

  private def findResource(uri: URI, params: scala.collection.immutable.Map[String, String]): Option[String] = {
    val JoinExpr = new Regex("""/textapp/join""")
    val QuitExpr = new Regex("""/textapp/quit""")
    val AddExpr = new Regex("""/textapp/msg/add""")
    val GetExpr = new Regex("""/textapp/msg/get""")
        
    val id = ClientId(java.util.UUID.fromString(params("id")))

    val json: JsonAST.JValue = uri.toString match {
      case JoinExpr() =>
        val document = documentHandler.onJoin(id, defaultChannel)
        ("status" -> "ok") ~
        ("document" -> document.text)
      case QuitExpr() =>
        documentHandler.onQuit(id, defaultChannel)
        ("status" -> "ok")
      case AddExpr() => 
        val encodedMsg = params("msg")
        val msg = decode(encodedMsg)
        documentHandler.onMsg(id, defaultChannel, msg)
        ("status" -> "ok")
      case GetExpr() => 
        val (msgs, document) = documentHandler.getMessages(id)
        val encodedMsgs = msgs.map(encode(_))
        ("status" -> "ok") ~
        ("msgs" -> encodedMsgs) ~<commit_msg>app: Move static json imports closer to actual usage<commit_after>package textapp.server

import MessageCoding.{encode, decode}
import ccf.transport.{ClientId, ChannelId}
import com.sun.net.httpserver.{HttpHandler, HttpExchange}
import java.net.URI
import java.util.UUID
import scala.collection.mutable.{ArrayBuffer, Map}
import scala.util.matching.Regex

class TextAppRequestHandler extends HttpHandler {
  private val page404 = 
    <html>
      <head><title>404 - Page not found</title></head>
      <body>
        <h1>404 - Page not found</h1>
      </body>
    </html>

  private val page500 = 
    <html>
      <head><title>500 - Internal server error</title></head>
      <body>
        <h1>500 - Internal server error</h1>
      </body>
    </html>

  private val documentHandler = new DocumentHandler
  private val defaultChannel = ChannelId.randomId

  def handle(exchange: HttpExchange) {
    try {
      val uri = exchange.getRequestURI
      println("Serving '%s' using %s %s".format(uri, exchange.getProtocol, exchange.getRequestMethod))

      val params = new FormDecoder(exchange.getRequestBody).params
      findResource(uri, params) match {
        case Some(resource) => {
          exchange.sendResponseHeaders(200, resource.length)
          exchange.getResponseBody.write(resource.getBytes)
        }
        case None => {
          exchange.sendResponseHeaders(404, 0)
          exchange.getResponseBody.write(page404.toString.getBytes)
        }
      }
    } catch {
      case e => 
        println("=== Exception while handling request ===")
        e.printStackTrace
        exchange.sendResponseHeaders(500, 0)
        exchange.getResponseBody.write(page500.toString.getBytes)
    } finally {
      exchange.getResponseBody.close
    }
  }

  private def findResource(uri: URI, params: scala.collection.immutable.Map[String, String]): Option[String] = {
    val JoinExpr = new Regex("""/textapp/join""")
    val QuitExpr = new Regex("""/textapp/quit""")
    val AddExpr = new Regex("""/textapp/msg/add""")
    val GetExpr = new Regex("""/textapp/msg/get""")
        
    val id = ClientId(java.util.UUID.fromString(params("id")))
  
    import net.liftweb.json.JsonAST
    import net.liftweb.json.JsonDSL._

    val json: JsonAST.JValue = uri.toString match {
      case JoinExpr() =>
        val document = documentHandler.onJoin(id, defaultChannel)
        ("status" -> "ok") ~
        ("document" -> document.text)
      case QuitExpr() =>
        documentHandler.onQuit(id, defaultChannel)
        ("status" -> "ok")
      case AddExpr() => 
        val encodedMsg = params("msg")
        val msg = decode(encodedMsg)
        documentHandler.onMsg(id, defaultChannel, msg)
        ("status" -> "ok")
      case GetExpr() => 
        val (msgs, document) = documentHandler.getMessages(id)
        val encodedMsgs = msgs.map(encode(_))
        ("status" -> "ok") ~
        ("msgs" -> encodedMsgs) ~
{'fraction_non_alphanumeric': 0.12792485055508113, 'fraction_numerical': 0.013321947053800172, 'mean_word_length': 2.800129785853342, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2402500', 'n_tokens_mistral': 1822, 'n_tokens_neox': 1738, 'n_words': 382}