/******************************************************************************
 * Copyright (c) 2000-2025 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
 *
 ******************************************************************************/
#ifndef _PER_HH
#define _PER_HH

#include "Types.h"
#include "RInt.hh"
#include "Error.hh"
#include "Vector.hh"

class INTEGER;
struct default_struct;
class TTCN_Buffer;
class OBJID;

enum PER_OPTIONS {
  PER_UNALIGNED = 0x0,
  PER_ALIGNED = 0x1,
  PER_BASIC = 0x0,
  PER_CANONICAL = 0x2,
  PER_UNALIGNED_BASIC = PER_UNALIGNED | PER_BASIC,
  PER_ALIGNED_BASIC = PER_ALIGNED | PER_BASIC,
  PER_UNALIGNED_CANONICAL = PER_UNALIGNED | PER_CANONICAL,
  PER_ALIGNED_CANONICAL = PER_ALIGNED | PER_CANONICAL
};

#define PER_OCTET 256
#define PER_16K 16384
#define PER_64K 65536

extern const unsigned char FrontBitMask[9];
extern const unsigned char BackBitMask[9];
extern const unsigned char MiddleBitMask[8][9];

extern void PER_encode_opentype(TTCN_Buffer& p_main_buf, TTCN_Buffer& p_ot_buf, int p_options);
extern void PER_decode_opentype(TTCN_Buffer& p_main_buf, TTCN_Buffer& p_ot_buf, int p_options);
extern void PER_skip_opentype(TTCN_Buffer& p_main_buf, int p_options);

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

class Per_SetOf_Buffers {
  int nof_elements;
  TTCN_Buffer** elements;

  Per_SetOf_Buffers(const Per_SetOf_Buffers&); // copy disabled
  Per_SetOf_Buffers operator=(const Per_SetOf_Buffers&); // assignment disabled
public:
  Per_SetOf_Buffers(int p_nof_elements);
  ~Per_SetOf_Buffers();
  TTCN_Buffer& operator[](int p_index);
  void sort();
};

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

class Per_Constraint {
  boolean extension_marker;
public:
  Per_Constraint(boolean p_ext = FALSE): extension_marker(p_ext) { }
  virtual ~Per_Constraint() { }
  boolean has_extension_marker() const { return extension_marker; }
};

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

class Per_Integer_Constraint : public Per_Constraint {
public:
  enum PerIntSetting {
    PER_INT_UNCONSTRAINED, // (MIN..MAX)
    PER_INT_SINGLE_VALUE, // (a)
    PER_INT_RANGE_FINITE, // (a..b)
    PER_INT_RANGE_MINUS_INFINITY, // (MIN..a)
    PER_INT_RANGE_PLUS_INFINITY   // (a..MAX)
  };

private:
  PerIntSetting setting;
  INTEGER* val_a;
  INTEGER* val_b;

public:
  Per_Integer_Constraint(boolean p_ext = FALSE);
  Per_Integer_Constraint(PerIntSetting p_setting, INTEGER* p_a, boolean p_ext);
  Per_Integer_Constraint(INTEGER* p_a, INTEGER* p_b, boolean p_ext);
  ~Per_Integer_Constraint();

  INTEGER get_nof_values() const;
  INTEGER get_lower_bound() const;
  INTEGER get_upper_bound() const;
  boolean has_lower_bound() const;
  boolean has_upper_bound() const;
  boolean is_within_extension_root(const INTEGER& x) const;
};

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

class Per_Seq_Set_Constraint : public Per_Constraint {
public:
  struct ext_add_info {
    int start_idx;
    boolean is_group;
  };
private:
  int* field_order;
  int nof_ext_adds;
  ext_add_info* ext_add_indexes;
public:
  Per_Seq_Set_Constraint(int* p_field_order, int p_nof_ext_adds, ext_add_info* p_ext_add_indexes, boolean p_ext);
  const int* get_field_order() const { return field_order; }
  int get_nof_ext_adds() const { return nof_ext_adds; }
  const ext_add_info* get_ext_add_indexes() const { return ext_add_indexes; }
};

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

class Per_BitString_Constraint : public Per_Constraint {
  boolean named_bits;
  const Per_Integer_Constraint* size_constraint;
public:
  Per_BitString_Constraint(boolean p_has_named_bits,
    const Per_Integer_Constraint* p_size_constraint);
  ~Per_BitString_Constraint();
  boolean has_named_bits() const { return named_bits; }
  const Per_Integer_Constraint* get_size_constraint() const { return size_constraint; }
};

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

