#ifndef morpheo_BitManipulation
#define morpheo_BitManipulation

/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include <stdint.h>
#include <iostream>
using namespace std;

namespace morpheo              {

  // gen_mask .....................................

  template <typename T>
  T gen_mask       (uint32_t size) 
  { 
    T mask = 0; 
    for (uint32_t i=0; i<size; i++)
      {
	mask <<= 1;
	mask  |= 1;
      }
    return mask;
  };

  // shift_left_logic, shift_right_logic ..........
  template <typename T>
  T shift_logic_left (uint32_t size, uint32_t data, uint32_t value)  
  {
    T mask = gen_mask<T> (size);

    return (mask & ((mask & data) << value));
  }

  template <typename T>
  T shift_logic_right (uint32_t size, uint32_t data, uint32_t value)  
  {
    T mask = gen_mask<T> (size);

    return (mask & ((mask & data) >> value));
  }

  // shift_logic ..................................
  template <typename T>
  T shift_logic      (uint32_t size, uint32_t data, uint32_t value, bool is_direction_left)
  {
    if (is_direction_left == true)
      return shift_logic_left  <T> (size, data, value);
    else
      return shift_logic_right <T> (size, data, value);
  }

  // shift_left_arithmetic, shift_right_arithmetic 
  template <typename T>
  T shift_arithmetic_left (uint32_t size, uint32_t data, uint32_t value)  
  {
    bool carry = (data&1) != 0;

    if (carry == false)
      return shift_logic_left <T> (size,data,value);
    else
      {
	if (value > size)
	  return gen_mask<T> (size);

	T mask = gen_mask<T> (value);
	return shift_logic_left <T> (size,data,value) | mask;
      }
  }


  template <typename T>
  T shift_arithmetic_right (uint32_t size, uint32_t data, uint32_t value)  
  {
    bool carry = (data&(1<<(size-1))) != 0;

    if (carry == false)
      return shift_logic_right <T> (size,data,value);
    else
      {
	if (value > size)
	  return gen_mask<T> (size);
	
	T mask = gen_mask<T> (value) << (size-value);
	return ((shift_logic_right <T> (size,data,value)) | mask);
      }
  }

  // shift_arithmetic .............................
  template <typename T>
  T shift_arithmetic      (uint32_t size, uint32_t data, uint32_t value, bool is_direction_left)
  {
    if (is_direction_left == true)
      return shift_arithmetic_left  <T> (size, data, value);
    else
      return shift_arithmetic_right <T> (size, data, value);
  }

  // shift ........................................
  template <typename T>
  T shift            (uint32_t size, uint32_t data, uint32_t value, bool is_direction_left, bool is_shift_arithmetic)
  {
    if (is_shift_arithmetic == true)
      return shift_arithmetic <T> (size, data, value, is_direction_left);
    else
      return shift_logic      <T> (size, data, value, is_direction_left);
  }

  // rotate_left, rotate_right ....................

  template <typename T>
  T rotate_left    (uint32_t size, uint32_t data, uint32_t value)  
  {
    T mask        = gen_mask<T> (size);
    T rotate_mask = gen_mask<T> (value);
    T rotate      = rotate_mask & shift_logic_right<T>(size,data,size-value);
    return (mask & (shift_logic_left <T> (size, data, value) | rotate));
  }

  template <typename T>
  T rotate_right    (uint32_t size, uint32_t data, uint32_t value)  
  {
    T mask        = gen_mask<T> (size);
    T rotate_mask = gen_mask<T> (value);
    T rotate      = shift_logic_left <T> (size,rotate_mask & data,size-value);
    return (mask & (shift_logic_right<T> (size, data, value) | rotate));
  }

  // rotate .......................................
  template <typename T>
  T rotate         (uint32_t size, uint32_t data, uint32_t value, bool is_direction_left)  
  {
    if (is_direction_left == true)
      return rotate_left  <T> (size, data, value);
    else
      return rotate_right <T> (size, data, value);
  }

  // range ........................................
  template <typename T>
  T range          (uint32_t size, uint32_t data, uint32_t index_max, uint32_t index_min)  
  {
    return gen_mask<T>(index_max-index_min+1) & shift_logic_left<T> (size, data, index_min);
  }

  template <typename T>
  T range          (uint32_t size, uint32_t data, uint32_t nb_bits)  
  {
    return gen_mask<T>(nb_bits) & data;
  }


}; // end namespace morpheo              

#endif
