#ifndef BOOST_ARCHIVE_ITERATORS_TRANSFORM_WIDTH_HPP
#define BOOST_ARCHIVE_ITERATORS_TRANSFORM_WIDTH_HPP

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// transform_width.hpp

// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org for updates, documentation, and revision history.

// iterator which takes elements of x bits and returns elements of y bits.
// used to change streams of 8 bit characters into streams of 6 bit characters.
// and vice-versa for implementing base64 encodeing/decoding. Be very careful
// when using and end iterator.  end is only reliable detected when the input
// stream length is some common multiple of x and y.  E.G. Base64 6 bit
// character and 8 bit bytes. Lowest common multiple is 24 => 4 6 bit characters
// or 3 8 bit characters

#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME & PTFO
#include <boost/serialization/pfto.hpp>

#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_traits.hpp>

namespace boost { 
namespace archive {
namespace iterators {

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// class used by text archives to translate char strings to wchar_t
// strings of the currently selected locale
template<
    class Base, 
    int BitsOut, 
    int BitsIn, 
    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type // output character
>
class transform_width : 
    public boost::iterator_adaptor<
        transform_width<Base, BitsOut, BitsIn, CharType>,
        Base,
        CharType,
        single_pass_traversal_tag,
        CharType
    >
{
    friend class boost::iterator_core_access;
    typedef BOOST_DEDUCED_TYPENAME boost::iterator_adaptor<
        transform_width<Base, BitsOut, BitsIn, CharType>,
        Base,
        CharType,
        single_pass_traversal_tag,
        CharType
    > super_t;

    typedef transform_width<Base, BitsOut, BitsIn, CharType> this_t;
    typedef BOOST_DEDUCED_TYPENAME iterator_value<Base>::type base_value_type;

    CharType fill();

    CharType dereference_impl(){
        if(! m_full){
            m_current_value = fill();
            m_full = true;
        }
        return m_current_value;
    }

    CharType dereference() const {
        return const_cast<this_t *>(this)->dereference_impl();
    }

    // test for iterator equality
    bool equal(const this_t & rhs) const {
        return
            this->base_reference() == rhs.base_reference();
        ;
    }

    void increment(){
        m_displacement += BitsOut;

        while(m_displacement >= BitsIn){
            m_displacement -= BitsIn;
            if(0 == m_displacement)
                m_bufferfull = false;
            if(! m_bufferfull){
                // note: suspect that this is not invoked for borland
                ++(this->base_reference());
            }
        }
        m_full = false;
    }

    CharType m_current_value;
    // number of bits left in current input character buffer
    unsigned int m_displacement;
    base_value_type m_buffer;
    // flag to current output character is ready - just used to save time
    bool m_full;
    // flag to indicate that m_buffer has data
    bool m_bufferfull;

public:
    // make composible buy using templated constructor
    template<class T>
    transform_width(BOOST_PFTO_WRAPPER(T) start) : 
        super_t(Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start)))),
        m_displacement(0),
        m_full(false),
        m_bufferfull(false)
    {}
    // intel 7.1 doesn't like default copy constructor
    transform_width(const transform_width & rhs) : 
        super_t(rhs.base_reference()),
        m_current_value(rhs.m_current_value),
        m_displacement(rhs.m_displacement),
        m_buffer(rhs.m_buffer),
        m_full(rhs.m_full),
        m_bufferfull(rhs.m_bufferfull)
    {}
};

template<class Base, int BitsOut, int BitsIn, class CharType>
CharType transform_width<Base, BitsOut, BitsIn, CharType>::fill(){
    CharType retval = 0;
    unsigned int missing_bits = BitsOut;
    for(;;){
        unsigned int bcount;
        if(! m_bufferfull){
            m_buffer = * this->base_reference();
            m_bufferfull = true;
            bcount = BitsIn;
        }
        else
            bcount = BitsIn - m_displacement;
        unsigned int i = (std::min)(bcount, missing_bits);
        // shift interesting bits to least significant position
        unsigned int j = m_buffer >> (bcount - i);
        // strip off uninteresting bits
        // (note presumption of two's complement arithmetic)
        j &= ~(-(1 << i));
        // append then interesting bits to the output value
        retval <<= i;
        retval |= j;
        missing_bits -= i;
        if(0 == missing_bits)
            break;
        // note: suspect that this is not invoked for borland 5.51
        ++(this->base_reference());
        m_bufferfull = false;
    }
    return retval;
}

} // namespace iterators
} // namespace archive
} // namespace boost

#endif // BOOST_ARCHIVE_ITERATORS_TRANSFORM_WIDTH_HPP