class Per_String_Constraint : public Per_Constraint {
public:
  enum PER_String_Type {
    PER_NumericString,
    PER_PrintableString,
    PER_VisibleString,
    PER_IA5String,
    PER_BMPString,
    PER_UniversalString,
    PER_GeneralizedTime,
    PER_UTCTime,
    /** The rest of the restricted string types (i.e. UTF8String, TeletexString,
      * VideotexString, GraphicString, GeneralString and ObjectDescriptor)
      * are grouped into one, since all of their constraints are ignored. */
    PER_UnknownMultiplierCharacterString
  };
  struct PER_String_Char_Set_Node {
    unsigned long char_code;
    boolean starts_interval;
  };
  struct PER_String_Char_Set {
    int nof_nodes;
    PER_String_Char_Set_Node* nodes;
  };
private:
  PER_String_Type string_type;
  PER_String_Char_Set* char_set;
  const Per_Integer_Constraint* size_constraint;
  static PER_String_Char_Set base_char_sets[PER_UnknownMultiplierCharacterString];
  int char_needed_bits[2][2];
  boolean use_original_char_code[2][2];
  long long int nof_char_values[2];
  unsigned long* encode_table[2][2];
  unsigned long* decode_table[2][2];
  void init(boolean p_ext_bit);
public:
  Per_String_Constraint();
  Per_String_Constraint(PER_String_Type p_string_type, PER_String_Char_Set* p_char_set,
    const Per_Integer_Constraint* p_size_constraint);
  ~Per_String_Constraint();
  PER_String_Type get_string_type() const { return string_type; }
  const Per_Integer_Constraint* get_size_constraint() const { return size_constraint; }
  const char* get_string_type_name() const;
  boolean is_valid_char(unsigned long p_char_code, boolean p_ext_bit) const;
  int get_char_needed_bits(int p_options, boolean p_ext_bit) const;
  unsigned long get_largest_char() const { return char_set->nodes[char_set->nof_nodes - 1].char_code; }
  void encode(TTCN_Buffer& p_buf, unsigned long p_char_code, int p_options, boolean p_ext_bit) const;
  unsigned long decode(TTCN_Buffer& p_buf, int p_options, boolean p_ext_bit) const;
  static unsigned long get_uchar_code(const universal_char& p_uchar);
  static universal_char get_uchar_from_code(unsigned long p_code);
};

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

class Per_Embedded_Pdv_Constraint : public Per_Constraint {
public:
  enum PER_EPDV_Case {
    PER_EPDV_GENERAL,
    PER_EPDV_PREDEFINED_FIXED,
    PER_EPDV_PREDEFINED_SYNTAXES
  };
private:
  PER_EPDV_Case enc_case;
  OBJID* objid1;
  OBJID* objid2;
public:
  Per_Embedded_Pdv_Constraint(PER_EPDV_Case p_case);
  Per_Embedded_Pdv_Constraint(OBJID* p_objid1, OBJID* p_objid2);
  ~Per_Embedded_Pdv_Constraint();
  PER_EPDV_Case get_case() const { return enc_case; }
  OBJID* get_objid(boolean p_first) const { return p_first ? objid1 : objid2; }
};

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

struct ASN_PERdescriptor_t {
  const Per_Constraint* c;
};

extern const ASN_PERdescriptor_t INTEGER_per_;
extern const ASN_PERdescriptor_t FLOAT_per_;
extern const ASN_PERdescriptor_t BOOLEAN_per_;
extern const ASN_PERdescriptor_t BITSTRING_per_;
extern const ASN_PERdescriptor_t OCTETSTRING_per_;
extern const ASN_PERdescriptor_t GeneralString_per_;
extern const ASN_PERdescriptor_t NumericString_per_;
extern const ASN_PERdescriptor_t UTF8String_per_;
extern const ASN_PERdescriptor_t PrintableString_per_;
extern const ASN_PERdescriptor_t UniversalString_per_;
extern const ASN_PERdescriptor_t BMPString_per_;
extern const ASN_PERdescriptor_t GraphicString_per_;
extern const ASN_PERdescriptor_t IA5String_per_;
extern const ASN_PERdescriptor_t TeletexString_per_;
extern const ASN_PERdescriptor_t VideotexString_per_;
extern const ASN_PERdescriptor_t VisibleString_per_;
extern const ASN_PERdescriptor_t ASN_NULL_per_;
extern const ASN_PERdescriptor_t OBJID_per_;
extern const ASN_PERdescriptor_t ASN_ROID_per_;
extern const ASN_PERdescriptor_t ASN_ANY_per_;
extern const ASN_PERdescriptor_t EXTERNAL_per_;
extern const ASN_PERdescriptor_t EMBEDDED_PDV_per_;
extern const ASN_PERdescriptor_t CHARACTER_STRING_per_;
extern const ASN_PERdescriptor_t ObjectDescriptor_per_;
extern const ASN_PERdescriptor_t ASN_GeneralizedTime_per_;
extern const ASN_PERdescriptor_t ASN_UTCTime_per_;

#endif // _PER_HH