/*
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.jcodings.specific;

import org.jcodings.Config;
import org.jcodings.IntHolder;
import org.jcodings.ascii.AsciiTables;
import org.jcodings.unicode.FixedWidthUnicodeEncoding;

public final class UTF32LEEncoding extends FixedWidthUnicodeEncoding {

    protected UTF32LEEncoding() {
        super("UTF-32LE", 4);
    }

    @Override
    public boolean isNewLine(byte[]bytes, int p, int end) {
        if (p + 3 < end) {
            if (bytes[p + 3] == 0 && bytes[p + 2] == 0 && bytes[p + 1] == 0 && bytes[p] == (byte)0x0a) return true;

            if (Config.USE_UNICODE_ALL_LINE_TERMINATORS) {
                if (bytes[p + 3] == 0 && bytes[p + 2] == 0 && bytes[p + 1] == 0 &&
                    (bytes[p] == (byte)0x0b || bytes[p] == (byte)0x0c || bytes[p] == (byte)0x0d || bytes[p] == (byte)0x85)) return true;

                if (bytes[p + 3] == 0 && bytes[p + 2] == 0 && bytes[p + 1] == (byte)0x20 &&
                   (bytes[p] == (byte)0x29 || bytes[p] == (byte)0x28)) return true;
            } // USE_UNICODE_ALL_LINE_TERMINATORS
        }
        return false;
    }

    @Override
    public int mbcToCode(byte[]bytes, int p, int end) {
        return (((bytes[p + 3] & 0xff) * 256 + (bytes[p + 2] & 0xff)) * 256 + (bytes[p + 1] & 0xff)) * 256 + (bytes[p] & 0xff);
    }

    @Override
    public int codeToMbc(int code, byte[]bytes, int p) {
        int p_ = p;
        bytes[p_++] = (byte) (code & 0xff);
        bytes[p_++] = (byte)((code & 0xff00)     >>> 8);
        bytes[p_++] = (byte)((code & 0xff0000)   >>> 16);
        bytes[p_++] = (byte)((code & 0xff000000) >>> 24);
        return 4;
    }

    @Override
    public int mbcCaseFold(int flag, byte[]bytes, IntHolder pp, int end, byte[]fold) {
        int p = pp.value;
        int foldP = 0;
        if (isAscii(bytes[p] & 0xff) && bytes[p + 1] == 0 && bytes[p + 2] == 0 && bytes[p + 3] == 0) {

            if (Config.USE_UNICODE_CASE_FOLD_TURKISH_AZERI) {
                if ((flag & Config.CASE_FOLD_TURKISH_AZERI) != 0) {
                    if (bytes[p] == (byte)0x49) {
                        fold[foldP++] = (byte)0x31;
                        fold[foldP++] = (byte)0x01;
                    }
                }
            } else {
                fold[foldP++] = AsciiTables.ToLowerCaseTable[bytes[p] & 0xff];
                fold[foldP++] = 0;
            } // USE_UNICODE_CASE_FOLD_TURKISH_AZERI

            fold[foldP++] = 0;
            fold[foldP] = 0;
            pp.value += 4;
            return 4;
        } else {
            return super.mbcCaseFold(flag, bytes, pp, end, fold);
        }
    }

    public static UTF32LEEncoding INSTANCE = new UTF32LEEncoding();
}