/*
 * Copyright 1999-2017 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      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 com.alibaba.druid.sql.parser;

import static com.alibaba.druid.sql.parser.LayoutCharacters.EOI;

public class CharTypes {
    private static final boolean[] hexFlags = new boolean[256];

    static {
        for (char c = 0; c < hexFlags.length; ++c) {
            if (c >= 'A' && c <= 'F') {
                hexFlags[c] = true;
            } else if (c >= 'a' && c <= 'f') {
                hexFlags[c] = true;
            } else if (c >= '0' && c <= '9') {
                hexFlags[c] = true;
            }
        }
    }

    public static boolean isHex(char c) {
        return c < 256 && hexFlags[c];
    }

    public static boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }

    private static final boolean[] firstIdentifierFlags = new boolean[256];
    private static final boolean[] UNDERSCORE_LETTERS = new boolean[256];

    static {
        // the Latin letter decimal values range between 192('À') and 255('ÿ') but exclude 215('×') and 247('÷').
        for (char c = 0; c < firstIdentifierFlags.length; ++c) {
            if ((c >= 'A' && c <= 'Z')
                    || (c >= 'a' && c <= 'z')
                    || (c >= 'À' && c <= 'ÿ' && c != '×' && c != '÷')) {
                firstIdentifierFlags[c] = true;
            }
        }
        firstIdentifierFlags['`'] = true;
        firstIdentifierFlags['_'] = true;
        firstIdentifierFlags['$'] = true;

        for (char c = 'A'; c <= 'Z'; ++c) {
            UNDERSCORE_LETTERS[c] = true;
        }
        for (char c = 'a'; c <= 'z'; ++c) {
            UNDERSCORE_LETTERS[c] = true;
        }
        UNDERSCORE_LETTERS['_'] = true;
    }

    public static boolean letterOrUnderScore(char c) {
        return (c & ~0xFF) == 0 && UNDERSCORE_LETTERS[c & 0xFF];
    }

    public static boolean isFirstIdentifierChar(char c) {
        if (c <= firstIdentifierFlags.length) {
            return firstIdentifierFlags[c];
        }
        return c != '　' && c != '，';
    }

    private static final String[] stringCache = new String[256];
    private static final boolean[] identifierFlags = new boolean[256];

    static {
        for (char c = 0; c < identifierFlags.length; ++c) {
            if (c >= 'A' && c <= 'Z') {
                identifierFlags[c] = true;
            } else if (c >= 'a' && c <= 'z') {
                identifierFlags[c] = true;
            } else if (c >= '0' && c <= '9') {
                identifierFlags[c] = true;
            }
        }
        // identifierFlags['`'] = true;
        identifierFlags['_'] = true;
        identifierFlags['$'] = true;
        identifierFlags['#'] = true;

        for (int i = 0; i < identifierFlags.length; i++) {
            if (identifierFlags[i]) {
                char ch = (char) i;
                stringCache[i] = Character.toString(ch);
            }
        }
    }

    public static boolean isIdentifierChar(char c) {
        if (c <= identifierFlags.length) {
            return identifierFlags[c];
        }
        return c != '　' && c != '，' && c != '）' && c != '（';
    }

    public static String valueOf(char ch) {
        if (ch < stringCache.length) {
            return stringCache[ch];
        }
        return null;
    }

    private static final boolean[] whitespaceFlags = new boolean[256];

    static {
        for (int i = 0; i <= 32; ++i) {
            whitespaceFlags[i] = true;
        }

        whitespaceFlags[EOI] = false;
        for (int i = 0x7F; i <= 0xA0; ++i) {
            whitespaceFlags[i] = true;
        }

        whitespaceFlags[160] = true; // 特别处理
//        whitespaceFlags[223] = true; // 特别处理, odps
//        whitespaceFlags[229] = true; // 特别处理, odps
//        whitespaceFlags[231] = true; // 特别处理, odps ç
    }

    /**
     * @return false if {@link LayoutCharacters#EOI}
     */
    public static boolean isWhitespace(char c) {
        return (c <= whitespaceFlags.length && whitespaceFlags[c]) //
                || c == '　'; // Chinese space
    }

    public static String trim(String value) {
        int len = value.length();
        int st = 0;

        while ((st < len) && (isWhitespace(value.charAt(st)))) {
            st++;
        }
        while ((st < len) && isWhitespace(value.charAt(len - 1))) {
            len--;
        }
        return ((st > 0) || (len < value.length())) ? value.substring(st, len) : value;
    }
}
