#include <iostream>
#include <string>
#include <type_traits>

struct empty_result
{
    static const std::string value;
};

template<size_t Width, size_t Height>
struct result_size
{
    static const size_t width = Width;
    static const size_t height = Height;
    static const size_t square = Width * Height;
};

template<char Foreground, char Background>
struct render_rule
{
    static const char background = Background;
    static const char foreground = Foreground;
};

const std::string empty_result::value;

template<size_t Idx, unsigned char Block>
struct get_element
{
    static const size_t value = ((Block & ((Idx < 4) ? 0xF0 : 0x0F)) >> (7 - Idx)) & 1;
};

template<size_t Id, size_t Idx, class Size, class Rule, size_t Element>
struct process_one
{
    static const bool in_render_zone = Idx < Size::square;
    static const bool new_line = Idx > 0 && (Idx % Size::width == 0);
    static const std::string value;
};

template<size_t Id, size_t Idx, class Size, class Rule, size_t Element>
const std::string process_one<Id, Idx, Size, Rule, Element>::value = (in_render_zone) ? (((new_line) ? (std::string() + '\n') : std::string()) + 
    ((Element != 0) ? Rule::foreground : Rule::background)) : std::string();

template<size_t Id, size_t Idx, class Size, class Rule, unsigned char Block>
struct process_block
{
    static const std::string value;
};

template<size_t Id, size_t Idx, class Size, class Rule, unsigned char Block>
const std::string process_block<Id, Idx, Size, Rule, Block>::value = 
    process_one<Id, Idx, Size, Rule, get_element<0, Block>::value>::value +
    process_one<Id, Idx + 1, Size, Rule, get_element<1, Block>::value>::value +
    process_one<Id, Idx + 2, Size, Rule, get_element<2, Block>::value>::value +
    process_one<Id, Idx + 3, Size, Rule, get_element<3, Block>::value>::value +
    process_one<Id, Idx + 4, Size, Rule, get_element<4, Block>::value>::value +
    process_one<Id, Idx + 5, Size, Rule, get_element<5, Block>::value>::value +
    process_one<Id, Idx + 6, Size, Rule, get_element<6, Block>::value>::value +
    process_one<Id, Idx + 7, Size, Rule, get_element<7, Block>::value>::value;

template<size_t Id, size_t Idx, class Size, class Rule, unsigned char... Data> struct render;

template<size_t Id, size_t Idx, class Size, class Rule, unsigned char First, unsigned char... Data>
struct render<Id, Idx, Size, Rule, First, Data...>
{
    static const std::string value;
};

template<size_t Id, size_t Idx, class Size, class Rule, unsigned char First, unsigned char... Data>
const std::string render<Id, Idx, Size, Rule, First, Data...>::value = process_block<Id, Idx, Size, Rule, First>::value +
    render<Id, Idx + 8, Size, Rule, Data...>::value;

template<size_t Id,  size_t Idx, class Size, class Rule, unsigned char Last>
struct render<Id, Idx, Size, Rule, Last>
{
    static const std::string value;
};

template<size_t Id, size_t Idx, class Size, class Rule, unsigned char Last>
const std::string render<Id, Idx, Size, Rule, Last>::value = process_block<Id, Idx, Size, Rule, Last>::value;

template<size_t Id, size_t Width, class Rule, unsigned char... Data>
struct silly_img
{
    static const size_t width = Width;
    static const size_t height = (Width > 0) ? (sizeof...(Data) * 8 / Width) : 0;
    static const bool is_valid = width > 0 && height > 0;
    static const std::string data;

    static void show_me()
    {
        std::cout << "(" << Id << ") Size: " << width << " x " << height << "\n\n";
        std::cout << data;
    }
};

template<size_t Id, size_t Width, class Rule, unsigned char... Data>
const std::string silly_img<Id, Width, Rule, Data...>::data = std::string() + 
    std::conditional< is_valid, render<Id, 0, result_size<width, height>, Rule, Data...>, empty_result>::type::value;

int main()
{
    silly_img<0, 11, render_rule<'$', ' '>, 0x31, 0x8F, 0x7B, 0xFF, 0xFF, 0xF3, 0xF8, 0x1C, 0x01, 0x00>::show_me();
    std::cout << "\n\n";
    silly_img<1, 15, render_rule<'#', '.'>, 0x31, 0x84, 0xF7, 0x9F, 0xFF, 0x97, 0xFF, 0x03, 0xF8, 0x81, 0xC3, 0x81, 0x02, 0x00>::show_me();
    std::cout << "\n\n";
    silly_img<2, 15, render_rule<'*', ' '>, 0x3F, 0xE4, 0xFF, 0x9F, 0xC0, 0x17, 0x80, 0x0F, 0x00, 0x8F, 0xF3, 0x8F, 0xF2, 0x00>::show_me();
}
