import { mapWebGLBlendModes } from '../../utils';

const BLEND = 0;
const DEPTH_TEST = 1;
const FRONT_FACE = 2;
const CULL_FACE = 3;
const BLEND_FUNC = 4;

/**
 * A WebGL state machines
 * 状态机管理类
 * @class
 */
export default class WebGLState {
    blendModes
    /**
     * The current active state
     *
     */
    activeState: Uint8Array;
    /**
     * The default state
     *
     */
    defaultState: Uint8Array;

    gl: any;
    maxAttribs: any;
    attribState: { tempAttribState: any[]; attribState: any[]; };
    nativeVaoExtension: any;
    /**
     * @param {WebGLRenderingContext} gl - The current WebGL rendering context
     */
    constructor(gl: WebGLRenderingContext) {

        this.activeState = new Uint8Array(16);


        this.defaultState = new Uint8Array(16);

        // default blend mode..暂时不用混色
        this.defaultState[0] = 1;

        this.gl = gl;

        this.maxAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);

        this.attribState = {
            tempAttribState: new Array(this.maxAttribs),
            attribState: new Array(this.maxAttribs),
        };

        this.blendModes = mapWebGLBlendModes(gl);

        // check we have vao..
        this.nativeVaoExtension = (
            gl.getExtension('OES_vertex_array_object')
            || gl.getExtension('MOZ_OES_vertex_array_object')
            || gl.getExtension('WEBKIT_OES_vertex_array_object')
        );
    }

    /**
     * Sets the current state
     *
     * @param {*} state - The state to set.
     */
    setState(state) {
        this.setBlend(state[BLEND]);
        this.setDepthTest(state[DEPTH_TEST]);
        this.setFrontFace(state[FRONT_FACE]);
        this.setCullFace(state[CULL_FACE]);
        this.setBlendMode(state[BLEND_FUNC]);
    }

    /**
     * Enables or disabled blending.
     *
     * @param {boolean} value - Turn on or off webgl blending.
     */
    setBlend(value) {
        value = value ? 1 : 0;

        if (this.activeState[BLEND] === value) {
            return;
        }

        this.activeState[BLEND] = value;
        this.gl[value ? 'enable' : 'disable'](this.gl.BLEND);
    }

    /**
     * Sets the blend mode.
     *
     * @param {number} value - The blend mode to set to.
     */
    setBlendMode(value) {
        if (value === this.activeState[BLEND_FUNC]) {
            return;
        }

        this.activeState[BLEND_FUNC] = value;

        const mode = this.blendModes[value];

        if (mode.length === 2) {
            this.gl.blendFunc(mode[0], mode[1]);
        }
        else {
            this.gl.blendFuncSeparate(mode[0], mode[1], mode[2], mode[3]);
        }
    }

    /**
     * Sets whether to enable or disable depth test.
     *
     * @param {boolean} value - Turn on or off webgl depth testing.
     */
    setDepthTest(value) {
        value = value ? 1 : 0;

        if (this.activeState[DEPTH_TEST] === value) {
            return;
        }

        this.activeState[DEPTH_TEST] = value;
        this.gl[value ? 'enable' : 'disable'](this.gl.DEPTH_TEST);
    }

    /**
     * 设置是否开启剔除功能
     * @param {boolean} value - Turn on or off webgl cull face.
     */
    setCullFace(value) {
        value = value ? 1 : 0;

        if (this.activeState[CULL_FACE] === value) {
            return;
        }

        this.activeState[CULL_FACE] = value;
        this.gl[value ? 'enable' : 'disable'](this.gl.CULL_FACE);
    }

    /**
     * 设置剔除的面，基本不设置，因为设置正方面就行setFrontFace
     * gl.FRONT  
     * gl.BACK 默认
     * gl.FRONT_AND_BACK
     */
    // setCullSide(value){
    //     value = value ? 1 : 0;
    // }
    
    /**
     * 设置gl的正面的绘制顺序，
     * @param {boolean} value - true是顺时针，false是逆时针
     */
    setFrontFace(value) {
        value = value ? 1 : 0;

        if (this.activeState[FRONT_FACE] === value) {
            return;
        }

        this.activeState[FRONT_FACE] = value;
        this.gl.frontFace(this.gl[value ? 'CW' : 'CCW']);
    }

    /**
     * Disables all the vaos in use
     *
     */
    resetAttributes() {
        for (let i = 0; i < this.attribState.tempAttribState.length; i++) {
            this.attribState.tempAttribState[i] = 0;
        }

        for (let i = 0; i < this.attribState.attribState.length; i++) {
            this.attribState.attribState[i] = 0;
        }

        // im going to assume one is always active for performance reasons.
        for (let i = 1; i < this.maxAttribs; i++) {
            this.gl.disableVertexAttribArray(i);
        }
    }

    // used
    /**
     * Resets all the logic and disables the vaos
     */
    resetToDefault() {
        // unbind any VAO if they exist..
        if (this.nativeVaoExtension) {
            this.nativeVaoExtension.bindVertexArrayOES(null);
        }

        // reset all attributes..
        this.resetAttributes();

        // set active state so we can force overrides of gl state
        for (let i = 0; i < this.activeState.length; ++i) {
            this.activeState[i] = 32;
        }

        this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);

        this.setState(this.defaultState);

    }

    /**
     * 
     */
    resetTo3D() {
        //允许深度检测
        this.setDepthTest(1);
        //设置逆时针为正面
        this.setFrontFace(0);
        //设置剔除
        this.setCullFace(1);
    }


}
