

#include "sln_brigades.h"
#include "parser.h"
#include "handshake_messages.h"
#include "sln_digest.h"

selene_error_t *sln_parser_initilize() { return SELENE_SUCCESS; }

void sln_parser_terminate() {}

selene_error_t *sln_parser_create(selene_t *s) {
  sln_parser_baton_t *baton;
  SLN_ASSERT_CONTEXT(s);

  baton = (sln_parser_baton_t *)sln_calloc(s, sizeof(*baton));
  s->backend_baton = baton;
  sln_brigade_create(s->alloc, &baton->in_ccs);
  sln_brigade_create(s->alloc, &baton->in_alert);
  sln_brigade_create(s->alloc, &baton->in_handshake);
  sln_brigade_create(s->alloc, &baton->in_application);

  sln_digest_create(s, SLN_DIGEST_MD5, &baton->md5_handshake_digest);
  sln_digest_create(s, SLN_DIGEST_SHA1, &baton->sha1_handshake_digest);

  sln_handshake_register_callbacks(s);

  return SELENE_SUCCESS;
}

static selene_error_t *have_io(selene_t *s, selene_event_e event,
                               void *baton_) {
  sln_parser_baton_t *baton;
  SLN_ASSERT_CONTEXT(s);

  baton = s->backend_baton;
  return sln_state_machine(s, baton);
}

selene_error_t *sln_parser_start(selene_t *s) {
  sln_parser_baton_t *baton;
  SLN_ASSERT_CONTEXT(s);

  baton = s->backend_baton;

  if (s->mode == SLN_MODE_CLIENT) {
    baton->handshake = SLN_HANDSHAKE_CLIENT_SEND_HELLO;
  } else {
    baton->handshake = SLN_HANDSHAKE_SERVER_WAIT_CLIENT_HELLO;
  }

  slnDbg(s, "starting client, handshake state %d", baton->handshake);

  SELENE_ERR(selene_subscribe(s, SELENE_EVENT_IO_IN_ENC, have_io, NULL));
  SELENE_ERR(selene_subscribe(s, SELENE_EVENT_IO_IN_CLEAR, have_io, NULL));

  return sln_state_machine(s, baton);
}

selene_error_t *sln_parser_destroy(selene_t *s) {
  sln_parser_baton_t *baton;
  SLN_ASSERT_CONTEXT(s);

  baton = s->backend_baton;

  sln_brigade_destroy(baton->in_ccs);
  sln_brigade_destroy(baton->in_alert);
  sln_brigade_destroy(baton->in_handshake);
  sln_brigade_destroy(baton->in_application);

  if (baton->fatal_err != SELENE_SUCCESS) {
    selene_error_clear(baton->fatal_err);
    baton->fatal_err = SELENE_SUCCESS;
  }

  s->backend_baton = NULL;

  sln_digest_destroy(baton->md5_handshake_digest);
  sln_digest_destroy(baton->sha1_handshake_digest);

  sln_free(s, baton);

  return SELENE_SUCCESS;
}
