/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

package org.eclipse.webdav.internal.authentication;

import org.eclipse.webdav.internal.kernel.utils.Assert;

/**
 * This class implements a BASE64 character encoder as specified in
 * RFC1521.
 */
public final class Base64Encoder {
    /**
     * Returns the BASE64 encoded <code>String</code> of the given data.
     *
     * @param data the bytes to be BASE64 encoded
     * @return     the BASE64 encoded <code>String</code> of the given data
     */
    public static String encode(byte[] data) {
        Assert.isNotNull(data);

        StringBuffer buf = new StringBuffer();

        byte b = 0;
        int bits = 2;

        for (int i = 0; i < data.length; ++i) {
            b = (byte) ((b | (data[i] >> bits)) & 0x003f);
            buf.append(encode(b));
            b = (byte) ((data[i] << 6 - bits) & 0x003f);
            bits += 2;
            if (bits == 8) {
                buf.append(encode((byte) (b & 0x003f)));
                b = 0;
                bits = 2;
            }
        }

        if (bits == 4) {
            buf.append(encode(b));
            buf.append("=="); //$NON-NLS-1$
        } else if (bits == 6) {
            buf.append(encode(b));
            buf.append('=');
        }

        return buf.toString();
    }

    private static char encode(byte b) {
        if (b >= 0 && b <= 25)
            return (char) (b + 65);
        if (b >= 26 && b <= 51)
            return (char) (b + 71);
        if (b >= 52 && b <= 61)
            return (char) (b - 4);
        if (b == 62)
            return '+';
        if (b == 63)
            return '/';
        return '=';
    }
}
