//Editor-Info: -*- C++ -*-
//
//Subject:  TOVE project / 
//
//File: bitstring.cpp
//
//Version: $Revision: 1.10 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/06/23 06:38:02 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Authors:
//      Sami Raatikainen
//
//Description:
//      See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//      
//Licence:
//     
//
//History:
//
// 

#include "bitstring.h"
#include "pf/exception.h"
#include <math.h>

//
//Function: pfBitString constructors
//
//Description:
//      When passing string as parameter, the string may contain only
//      ones and zeroes.
//

pfBitString :: pfBitString(void)
    : _bitString()
{
    return;
}

pfBitString :: pfBitString(const string &string_)
    : _bitString()
{
    checkString(string_);
    _bitString = string_;
    return;
}

pfBitString :: pfBitString(const pfBitString &other_)
    : _bitString(other_._bitString)
{
    return;
}

//
//Function: pfBitString destructor
//
//Description:
//      
//

pfBitString :: ~pfBitString(void)
{
    return;
}

//
//Function: pfBitString - operator overloadings
//
//Description:
//
//

pfBoolean pfBitString :: operator==(const pfBitString &other_) const
{
    pfBoolean value = 0;
    if(_bitString == other_._bitString)
    {
        value = 1;
    }
    return value;
}

pfBoolean pfBitString :: operator!=(const pfBitString &other_) const
{
    pfBoolean value = 1;
    if((*this) == other_)
    {
        value = 0;
    }
    return value;
}

ostream& operator<<(ostream &ostream_, const pfBitString &bitString_)
{
    ostream_ << bitString_._bitString;
    return ostream_;
}


//
//Function: length()
//
//Description:
//      Returns the number of bits.
//

pfUlong pfBitString :: length(void) const
{
    pfUlong length = _bitString.length();
    return length;
}


//
//Function: putBits methods
//
//Description:
//      Puts the given value represented with given number of bits.
//      If length_ > 32, bitString will not be changed.
//      Note: GNU C++ BitString uses MSB last, but pfBitString MSB first.
//

void pfBitString :: putFirstBits(pfUlong value_, pfUlong length_)
{
    string newString = longToString(value_, length_);
    _bitString = newString + _bitString;
    return;
}

void pfBitString :: putFirstBits(const string &string_)
{
    checkString(string_);
    _bitString = string_ + _bitString;
    return;
}

void pfBitString :: putLastBits(pfUlong value_, pfUlong length_)
{
    string newString = longToString(value_, length_);
    _bitString += newString;
    return;
}

void pfBitString :: putLastBits(const string &string_)
{
    checkString(string_);
    _bitString += string_;
    return;
}

//
//Function: getBits methods
//
//Description:
//      Gets the value represented with given number of bits.
//

pfUlong pfBitString :: getFirstBits(pfUlong length_)
{
    pfUlong value;
    value = readBits(0, length_);
#ifndef NON_STD_STL
    _bitString.erase(0, length_);
#else
    _bitString.remove(0, length_);
#endif // NON_STD_STL    
    return value;
}

pfUlong pfBitString :: getLastBits(pfUlong length_)
{
    pfUlong value;
    if(length_ > _bitString.length())
    {
        throw pfBadValue(PF_EX_INFO);
    }
    pfUlong offset = _bitString.length() - length_;
    value = readBits(offset, length_);
#ifndef NON_STD_STL
    _bitString.erase(offset, length_);
#else
    _bitString.remove(offset, length_);
#endif // NON_STD_STL    
    return value;
}
    

//
//Function: readBits methods
//
//Description:
//      Returns the given value represented with given number of bits
//      from the given offset.
//

pfUlong pfBitString :: readBits(pfUlong offset_, pfUlong length_) const
{
    pfUlong value = 0;
    if((length_ + offset_) > (pfUlong)_bitString.length())
    {
        throw pfBadValue(PF_EX_INFO);
    }
    pfUlong iterPosition = length_;
    for(pfUlong i = 0; i < length_; i++)
    {
        iterPosition--;
        if(_bitString[offset_ + i] == '1')
        {
            value += 1 * (pfUlong)pow(2, iterPosition);
        }
    }
    return value;
}


//
//Function: toString
//
//Description:
//      Returns a string of a given length, doesn't change the bitstring.
//      If default value (0) is used, return the whole bitString.
//

string pfBitString :: toString(pfUlong length_) const
{
    string value;
    if(length_ > length())
    {
        throw pfBadValue(PF_EX_INFO);
    }
    if(length_ == 0)
    {
        value = _bitString;
    }
    else
    {
        value = _bitString.substr(length_);
    }
    return value;
}


//
//Function: checkString
//
//Description:
//      Private method that returns false if the given string
//      includes other chars than 0 or 1.
//

void pfBitString :: checkString(const string &string_) const
{
    string::const_iterator iter;
    for(iter = string_.begin(); iter != string_.end(); iter++)
    {
        if(*iter != '0' && *iter != '1')
        {
            throw pfBadValue(PF_EX_INFO);
        }
    }
    return;
}

//
//Function: longToString
//
//Description:
//      Converts length_ number of bits from a value_ to a string.
//      Makes use of the bitwise OR operator.
//

string pfBitString :: longToString(pfUlong value_, pfUlong length_) const
{
    string bitString;
    if(length_ > 32)
    {
        throw pfBadValue(PF_EX_INFO);
    }
    for(pfUlong i=0; i<length_; i++)
    {
        if(value_ == (value_ | (1<<i))) // if last bit 1
        {
            bitString = "1" + bitString;
        }
        else
        {
            bitString = "0" + bitString;
        }
    }    
    return bitString;
}
