//
//  ========================================================================
//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.http2.hpack;

import java.nio.ByteBuffer;

public class NBitInteger
{
    public static int octectsNeeded(int n, int i)
    {
        if (n == 8)
        {
            int nbits = 0xFF;
            i = i - nbits;
            if (i < 0)
                return 1;
            if (i == 0)
                return 2;
            int lz = Integer.numberOfLeadingZeros(i);
            int log = 32 - lz;
            return 1 + (log + 6) / 7;
        }

        int nbits = 0xFF >>> (8 - n);
        i = i - nbits;
        if (i < 0)
            return 0;
        if (i == 0)
            return 1;
        int lz = Integer.numberOfLeadingZeros(i);
        int log = 32 - lz;
        return (log + 6) / 7;
    }

    public static void encode(ByteBuffer buf, int n, int i)
    {
        if (n == 8)
        {
            if (i < 0xFF)
            {
                buf.put((byte)i);
            }
            else
            {
                buf.put((byte)0xFF);

                int length = i - 0xFF;
                while (true)
                {
                    if ((length & ~0x7F) == 0)
                    {
                        buf.put((byte)length);
                        return;
                    }
                    else
                    {
                        buf.put((byte)((length & 0x7F) | 0x80));
                        length >>>= 7;
                    }
                }
            }
        }
        else
        {
            int p = buf.position() - 1;
            int bits = 0xFF >>> (8 - n);

            if (i < bits)
            {
                buf.put(p, (byte)((buf.get(p) & ~bits) | i));
            }
            else
            {
                buf.put(p, (byte)(buf.get(p) | bits));

                int length = i - bits;
                while (true)
                {
                    if ((length & ~0x7F) == 0)
                    {
                        buf.put((byte)length);
                        return;
                    }
                    else
                    {
                        buf.put((byte)((length & 0x7F) | 0x80));
                        length >>>= 7;
                    }
                }
            }
        }
    }

    public static int decode(ByteBuffer buffer, int n)
    {
        if (n == 8)
        {
            int nbits = 0xFF;

            int i = buffer.get() & 0xff;

            if (i == nbits)
            {
                int m = 1;
                int b;
                do
                {
                    b = 0xff & buffer.get();
                    i = i + (b & 127) * m;
                    m = m * 128;
                }
                while ((b & 128) == 128);
            }
            return i;
        }

        int nbits = 0xFF >>> (8 - n);

        int i = buffer.get(buffer.position() - 1) & nbits;

        if (i == nbits)
        {
            int m = 1;
            int b;
            do
            {
                b = 0xff & buffer.get();
                i = i + (b & 127) * m;
                m = m * 128;
            }
            while ((b & 128) == 128);
        }
        return i;
    }
}
