// File:		bits.cc
// -----------------------------------------------------------------------
// Author:		Omri Traub, <otraub@eecs.harvard.edu>
// Modified by: Adriana Karagiozova, <karagioz@post.harvard.edu>
// Date:		08/06/01
// Assignment:	Unit 9 Main prigramming exercises>
// Version:		2
//
// Description:
//      Routines for reading and writing bits to a file.
//
// NOTE: 
//      You should not have to modify this file.
//

#include <iostream>
#include <iomanip>
#include <fstream>
#include "bits.hpp"


// Constructor: bit_reader
// -----------------------
// Description:
//      Initializes the reader with an input file handle.
// 
bit_reader::bit_reader(ifstream &_in)
{
    in = &_in;
 
    buffer  = 0;
    buf_len = 0;
}


// Function:    get_bit
// --------------------
// Description:
//      Reads the next bit from the file into the argument int variable.
//      Returns a bool indicating whether the end of file was reached.
//      
bool bit_reader::get_bit(int &the_bit)
{
    // If the uffer is empty, read more bits from the file
    if (buf_len == 0) {
		buffer = in->get();
		if (in->eof()) {
            // eof has been reached
	    	return false;
        }
		// just read 8 bits
		buf_len = 8;
    }

    // Now we need to get the highest bit that is valid:
    // i.e. the bit in position buf_len - 1 in the buffer
    the_bit = (buffer & (1 << (buf_len-1))) >> (buf_len - 1);

    buf_len--;

    return true;
}


// Constructor: bit_writer
// -----------------------
// Description:
//      Initializes the reader with an output file handle.
//      
bit_writer::bit_writer(ofstream &_out)
{
    out = &_out;
 
    buffer    = 0;
    buf_len   = 0;
    num_bytes = 0;
}


// Function:    write_code
// -----------------------
// Description:
//      Writes the next code (sequence of bits) to the file.
//      
void bit_writer::write_code(code the_code)
{
    int i;
    int bit;

    // call put_bit() on all bits, from left to right
    for (i = the_code.length - 1 ; i >= 0; i--) {
		bit = (the_code.bits & (1 << i)) >> i;
		put_bit(bit);
    }
}


// Function:    put_bit
// --------------------
// Description: 
//      Writes the next bit to the file
//      
void bit_writer::put_bit(int the_bit)
{
    // If the buffer has eight bits, need to flush it first
    if (buf_len == 8) {
		flush_bits();
    }

    // Add the new bit to the right of the exisiting buffer
    buffer = (buffer << 1) | the_bit;

    buf_len++;
}


// Function:    flush_bits
// -----------------------
// Description:
//      When the buffer gets full, writes the bits out to the file.
// 
// Note:
//      Call this file when you are done writing, or else some bits
//      may not get written out!
//      
void bit_writer::flush_bits()
{
    // If buffer has fewer than 8 bits, need to shift the bits
    // left to align them with the left end of the byte before 
    // writing out.  
    // NOTE: when you read in the bits, there may be some 
    // extra 0 bits dangling at the end!
    if (buf_len < 8) {
		buffer = buffer << (8 - buf_len);
    }
    
    out->put(buffer);

    buffer  = 0;
    buf_len = 0;

    num_bytes++;
}
