#ifndef INCLUDED_BOBCAT_BASE64BUFBASE_
#define INCLUDED_BOBCAT_BASE64BUFBASE_

//  See also https://en.wikipedia.org/wiki/Base64
// And  https://www.ietf.org/rfc/rfc4648.txt
//
//
//                       Table 1: The Base 64 Alphabet
//
//      Value Encoding  Value Encoding  Value Encoding  Value Encoding
//          0 A            17 R            34 i            51 z
//          1 B            18 S            35 j            52 0
//          2 C            19 T            36 k            53 1
//          3 D            20 U            37 l            54 2
//          4 E            21 V            38 m            55 3
//          5 F            22 W            39 n            56 4
//          6 G            23 X            40 o            57 5
//          7 H            24 Y            41 p            58 6
//          8 I            25 Z            42 q            59 7
//          9 J            26 a            43 r            60 8
//         10 K            27 b            44 s            61 9
//         11 L            28 c            45 t            62 +
//         12 M            29 d            46 u            63 /
//         13 N            30 e            47 v
//         14 O            31 f            48 w         (pad) =
//         15 P            32 g            49 x
//         16 Q            33 h            50 y
//
//
// Bit offset   | 7               0 | 7               0 | 7               0 |
// Text content |          M        |        a          |        n          |
// ASCII        |        77 (0x4d)  |     97 (0x61)     |    110 (0x6e)     |
// Bit pattern  | 0 1 0 0 1 1 | 0 1 | 0 1 1 0 | 0 0 0 1 | 0 1 | 1 0 1 1 1 0 |
// Index        |      19     |        2      |        5      |    46       |
// Base64       |       T     |        W      |        F      |     u       |
// Variables    |      b0     |       b1      |       b2      |    b3       |
//
// If the last group of four ends in '==' (i.e., b2 equals '=') then only one
// char is written;
// If the last group of four ends in '='  (i.e., b3 equals '=') then only two
// chars are written;

#include <istream>
#include <string>

#include <bobcat/ifilterbuf>
#include <bobcat/exception>

namespace FBB
{

namespace IUO   // the facilities defined here are not further documented:
{               // the Base64BufBase class defined below should be
                // used by IBase64Buf only.

class Base64BufBase: public FBB::IFilterBuf
{
    std::istream &d_in;                         // stream to read
    bool (Base64BufBase::*d_action)();    // encrypting or decrypting
    size_t d_bufSize;
    std::string d_buffer;
    bool d_allDone = false;

    static std::string const s_tabStr;          // conversion characters

    public:
        Base64BufBase(std::istream &in, size_t bufSize);

    protected:
        void doEncrypt();
        void doDecrypt();

    private:
        bool filter(char const **srcBegin, char const **srcEnd) override;
        bool encrypt(); // false means: don't call again, but there
                        // may still be input waiting in d_buffer
        bool decrypt();

        template <int from, int size, int shl = 0>
        static int bits(int value);

        static size_t indexOf(int ch);

};

template <int from, int size, int shl>
inline int Base64BufBase::bits(int value)
{
    return value == EOF ? 0 :
            (value & ((1 << (from + size)) - 1)) >> from << shl;
}

}   // IUO
}   // FBB

#endif
