package com.rbmhtechnology.eventuate.chaos

import java.net.InetSocketAddress

import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.ActorRef
import akka.io.IO
import akka.io.Tcp
import akka.util.ByteString

abstract class ChaosInterface extends Actor with ActorLogging {
  val port = 8080
  val endpoint = new InetSocketAddress(port)
  val command = """(?s)(\w+)\s+(\d+).*""".r

  implicit val ec = context.dispatcher

  IO(Tcp)(context.system) ! Tcp.Bind(self, endpoint)

  println(s"Now listening on port $port")

  def handleCommand: PartialFunction[(String, Option[Int], ActorRef), Unit]

  protected def reply(message: String, receiver: ActorRef) = {
    receiver ! Tcp.Write(ByteString(message))
    receiver ! Tcp.Close
  }

  protected def closeOnError(receiver: ActorRef): PartialFunction[Throwable, Unit] = {
    case err: Throwable =>
      receiver ! Tcp.Close
  }

  def receive: Receive = {
    case Tcp.Connected(remote, _) =>
      sender ! Tcp.Register(self)

    case Tcp.Received(bs) =>
      val content = bs.utf8String

      content match {
        case command(c, value) if handleCommand.isDefinedAt(c, Some(value.toInt), sender) =>
          handleCommand(c, Some(value.toInt), sender)
        case c if c.startsWith("quit") =>
          context.system.terminate()
        case c if handleCommand.isDefinedAt(c, None, sender) =>
          handleCommand(c, None, sender)
        case _ =>
          sender ! Tcp.Close
      }

    case Tcp.Closed =>
    case Tcp.PeerClosed =>
  }
}