/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */

package net.ranides.assira.text;

import lombok.experimental.UtilityClass;

/**
 * Null-safe static methods checking string content.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
@UtilityClass
public final class StringTraits {

    /**
     * Returns true if value is not empty.
     * That means: it isn't null and contains at least one character.
     *
     * @param value value
     * @return boolean
     */
    public static boolean isNotEmpty(CharSequence value) {
        return !isEmpty(value);
    }

    /**
     * Returns true if value is not blank.
     * That means: it isn't null and contains at least one non-space character.
     *
     * @param value value
     * @return boolean
     */
    public static boolean isNotBlank(CharSequence value) {
        return !isBlank(value);
    }

    /**
     * Returns true if value is empty.
     * That means: it is null or its length is zero.
     *
     * @param value value
     * @return boolean
     */
    public static boolean isEmpty(CharSequence value) {
		return null == value || 0 == value.length();
	}

    /**
     * Returns true if value is blank.
     * That means: it is null, its length is zero, or contains only white-space characters.
     *
     * @param value value
     * @return boolean
     */
	public static boolean isBlank(CharSequence value) {
		return isEmpty(value) || value.toString().trim().isEmpty();
	}

    /**
     * Returns true if value is decimal number.
     * That means: it is not empty and contains only decimal digits
     *
     * @param text text
     * @return boolean
     */
    public static boolean isNumber(CharSequence text) {
        if(isEmpty(text)) {
            return false;
        }
        for(int i=0,n=text.length(); i<n; i++) {
            if(!isNumber(text.charAt(i))) {
                return false;
            }
        }
        return true;
    }
    
    private static boolean isNumber(char c) {
        return c>='0' && c<='9';
    }

    /**
     * Returns true if text starts with prefix.
     * That means: text is not null and contains "prefix" at the very begining
     *
     * @param text text
     * @param prefix prefix
     * @return boolean
     */
    public static boolean starts(String text, String prefix) {
		return null != text && text.startsWith(prefix);
	}

    /**
     * Returns true if text ends with suffix.
     * That means: text is not null and contains "suffix" at the very end
     *
     * @param text text
     * @param suffix suffix
     * @return boolean
     */
    public static boolean ends(String text, String suffix) {
		return null != text && text.endsWith(suffix);
	}

    /**
     * Returns true if text contains character.
     *
     * @param text text
     * @param ch ch
     * @return boolean
     */
    public static boolean contains(String text, int ch) {
        return null != text && -1 != text.indexOf(ch);
    }

    /**
     * Returns true if text contains specified fragment.
     *
     * @param text text
     * @param fragment fragment
     * @return boolean
     */
    public static boolean contains(String text, String fragment) {
		return null != text && text.contains(fragment);
	}

    /**
     * Returns true if text could be used as java identifier.
     * Valid java identifiers are described in JLS Chapter 3.
     *
     * @param text text
     * @return boolean
     */
    public static boolean isJavaIdentifier(String text) {
        int cp = text.codePointAt(0);
        if (!Character.isJavaIdentifierStart(cp)) {
            return false;
        }
        for (int i = Character.charCount(cp), n = text.length(); i < n; i += Character.charCount(cp)) {
            cp = text.codePointAt(i);
            if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
                return false;
            }
        }
        return true;
    }
}
