/*
 *  Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */


#if CONFIG_DEBUG
#include <assert.h>
#endif
#include <stdio.h>

#include "treecoder.h"

static void tree2tok(
    struct vp8_token_struct *const p,
    vp8_tree t,
    int i,
    int v,
    int L
)
{
    v += v;
    ++L;

    do
    {
        const vp8_tree_index j = t[i++];

        if (j <= 0)
        {
            p[-j].value = v;
            p[-j].Len = L;
        }
        else
            tree2tok(p, t, j, v, L);
    }
    while (++v & 1);
}

void vp8_tokens_from_tree(struct vp8_token_struct *p, vp8_tree t)
{
    tree2tok(p, t, 0, 0, 0);
}

void vp8_tokens_from_tree_offset(struct vp8_token_struct *p, vp8_tree t,
                                 int offset)
{
    tree2tok(p - offset, t, 0, 0, 0);
}

static void branch_counts(
    int n,                      /* n = size of alphabet */
    vp8_token tok               [ /* n */ ],
    vp8_tree tree,
    unsigned int branch_ct       [ /* n-1 */ ] [2],
    const unsigned int num_events[ /* n */ ]
)
{
    const int tree_len = n - 1;
    int t = 0;

#if CONFIG_DEBUG
    assert(tree_len);
#endif

    do
    {
        branch_ct[t][0] = branch_ct[t][1] = 0;
    }
    while (++t < tree_len);

    t = 0;

    do
    {
        int L = tok[t].Len;
        const int enc = tok[t].value;
        const unsigned int ct = num_events[t];

        vp8_tree_index i = 0;

        do
        {
            const int b = (enc >> --L) & 1;
            const int j = i >> 1;
#if CONFIG_DEBUG
            assert(j < tree_len  &&  0 <= L);
#endif

            branch_ct [j] [b] += ct;
            i = tree[ i + b];
        }
        while (i > 0);

#if CONFIG_DEBUG
        assert(!L);
#endif
    }
    while (++t < n);

}


void vp8_tree_probs_from_distribution(
    int n,                      /* n = size of alphabet */
    vp8_token tok               [ /* n */ ],
    vp8_tree tree,
    vp8_prob probs          [ /* n-1 */ ],
    unsigned int branch_ct       [ /* n-1 */ ] [2],
    const unsigned int num_events[ /* n */ ],
    unsigned int Pfac,
    int rd
)
{
    const int tree_len = n - 1;
    int t = 0;

    branch_counts(n, tok, tree, branch_ct, num_events);

    do
    {
        const unsigned int *const c = branch_ct[t];
        const unsigned int tot = c[0] + c[1];

#if CONFIG_DEBUG
        assert(tot < (1 << 24));        /* no overflow below */
#endif

        if (tot)
        {
            const unsigned int p = ((c[0] * Pfac) + (rd ? tot >> 1 : 0)) / tot;
            probs[t] = p < 256 ? (p ? p : 1) : 255; /* agree w/old version for now */
        }
        else
            probs[t] = vp8_prob_half;
    }
    while (++t < tree_len);
}
