
import Graphics from '../../graphics/Graphics';
import { WebglRenderer } from '../WebglRenderer';
import RenderTarget from '../renderTarget/RenderTarget';
import { SpriteMaskFilter } from '../../filter';

/**
 * @class
 */
export default class MaskManager {
    renderer: WebglRenderer;
    scissor: boolean;
    scissorData: any;
    scissorRenderTarget: RenderTarget;
    enableScissor: boolean;
    alphaMaskPool: any[];
    alphaMaskIndex: number;
    /**
     * - The renderer this manager works for.
     */
    constructor(renderer: WebglRenderer) {

        this.renderer = renderer

        // TODO - we don't need both!
        this.scissor = false;
        this.scissorData = null;
        this.scissorRenderTarget = null;

        this.enableScissor = true;

        this.alphaMaskPool = [];
        this.alphaMaskIndex = 0;
    }

    /**
     * Applies the Mask and adds it to the current filter stack.
     *
     * @param {DisplayObject} target - Display Object to push the mask to
     * @param {Sprite|Graphics} maskData - The masking data.
     */
    pushMask(target, maskData) {
        // TODO the root check means scissor rect will not
        // be used on render textures more info here:
        // https://github.com/pixijs/js/pull/3545

        if (maskData.texture) {
            this.pushSpriteMask(target, maskData);
        }
        else
            // if (this.enableScissor
            //     && !this.scissor
            //     && this.renderer._activeRenderTarget.root
            //     && !this.renderer.stencilManager.stencilMaskStack.length
            //     && maskData.isFastRect()) {
            //     const matrix = maskData.worldMatrix;

            //     let rot = Math.atan2(matrix.b, matrix.a);

            //     // use the nearest degree!
            //     rot = Math.round(rot * (180 / Math.PI));

            //     if (rot % 90) {
            //         this.pushStencilMask(maskData);
            //     }
            //     else {
            //         this.pushScissorMask(target, maskData);
            //     }
            // }
            // else {
            this.pushStencilMask(maskData);
        // }
    }

    /**
     * Removes the last mask from the mask stack and doesn't return it.
     *
     * @param {DisplayObject} target - Display Object to pop the mask from
     * @param {Sprite|Graphics} maskData - The masking data.
     */
    popMask(target, maskData) {
        if (maskData.texture) {
            this.popSpriteMask();
        }
        else
            // if (this.enableScissor && !this.renderer.stencilManager.stencilMaskStack.length) {
            //     this.popScissorMask();
            // }
            // else {
            this.popStencilMask();
        // }
    }

    /**
     * Applies the Mask and adds it to the current filter stack.
     *
     * @param {PIXI.RenderTarget} target - Display Object to push the sprite mask to
     * @param {PIXI.Sprite} maskData - Sprite to be used as the mask
     */
    private pushSpriteMask(target, maskData) {
        let alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex];

        if (!alphaMaskFilter) {
            alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex] = [new SpriteMaskFilter(maskData)];
        }

        alphaMaskFilter[0].resolution = 1;
        alphaMaskFilter[0].maskSprite = maskData;

        // TODO - may cause issues!
        // target.filterArea = maskData.getBounds(true);

        this.renderer.filterManager.pushFilter(target, alphaMaskFilter);

        this.alphaMaskIndex++;
    }

    /**
     * Removes the last filter from the filter stack and doesn't return it.
     *
     */
    private popSpriteMask() {
        this.renderer.filterManager.popFilter();
        this.alphaMaskIndex--;
    }

    /**
     * Applies the Mask and adds it to the current filter stack.
     *
     * @param {Graphics} maskData - The masking data.
     */
    private pushStencilMask(maskData: Graphics) {
        this.renderer.batchManager.flush();
        this.renderer.stencilManager.pushStencil(maskData);
    }

    /**
     * Removes the last filter from the filter stack and doesn't return it.
     *
     */
    private popStencilMask() {
        this.renderer.stencilManager.popStencil();
    }

    /**
     * 有bug暂不用
     * @param {DisplayObject} target - Display Object to push the mask to
     * @param {Graphics} maskData - The masking data.
     */
    pushScissorMask(target, maskData: Graphics) {
        maskData.renderable = true;

        const renderTarget = this.renderer._activeRenderTarget;

        const bounds = maskData.getBounds();

        bounds.fit(renderTarget.size);
        maskData.renderable = false;

        this.renderer.gl.enable(this.renderer.gl.SCISSOR_TEST);

        this.renderer.gl.scissor(
            bounds.x,
            (renderTarget.root ? renderTarget.size.height - bounds.y - bounds.height : bounds.y),
            bounds.width,
            bounds.height
        );

        this.scissorRenderTarget = renderTarget;
        this.scissorData = maskData;
        this.scissor = true;
    }

    /**
     *有bug暂不用
     *
     */
    private popScissorMask() {
        this.scissorRenderTarget = null;
        this.scissorData = null;
        this.scissor = false;

        // must be scissor!
        const gl = this.renderer.gl;

        gl.disable(gl.SCISSOR_TEST);
    }

    destroy() {
        this.renderer = null
    }
}
