// CODYlib		-*- mode:c++ -*-
// Copyright (C) 2020 Nathan Sidwell, nathan@acm.org
// License: Apache v2.0

// Cody
#include "internal.hh"
// C
#include <cerrno>
#include <cstdlib>
#include <cstring>

// Client code

namespace Cody {

// These do not need to be members
static Packet ConnectResponse (std::vector<std::string> &words);
static Packet PathnameResponse (std::vector<std::string> &words);
static Packet OKResponse (std::vector<std::string> &words);
static Packet IncludeTranslateResponse (std::vector<std::string> &words);

// Must be consistently ordered with the RequestCode enum
static Packet (*const responseTable[Detail::RC_HWM])
  (std::vector<std::string> &) =
  {
    &ConnectResponse,
    &PathnameResponse,
    &PathnameResponse,
    &PathnameResponse,
    &OKResponse,
    &IncludeTranslateResponse,
  };

Client::Client ()
{
  fd.from = fd.to = -1;
}

Client::Client (Client &&src)
  : write (std::move (src.write)),
    read (std::move (src.read)),
    corked (std::move (src.corked)),
    is_direct (src.is_direct),
    is_connected (src.is_connected)
{
  if (is_direct)
    server = src.server;
  else
    {
      fd.from = src.fd.from;
      fd.to = src.fd.to;
    }
}

Client::~Client ()
{
}

Client &Client::operator= (Client &&src)
{
  write = std::move (src.write);
  read = std::move (src.read);
  corked = std::move (src.corked);
  is_direct = src.is_direct;
  is_connected = src.is_connected;
  if (is_direct)
    server = src.server;
  else
    {
      fd.from = src.fd.from;
      fd.to = src.fd.to;
    }

  return *this;
}

int Client::CommunicateWithServer ()
{
  write.PrepareToWrite ();
  read.PrepareToRead ();
  if (IsDirect ())
    server->DirectProcess (write, read);
  else
    {
      // Write the write buffer
      while (int e = write.Write (fd.to))
	if (e != EAGAIN && e != EINTR)
	  return e;
      // Read the read buffer
      while (int e = read.Read (fd.from))
	if (e != EAGAIN && e != EINTR)
	  return e;
    }

  return 0;
}

static Packet CommunicationError (int err)
{
  std::string e {u8"communication error:"};
  e.append (strerror (err));

  return Packet (Client::PC_ERROR, std::move (e));
}

Packet Client::ProcessResponse (std::vector<std::string> &words,
			       unsigned code, bool isLast)
{
  if (int e = read.Lex (words))
    {
      if (e == EINVAL)
	{
	  std::string msg (u8"malformed string '");
	  msg.append (words[0]);
	  msg.append (u8"'");
	  return Packet (Client::PC_ERROR, std::move (msg));
	}
      else
	return Packet (Client::PC_ERROR, u8"missing response");
    }

  Assert (!words.empty ());
  if (words[0] == u8"ERROR")
    return Packet (Client::PC_ERROR,
		  std::move (words.size () == 2 ? words[1]
			     : u8"malformed error response"));

  if (isLast && !read.IsAtEnd ())
    return Packet (Client::PC_ERROR,
		   std::string (u8"unexpected extra response"));

  Assert (code < Detail::RC_HWM);
  Packet result (responseTable[code] (words));
  result.SetRequest (code);
  if (result.GetCode () == Client::PC_ERROR && result.GetString ().empty ())
    {
      std::string msg {u8"malformed response '"};

      read.LexedLine (msg);
      msg.append (u8"'");
      result.GetString () = std::move (msg);
    }
  else if (result.GetCode () == Client::PC_CONNECT)
    is_connected = true;

  return result;
}

Packet Client::MaybeRequest (unsigned code)
{
  if (IsCorked ())
    {
      corked.push_back (code);
      return Packet (PC_CORKED);
    }

  if (int err = CommunicateWithServer ())
    return CommunicationError (err);

  std::vector<std::string> words;
  return ProcessResponse(words, code, true);
}

void Client::Cork ()
{
  if (corked.empty ())
    corked.push_back (-1);
}

std::vector<Packet> Client::Uncork ()
{
  std::vector<Packet> result;

  if (corked.size () > 1)
    {
      if (int err = CommunicateWithServer ())
	result.emplace_back (CommunicationError (err));
      else
	{
	  std::vector<std::string> words;
	  for (auto iter = corked.begin () + 1; iter != corked.end ();)
	    {
	      char code = *iter;
	      ++iter;
	      result.emplace_back (ProcessResponse (words, code,
						    iter == corked.end ()));
	    }
	}
    }

  corked.clear ();

  return result;
}

// Now the individual message handlers

// HELLO $vernum $agent $ident
Packet Client::Connect (char const *agent, char const *ident,
			  size_t alen, size_t ilen)
{
  write.BeginLine ();
  write.AppendWord (u8"HELLO");
  write.AppendInteger (Version);
  write.AppendWord (agent, true, alen);
  write.AppendWord (ident, true, ilen);
  write.EndLine ();

  return MaybeRequest (Detail::RC_CONNECT);
}

// HELLO $version $agent [$flags]
Packet ConnectResponse (std::vector<std::string> &words)
{
  if (words[0] == u8"HELLO" && (words.size () == 3 || words.size () == 4))
    {
      char *eptr;
      unsigned long val = strtoul (words[1].c_str (), &eptr, 10);

      unsigned version = unsigned (val);
      if (*eptr || version != val || version < Version)
	return Packet (Client::PC_ERROR, u8"incompatible version");
      else
	{
	  unsigned flags = 0;
	  if (words.size () == 4)
	    {
	      val = strtoul (words[3].c_str (), &eptr, 10);
	      flags = unsigned (val);
	    }
	  return Packet (Client::PC_CONNECT, flags);
	}
    }

  return Packet (Client::PC_ERROR, u8"");
}

// MODULE-REPO
Packet Client::ModuleRepo ()
{
  write.BeginLine ();
  write.AppendWord (u8"MODULE-REPO");
  write.EndLine ();

  return MaybeRequest (Detail::RC_MODULE_REPO);
}

// PATHNAME $dir | ERROR
Packet PathnameResponse (std::vector<std::string> &words)
{
  if (words[0] == u8"PATHNAME" && words.size () == 2)
    return Packet (Client::PC_PATHNAME, std::move (words[1]));

  return Packet (Client::PC_ERROR, u8"");
}

// OK or ERROR
Packet OKResponse (std::vector<std::string> &words)
{
  if (words[0] == u8"OK")
    return Packet (Client::PC_OK);
  else
    return Packet (Client::PC_ERROR,
		   words.size () == 2 ? std::move (words[1]) : "");
}

// MODULE-EXPORT $modulename [$flags]
Packet Client::ModuleExport (char const *module, Flags flags, size_t mlen)
{
  write.BeginLine ();
  write.AppendWord (u8"MODULE-EXPORT");
  write.AppendWord (module, true, mlen);
  if (flags != Flags::None)
    write.AppendInteger (unsigned (flags));
  write.EndLine ();

  return MaybeRequest (Detail::RC_MODULE_EXPORT);
}

// MODULE-IMPORT $modulename [$flags]
Packet Client::ModuleImport (char const *module, Flags flags, size_t mlen)
{
  write.BeginLine ();
  write.AppendWord (u8"MODULE-IMPORT");
  write.AppendWord (module, true, mlen);
  if (flags != Flags::None)
    write.AppendInteger (unsigned (flags));
  write.EndLine ();

  return MaybeRequest (Detail::RC_MODULE_IMPORT);
}

// MODULE-COMPILED $modulename [$flags]
Packet Client::ModuleCompiled (char const *module, Flags flags, size_t mlen)
{
  write.BeginLine ();
  write.AppendWord (u8"MODULE-COMPILED");
  write.AppendWord (module, true, mlen);
  if (flags != Flags::None)
    write.AppendInteger (unsigned (flags));
  write.EndLine ();

  return MaybeRequest (Detail::RC_MODULE_COMPILED);
}

// INCLUDE-TRANSLATE $includename [$flags]
Packet Client::IncludeTranslate (char const *include, Flags flags, size_t ilen)
{
  write.BeginLine ();
  write.AppendWord (u8"INCLUDE-TRANSLATE");
  write.AppendWord (include, true, ilen);
  if (flags != Flags::None)
    write.AppendInteger (unsigned (flags));
  write.EndLine ();

  return MaybeRequest (Detail::RC_INCLUDE_TRANSLATE);
}

// BOOL $knowntextualness
// PATHNAME $cmifile
Packet IncludeTranslateResponse (std::vector<std::string> &words)
{
  if (words[0] == u8"BOOL" && words.size () == 2)
    {
      if (words[1] == u8"FALSE")
	return Packet (Client::PC_BOOL, 0);
      else if (words[1] == u8"TRUE")
	return Packet (Client::PC_BOOL, 1);
      else
	return Packet (Client::PC_ERROR, u8"");
    }
  else
    return PathnameResponse (words);
}

}

