#include "RandomNBit.h"
#include "../Random.h"

#include <cassert>
#include <cstdio>
#include <boost/lexical_cast.hpp>

tools::RandomNBit::RandomNBit( unsigned int numberOfBits ) :
    n( numberOfBits ), size( 0u ), data( n + 2u ) {
  switch ( n % 3 ) {
    case 0:
      size = n;
      break;
    case 1:
      size = n + 2u;
      break;
    case 2:
      size = n + 1u;
      break;
    default:
      assert( false );
  }
  data.resize( size );
  generate();
}

unsigned int tools::RandomNBit::getN() const {
  return n;
}

void tools::RandomNBit::generate() {
  assert( size == data.size() );
  assert( n <= size );
  assert( n + 3u >= size );
  for ( unsigned i = 0; i < ( size - n ); i++ )
    data.set( i, false );
  data.set( size - n, true );
  Random *random = Random::getInstance();
  for ( unsigned int i = ( size - n + 1u ); i < size; i++ )
    data.set( i, random->getBit() );
}

void tools::RandomNBit::print( bool octalOnly ) const {
  if ( !octalOnly ) {
    for ( unsigned int i = ( size - n ); i < size; i++ ) {
      unsigned int digit = 0u;
      if ( data.test( i ) )
        digit |= 0x01;
      std::printf( "%u", digit );
    }
    std::printf( "\n" );
  }

  for ( unsigned int i = 0u; i < size; i += 3u ) {
    unsigned int digit = 0u;
    if ( data.test( i ) )
      digit |= 0x04;
    if ( data.test( i + 1u ) )
      digit |= 0x02;
    if ( data.test( i + 2u ) )
      digit |= 0x01;
    std::printf( "%u", digit );
  }
  std::printf( "\n" );
}


int main( int argc, char *argv[] ) {
  if ( argc == 1 ) {
    std::fprintf( stderr, "Usage: %s <number of bits>\n", argv[0] );
    return 1;
  }
  unsigned int n = 0u;
  try {
    n = boost::lexical_cast<unsigned int>( argv[1] );
    if ( n == 0u )
      throw boost::bad_lexical_cast();
  } catch ( boost::bad_lexical_cast & ) {
    std::fprintf( stderr, "Could not convert '%s' to natural number!\n", argv[1] );
    std::fprintf( stderr, "Usage: %s <number of bits>\n", argv[0] );
    return 1;
  }

  tools::RandomNBit rnb( n );
  rnb.print();
  return 0;
}
