import { ObjectExtensions } from './ObjectExtensions';

/**
 * Helper Utility for the String class
 */
export class StringExtensions {
    /**
     * Check whether a function is null or empty
     * @param stringObject The string to check.
     */
    public static isNullOrEmpty(stringObject: string): boolean {
        if (ObjectExtensions.isNullOrUndefined(stringObject)) return true;
        if (stringObject === String()) return true;
        return false;
    }
    /**
     * Check whether a function is null or consists of whitespace
     * @param stringObject The string to check.
     */
    public static isNullOrWhitespace(stringObject: string): boolean {
        if (ObjectExtensions.isNullOrUndefined(stringObject)) return true;
        return StringExtensions.isNullOrEmpty(stringObject
            .toString() // <- Failsafe incase it's not a string
            .trim());
    }
    /**
     * Check whether a string starts with a certain character
     * @param stringObject The string to check.
     * @param characters The characters to check.
     */
    public static startsWith(stringObject: string, characters: string): boolean {
        if (StringExtensions.isNullOrWhitespace(stringObject)) return false;
        if (StringExtensions.isNullOrWhitespace(characters)) return false;
        return stringObject.substr(0, characters.length) === characters;
    }
    /**
     * Check whether a string ends with a certain character
     * @param stringObject The string to check.
     * @param characters The characters to check.
     */
    public static endsWith(stringObject: string, characters: string): boolean {
        if (StringExtensions.isNullOrWhitespace(stringObject)) return false;
        if (StringExtensions.isNullOrWhitespace(characters)) return false;
        return stringObject.substring(stringObject.length - characters.length) === characters;
    }
    /**
     * Trim the given character at the start of the string
     * @param stringObject The string to trim.
     * @param characters (optional) The characters to trim.
     */
    public static trimStartCharacters(stringObject: string, characters?: string): string {
        /* istanbul ignore next */
        if (StringExtensions.isNullOrWhitespace(stringObject))
            throw new ReferenceError(`The parameter stringObject is required`);
        if (StringExtensions.isNullOrWhitespace(characters))
            characters = ' ';

        return stringObject
            .replace(new RegExp(`^${characters}*`, 'gmi'), String());
    }
    /**
     * Trim the given character at the end of the string
     * @param stringObject The string to trim.
     * @param characters (optional) The characters to trim.
     */
    public static trimEndCharacters(stringObject: string, characters?: string): string {
        /* istanbul ignore next */
        if (StringExtensions.isNullOrWhitespace(stringObject))
            throw new ReferenceError(`The parameter stringObject is required`);
        if (StringExtensions.isNullOrWhitespace(characters))
            characters = ' ';

        return stringObject
            .replace(new RegExp(`${characters}*$`, 'gmi'), String());
    }
    /**
     * Trim the given character at the start and end of the string
     * @param stringObject The string to trim.
     * @param characters (optional) The characters to trim.
     */
    public static trimCharacters(stringObject: string, characters?: string): string {
        /* istanbul ignore next */
        if (StringExtensions.isNullOrWhitespace(stringObject))
            throw new ReferenceError(`The parameter stringObject is required`);
        if (StringExtensions.isNullOrWhitespace(characters))
            return stringObject.trim();

        stringObject = StringExtensions.trimStartCharacters(stringObject, characters);
        stringObject = StringExtensions.trimEndCharacters(stringObject, characters);
        return stringObject;
    }
}

/* istanbul ignore start */

/**
 * Interface to allow extension code completion
 */
export interface String {
    /**
     * Check whether a function is null or empty
     */
    isNullOrEmpty(): boolean;
    /**
     * Check whether a function is null or consists of whitespace
     */
    isNullOrWhitespace(): boolean;
    /**
     * Check whether a string starts with a certain character
     * @param startChar The character to check.
     */
    startsWith(startChar: string): boolean;
    /**
     * Check whether a string ends with a certain character
     * @param character The character to check.
     */
    endsWith(character: string): boolean;
    /**
     * Trim the given character at the start of the string
     * @param character The character to trim.
     */
    trimStartCharacters(character: string): string;
    /**
     * Trim the given character at the end of the string
     * @param character The character to trim.
     */
    trimEndCharacters(character: string): string;
    /**
     * Trim the given character at the start and end of the string
     * @param character The character to trim.
     */
    trimCharacters(character: string): string;
}

export default StringExtensions;

/* istanbul ignore next */
/**
 * Apply extensions to the String interface
 */
// tslint:disable-next-line:no-unused-expression
!function applyStringExtensions(): void
{
    Object.prototype['isNullOrEmpty'] = () => StringExtensions.isNullOrEmpty(this);
    Object.prototype['isNullOrWhitespace'] = () => StringExtensions.isNullOrWhitespace(this);
    Object.prototype['startsWith'] = (startChar) =>
        StringExtensions.startsWith(this, startChar);
    Object.prototype['endsWith'] = (character) =>
        StringExtensions.endsWith(this, character);
    Object.prototype['trimStartCharacters'] = (character) =>
        StringExtensions.trimStartCharacters(this, character);
    Object.prototype['trimEndCharacters'] = (character) =>
        StringExtensions.trimEndCharacters(this, character);
    Object.prototype['trimCharacters'] = (character) =>
        StringExtensions.trimCharacters(this, character);
}();

/* istanbul ignore end */