import Filter from "../Filter";
import { defaultVert } from "../defaultVerts";

const adjustmentFrag = [
    "precision mediump float;",
    'varying vec2 vTextureCoord;',
    'uniform sampler2D uSampler;',

    'uniform float gamma;',
    'uniform float contrast;',
    'uniform float saturation;',
    'uniform float brightness;',
    'uniform float red;',
    'uniform float green;',
    'uniform float blue;',
    'uniform float alpha;',

    'void main(void)',
    '{',
    'vec4 c = texture2D(uSampler, vTextureCoord);',

    'if (c.a > 0.0) {',
    'c.rgb /= c.a;',

    'vec3 rgb = pow(c.rgb, vec3(1. / gamma));',
    'rgb = mix(vec3(.5), mix(vec3(dot(vec3(.2125, .7154, .0721), rgb)), rgb, saturation), contrast);',
    'rgb.r *= red;',
    'rgb.g *= green;',
    'rgb.b *= blue;',
    'c.rgb = rgb * brightness;',

    'c.rgb *= c.a;',
    '}',

    'gl_FragColor = c * alpha;',
    '}'

].join("\n")

interface OptionsInt {
    gamma?: number;
    saturation?: number;
    contrast?: number;
    brightness?: number;
    red?: number;
    green?: number;
    blue?: number;
    alpha?: number;
}
/**
 * 
 * @param {object} [options] - The optional parameters of the filter.
 * @param {number} [options.gamma=1] - The amount of luminance
 * @param {number} [options.saturation=1] - The amount of color saturation
 * @param {number} [options.contrast=1] - The amount of contrast
 * @param {number} [options.brightness=1] - The overall brightness
 * @param {number} [options.red=1] - The multipled red channel
 * @param {number} [options.green=1] - The multipled green channel
 * @param {number} [options.blue=1] - The multipled blue channel
 * @param {number} [options.alpha=1] - The overall alpha amount
 */
export class AdjustmentFilter extends Filter {
    /**
     * The amount of luminance
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    gamma: number = 1;
    /**
     * The amount of saturation
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    saturation: number = 1;
    /**
     * The amount of contrast
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    contrast: number = 1;
    /**
     * The amount of brightness
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    brightness: number = 1;
    /**
     * The amount of red channel
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    red: number = 1;
    /**
     * The amount of green channel
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    green: number = 1;
    /**
     * The amount of blue channel
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    blue: number = 1;
    /**
     * The amount of alpha channel
     * @member {number}
     * @memberof filters.AdjustmentFilter#
     * @default 1
     */
    alpha: number = 1;
    constructor(options?: OptionsInt) {
        super(defaultVert, adjustmentFrag);
        if (typeof options == "object") {
            Object.keys(options).forEach(e => { this[e] = options[e]; });
        }
    }

    /**
     * Override existing apply method in Filter
     * @private
     */
    apply(filterManager, input, output, clear) {
        this.uniforms.gamma = Math.max(this.gamma, 0.0001);
        this.uniforms.saturation = this.saturation;
        this.uniforms.contrast = this.contrast;
        this.uniforms.brightness = this.brightness;
        this.uniforms.red = this.red;
        this.uniforms.green = this.green;
        this.uniforms.blue = this.blue;
        this.uniforms.alpha = this.alpha;

        filterManager.applyFilter(this, input, output, clear);
    }
}

