/*******************************************************************************
 *
 * File:     type-facilities.cpp
 *
 * Contents: An example showcasing various type-related support facilities.
 *
 * Copyright 2017
 *
 * Author: David Juhasz (david.juhasz@tuwien.ac.at)
 *
 ******************************************************************************/

#include "rosa/config/version.h"

#include "rosa/support/log.h"
#include "rosa/support/terminal_colors.h"
#include "rosa/support/type_token.hpp"

#include <iostream>

using namespace rosa;
using namespace rosa::terminal;

int main(void) {
  LOG_INFO_STREAM << library_string() << " -- " << Color::Red
                  << "type facilities" << Color::Default << std::endl;

  auto &Log = LOG_TRACE_STREAM << std::endl;
  Log << "NumberOfBuiltinTypes: " << NumberOfBuiltinTypes << std::endl
      << "TokenBits: " << token::TokenBits << std::endl
      << "RepresentationBits: " << token::RepresentationBits << std::endl
      << "MaxTokenizableListSize: " << token::MaxTokenizableListSize
      << std::endl
      << std::endl;

  Log << "Type number information on 'uint8_t':" << std::endl;
  constexpr TypeNumber TN = TypeNumberOf<uint8_t>::Value;
  Log << "  type number: " << PRINTABLE_TN(TN) << std::endl
      << "  size: " << TypeForNumber<TN>::Size << std::endl
      << "  name: " << TypeForNumber<TN>::Name << std::endl
      << std::endl;

  Log << "Type number information on 'std::string':" << std::endl;
  constexpr TypeNumber TNS = TypeNumberOf<std::string>::Value;
  Log << "  type number: " << PRINTABLE_TN(TNS) << std::endl
      << "  size: " << TypeForNumber<TNS>::Size << std::endl
      << "  name: " << TypeForNumber<TNS>::Name << std::endl
      << std::endl;

  Log << "Type number information of AtomConstants:"
      << std::endl;
  using Atom1 = AtomConstant<atom("atom1")>;
  using Atom2 = AtomConstant<atom("atom2")>;
  Log << "  std::is_same<Atom1, Atom2>::value: "
      << std::is_same<Atom1, Atom2>::value << std::endl
      << "  TypeNumberOf<Atom1>::Value: "
      << PRINTABLE_TN(TypeNumberOf<Atom1>::Value) << std::endl
      << "  TypeNumberOf<Atom2>::Value: "
      << PRINTABLE_TN(TypeNumberOf<Atom2>::Value) << std::endl
      << "  name: " << TypeForNumber<TypeNumberOf<Atom1>::Value>::Name
      << std::endl
      << std::endl;

  Log << "Type token information on 'TypeList<uint8_t, uint16_t, std::string>':"
      << std::endl;
  // Token is generated statically.
  constexpr Token T = TypeToken<uint8_t, uint16_t, std::string>::Value;
  STATIC_ASSERT(
      (T == TypeListToken<TypeList<uint8_t, uint16_t, std::string>>::Value),
      "alias template definition is wrong");
  Token T_ = T; // We need a non-const value for dropping head later.
  // Iterate over encoded entries in Token.
  while (!emptyToken(T_)) {
    Log << "  token: " << PRINTABLE_TOKEN(T_) << std::endl
        << "  valid: " << validToken(T_) << std::endl
        << "  empty: " << emptyToken(T_) << std::endl
        << "  length: " << lengthOfToken(T_) << std::endl
        << "  full size: " << sizeOfValuesOfToken(T_) << std::endl
        << "  head type number: " << PRINTABLE_TN(typeNumberOfHeadOfToken(T_))
        << std::endl
        << "  size of head: " << sizeOfHeadOfToken(T_) << std::endl
        << "  name of head: " << nameOfHeadOfToken(T_) << std::endl
        << "  is head uint8_t: " << isHeadOfTokenTheSameType<uint8_t>(T_)
        << std::endl
        << "  is head uint16_t: " << isHeadOfTokenTheSameType<uint16_t>(T_)
        << std::endl
        << "  is head std::string: "
        << isHeadOfTokenTheSameType<std::string>(T_) << std::endl
        << "Dropping head..." << std::endl;
    dropHeadOfToken(T_);
  }
  // Here when Token became empty.
  Log << "  token: " << PRINTABLE_TOKEN(T_) << std::endl
      << "  empty: " << emptyToken(T_) << std::endl;

  return 0;
}

