// Copyright (C) 2016, 2017  Stefan Vargyas
// 
// This file is part of Json-Type.
// 
// Json-Type is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Json-Type is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Json-Type.  If not, see <http://www.gnu.org/licenses/>.

#ifndef BITSET_NAME
#error  BITSET_NAME is not defined
#endif

#ifdef  BITSET_NEED_VALIDATE

#ifndef BITSET_PTR_SPACE_TYPE
#error  BITSET_PTR_SPACE_TYPE is not defined
#endif

#ifndef BITSET_VALIDATE_PTR_SPACE_INSERT
#error  BITSET_VALIDATE_PTR_SPACE_INSERT is not defined
#endif

#endif // BITSET_NEED_VALIDATE

#ifdef  BITSET_NEED_GEN_DEF

#ifndef BITSET_PTR_SPACE_TYPE
#error  BITSET_PTR_SPACE_TYPE is not defined
#endif

#ifndef BITSET_PTR_SPACE_NODE_TYPE
#error  BITSET_PTR_SPACE_NODE_TYPE is not defined
#endif

#ifndef BITSET_GEN_DEF_PTR_SPACE_INSERT
#error  BITSET_GEN_DEF_PTR_SPACE_INSERT is not defined
#endif

#ifndef BITSET_GEN_DEF_PTR_SPACE_LOOKUP
#error  BITSET_GEN_DEF_PTR_SPACE_LOOKUP is not defined
#endif

#endif // BITSET_NEED_GEN_DEF

#define BITSET_MAKE_NAME_(n, s) n ## _bit_set_ ## s
#define BITSET_MAKE_NAME(n, s)  BITSET_MAKE_NAME_(n, s)

#define BITSET_VALIDATE BITSET_MAKE_NAME(BITSET_NAME, validate)
#define BITSET_GEN_DEF  BITSET_MAKE_NAME(BITSET_NAME, gen_def)

#ifdef BITSET_NEED_VALIDATE

static bool BITSET_VALIDATE(
    const struct bit_set_t* set,
    BITSET_PTR_SPACE_TYPE* space,
    const void** result)
{
    BITSET_VALIDATE_PTR_SPACE_INSERT(set);

    if (!BIT_SET_IS_VAL_(set)) {
        ASSERT(set->u.ptr != NULL);
        BITSET_VALIDATE_PTR_SPACE_INSERT(set->u.ptr);
    }

    *result = NULL;
    return true;
}

#endif // BITSET_NEED_VALIDATE

#ifdef BITSET_NEED_GEN_DEF

static void BITSET_GEN_DEF(
    const struct bit_set_t* set,
    BITSET_PTR_SPACE_TYPE* space,
    FILE* file)
{
    BITSET_PTR_SPACE_NODE_TYPE *t, *u;
    size_t m;
    bool v;

    m = BIT_SET_VAL_MASK_(set);

    if (!(v = BIT_SET_IS_VAL_(set))) {
        size_t k = 0, n = 0, w;
        const uchar_t *p, *e;

        u = BITSET_GEN_DEF_PTR_SPACE_INSERT(set->u.ptr);
        w = BIT_SET_WIDTH_(set->size);

        fprintf(file,
            "static const uchar_t __%zu[%zu] = {",
            u->val, w);

        for (p = set->u.ptr,
             e = p + w;
             p < e;
             p ++,
             k ++) {
            if (*p) {
                size_t u =
                    UINT_TO_SIZE(*p);
                fprintf(file,
                    "\n"
                    "    [%zu] = 0x%02zxu,",
                    k, p == e - 1 ? (u & m) : u);
                n ++;
            }
        }

        if (n)
            fputc('\n', file);

        fputs(
            "};\n\n",
            file);
    }

    t = BITSET_GEN_DEF_PTR_SPACE_INSERT(set);

    fprintf(file,
        "static const struct bit_set_t __%zu = {\n"
        "    .size = %zu,\n",
        t->val, set->size);

    if (v)
        fprintf(file,
            "    .u.val = 0x%zxul\n",
            UINT_TO_SIZE(set->u.val) & m);
    else
        fprintf(file,
            "    .u.ptr = __%zu\n",
            u->val);

    fputs(
        "};\n\n",
        file);
}

#endif // BITSET_NEED_GEN_DEF


