const ColorTool = {

    /**
     * Checks whether the color is in hex format
     *
     * @param {string} color
     * @returns {boolean}
     */
    isHex: (color) => !!color.match(/^#([a-f\d]{3}){1,2}$/i),

    /**
     * Checks whether the color is an RGB string
     *
     * @param {string} color
     * @returns {boolean}
     */
    isRgb: color => !!color.match(/^rgb\((\s?\d{1,3}\s?,?){3}\)$/i),

    /**
     * Checks whether the color is an RGBA string
     *
     * @param {string} color
     * @returns {boolean}
     */
    isRgba: color => !!color.match(/^rgba\((\s?\d{1,3}\s?,?){3}\s?[.0-9]+\)$/i),

    /**
     * Returns the colors of an RGB string as an array
     *
     * @param {string} color
     * @param {boolean} withAlpha
     * @returns {array}
     */
    splitRgb: (color, withAlpha) => {
        const matches = color.match(/^rgba?\((.*)\)/i);

        return matches[1].split(',').filter((v, i) => i < (withAlpha ? 4 : 3)).map(v => parseInt(v));
    },

    /**
     * Returns the colors and alpha level of a RGBA string as an array
     *
     * @param {string} color
     * @param {boolean} withAlpha
     * @returns {array}
     */
    splitRgba: (color) => ColorTool.splitRgb(color, true),

    /**
     * Convert a hex color to RGB
     * @see https://stackoverflow.com/a/39077686
     *
     * @param {string} hex
     * @returns {string}
     */
    hexToRgb: hex => 'rgb(' + hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (m, r, g, b) => '#' + r + r + g + g + b + b).substring(1).match(/.{2}/g).map(x => parseInt(x, 16)).join(',') + ')',

    /**
     * Convert a RGB color to hex
     * @see https://stackoverflow.com/a/13070198
     *
     * @param {string} rgb
     * @returns {string}
     */
    rgbToHex: rgb => '#' + ColorTool.splitRgb(rgb).map(value => value.toString(16)).map(value => (value.length === 1 ? '0' : '') + value).join(''),

    /**
     * Convert a RGBA color to RGB
     *
     * @param {string} rgba
     * @returns {string}
     */
    rgbaToRgb: rgba => 'rgb(' + ColorTool.splitRgb(rgba, false).join(',') + ')',

    /**
     * Returns a hex color
     *
     * @param {string} color
     * @returns {string}
     */
    toHex: color => {
        if(ColorTool.isHex(color)) {
            return color;
        }

        if(ColorTool.isRgba(color)) {
            color = ColorTool.rgbaToRgb(color);
        }

        if(ColorTool.isRgb(color)) {
            return ColorTool.rgbToHex(color);
        }
    },

    /**
     * Returns a RGB color
     *
     * @param {string} color
     * @returns {string}
     */
    toRgb: (color) => {
        if (ColorTool.isRgb(color)) {
            return color;
        }

        if (ColorTool.isRgba(color)) {
            return ColorTool.rgbaToRgb(color);
        }

        if (ColorTool.isHex(color)) {
            return ColorTool.hexToRgb(color);
        }
    },

    /**
     * Returns a RGBA color
     *
     * @param {string} color
     * @param {number} opacity
     * @returns {string}
     */
    toRgba: (color, opacity) => {
        if (ColorTool.isRgba(color)) {
            return color;
        }

        return ColorTool.setOpacity(color, opacity);
    },

    /**
     * Removes opacity from a color string
     *
     * @param {string} color
     * @returns {string}
     */
    removeOpacity: color => {
        if (ColorTool.isRgb(color)) {
            return color;
        }

        if (ColorTool.isRgba(color)) {
            return ColorTool.rgbaToRgb(color);
        }

        if(ColorTool.isHex(color)) {
            return color.substring(0, 7);
        }
    },

    /**
     * Convert a color to RGBA with an opacity
     *
     * @param {string} color
     * @param {number} opacity
     * @returns {string}
     */
    setOpacity: (color, opacity) => {
        const alpha = Math.max(0, Math.min(isNaN(opacity) ? 1 : opacity, 1));
        const rgb = ColorTool.toRgb(color);

        return 'rgba(' + ColorTool.splitRgb(rgb).join(',') + ',' + alpha + ')';
    },

    /**
     * Get the brightness of a color from 0 (#fff) to 1 (#000)
     *
     * @param {string} color
     * @returns {number}
     */
    getBrightness: color => 1 / (255 * 3) * ColorTool.splitRgb(ColorTool.toRgb(color)).reduce((a, b) => a + b, 0),

    /**
     * Get the background color of an element
     *
     * @param node
     * @returns {string}
     */
    getBackgroundColor: node => getComputedStyle(node, null).getPropertyValue('background-color')
};