/******************************************************************************
 * Copyright (c) 2000-2023 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors:
 *   Baranyi, Botond – initial implementation
 *
 ******************************************************************************/
#include "PER.hh"
#include "Integer.hh"

const unsigned char FrontBitMask[9] = {
  0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };

const unsigned char BackBitMask[9] = {
  0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };

const unsigned char MiddleBitMask[8][9] = {
  { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF },
  { 0x00, 0x40, 0x60, 0x70, 0x78, 0x7C, 0x7E, 0x7F, 0x00 },
  { 0x00, 0x20, 0x30, 0x38, 0x3C, 0x3E, 0x3F, 0x00, 0x00 },
  { 0x00, 0x10, 0x18, 0x1C, 0x1E, 0x1F, 0x00, 0x00, 0x00 },
  { 0x00, 0x08, 0x0C, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00 },
  { 0x00, 0x04, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 },
  { 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
  { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };


INTEGER PerConstraint::get_nof_values() const
{
  TTCN_error("Internal error: PerConstraint::get_nof_values() called");
  return INTEGER(0);
}

INTEGER PerConstraint::get_lower_bound() const
{
  TTCN_error("Internal error: PerConstraint::get_lower_bound() called");
  return INTEGER(0);
}

INTEGER PerConstraint::get_upper_bound() const
{
  TTCN_error("Internal error: PerConstraint::get_upper_bound() called");
  return INTEGER(0);
}

boolean PerConstraint::has_lower_bound() const
{
  TTCN_error("Internal error: PerConstraint::has_lower_bound() called");
  return FALSE;
}

boolean PerConstraint::has_upper_bound() const
{
  TTCN_error("Internal error: PerConstraint::has_upper_bound() called");
  return FALSE;
}

boolean PerConstraint::has_extension_marker() const
{
  TTCN_error("Internal error: PerConstraint::has_extension_marker() called");
  return FALSE;
}

boolean PerConstraint::is_within_extension_root(const INTEGER&) const
{
  TTCN_error("Internal error: PerConstraint::is_within_extension_root() called");
  return FALSE;
}

////////////////////////////////////////////////////////////////////////////////

PerIntegerConstraint::PerIntegerConstraint(boolean p_ext)
: setting(PER_INT_UNCONSTRAINED), val_a(NULL), val_b(NULL), extension_marker(p_ext)
{
}

PerIntegerConstraint::PerIntegerConstraint(PerIntSetting p_setting, INTEGER* p_a, boolean p_ext)
: setting(p_setting), val_a(p_a), val_b(NULL), extension_marker(p_ext)
{
  switch (setting) {
  case PER_INT_SINGLE_VALUE:
  case PER_INT_RANGE_MINUS_INFINITY:
  case PER_INT_RANGE_PLUS_INFINITY:
    break; // OK
  default:
    TTCN_error("Internal error: Invalid PER integer constraint type: %d", (int) setting);
  }
}

PerIntegerConstraint::PerIntegerConstraint(INTEGER* p_a, INTEGER* p_b, boolean p_ext)
: setting(PER_INT_RANGE_FINITE), val_a(p_a), val_b(p_b), extension_marker(p_ext)
{
}

PerIntegerConstraint::~PerIntegerConstraint()
{
  switch (setting) {
  case PER_INT_RANGE_FINITE:
    delete val_b;
    // fall through
  case PER_INT_SINGLE_VALUE:
  case PER_INT_RANGE_MINUS_INFINITY:
  case PER_INT_RANGE_PLUS_INFINITY:
    delete val_a;
    break;
  default:
    break;
  }
}

INTEGER PerIntegerConstraint::get_nof_values() const
{
  switch (setting) {
  case PER_INT_SINGLE_VALUE:
    return INTEGER(1);
  case PER_INT_RANGE_FINITE:
    return *val_b - *val_a + 1;
  default:
    return INTEGER(0);
  }
}

INTEGER PerIntegerConstraint::get_lower_bound() const
{
  switch (setting) {
  case PER_INT_SINGLE_VALUE:
  case PER_INT_RANGE_FINITE:
  case PER_INT_RANGE_PLUS_INFINITY:
    return *val_a;
  default:
    TTCN_error("Internal error: Lower bound requested for invalid PER integer "
      "constraint type: %d", (int) setting);
  }
}

INTEGER PerIntegerConstraint::get_upper_bound() const
{
  switch (setting) {
  case PER_INT_SINGLE_VALUE:
  case PER_INT_RANGE_MINUS_INFINITY:
    return *val_a;
  case PER_INT_RANGE_FINITE:
    return *val_b;
  default:
    TTCN_error("Internal error: Upper bound requested for invalid PER integer "
      "constraint type: %d", (int) setting);
  }
}

boolean PerIntegerConstraint::has_lower_bound() const
{
  switch (setting) {
  case PER_INT_SINGLE_VALUE:
  case PER_INT_RANGE_FINITE:
  case PER_INT_RANGE_PLUS_INFINITY:
    return TRUE;
  default:
    return FALSE;
  }
}

boolean PerIntegerConstraint::has_upper_bound() const
{
  switch (setting) {
  case PER_INT_SINGLE_VALUE:
  case PER_INT_RANGE_FINITE:
  case PER_INT_RANGE_MINUS_INFINITY:
    return TRUE;
  default:
    return FALSE;
  }
}

boolean PerIntegerConstraint::is_within_extension_root(const INTEGER& x) const
{
  switch (setting) {
  case PER_INT_SINGLE_VALUE:
    return x == *val_a;
  case PER_INT_RANGE_FINITE:
    return x >= *val_a && x <= *val_b;
  case PER_INT_RANGE_PLUS_INFINITY:
    return x >= *val_a;
  case PER_INT_RANGE_MINUS_INFINITY:
    return x <= *val_a;
  default:
    return TRUE;
  }
}

static PerIntegerConstraint INTEGER_per_cons_;
const ASN_PERdescriptor_t INTEGER_per_ = { &INTEGER_per_cons_ };

const ASN_PERdescriptor_t FLOAT_per_ = { NULL }; // todo
const ASN_PERdescriptor_t BOOLEAN_per_ = { NULL }; // todo
const ASN_PERdescriptor_t BITSTRING_per_ = { NULL }; // todo

static PerIntegerConstraint default_size_per_cons_(PerIntegerConstraint::PER_INT_RANGE_PLUS_INFINITY, new INTEGER(0), FALSE);
const ASN_PERdescriptor_t OCTETSTRING_per_ = { &default_size_per_cons_ };

const ASN_PERdescriptor_t GeneralString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t NumericString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t UTF8String_per_ = { NULL }; // todo
const ASN_PERdescriptor_t PrintableString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t UniversalString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t BMPString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t GraphicString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t IA5String_per_ = { NULL }; // todo
const ASN_PERdescriptor_t TeletexString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t VideotexString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t VisibleString_per_ = { NULL }; // todo
const ASN_PERdescriptor_t ASN_NULL_per_ = { NULL }; // todo
const ASN_PERdescriptor_t OBJID_per_ = { NULL }; // todo
const ASN_PERdescriptor_t ASN_ROID_per_ = { NULL }; // todo
const ASN_PERdescriptor_t ASN_ANY_per_ = { NULL }; // todo
const ASN_PERdescriptor_t ENUMERATED_per_ = { NULL }; // todo
const ASN_PERdescriptor_t EXTERNAL_per_ = { NULL }; // todo
const ASN_PERdescriptor_t EMBEDDED_PDV_per_ = { NULL }; // todo
const ASN_PERdescriptor_t CHARACTER_STRING_per_ = { NULL }; // todo
const ASN_PERdescriptor_t ObjectDescriptor_per_ = { NULL }; // todo
const ASN_PERdescriptor_t ASN_GeneralizedTime_per_ = { NULL }; // todo