class ReelManager
{
    constructor (config)
    {
        this.parentScene = config.scene;
        this.lines = config.lines;

        this.reelPanel = this.parentScene.add.image(0, 0, "bgrreels").setDepth(PANEL_DEPTH);

        this.reelBack = this.parentScene.add.image(0, 0, "backreels").setDepth(PANEL_BACK_DEPTH);

        this.nmReelsStopped = 0;//at the end of spin, number of reels that are stopped

        this.extraSpinTime = 335;

        this.winLineTime = 3000;
        this.winLineTimer = 0;

        this.winTime = 2000;// total win scene time
        this.winTimer = 0;
      
        this.scattersAnimTime = 3000;
        this.scatterAnimTimer = 0;

        this.shakeTime = 3400;
        this.shakeTimer = 0;
        
        this.spinPositions = [];

        for (let i = 0; i < config.reels.length; ++i )
        {
            let pos = (Math.floor(Math.random() * (config.reels[i].length)));
            this.spinPositions.push(pos);
        }
       
        this.winLines = [];
        this.winLine = 0;
        
        this.reels = [];

        let reelconf = 
        {
            scene: this.parentScene,
            rm: this,
            lines: this.lines,

            duration: 50,
            backDuration: 280,
            backEase: "Quart.easeOut",
            
            spinTime: REEL_SPIN_DURATION + this.parentScene.gameSocket.getExtraStartSpinTime()//max spin time
        }            

        reelconf.reelId = 0;
        reelconf.reelPosition = this.spinPositions[0];
        reelconf.reel = config.reels[0];

        reelconf.containerX = 533;
        reelconf.containerY = 782;

        this.reels.push(new Reel(reelconf));

        reelconf.reelId = 1;
        reelconf.reelPosition = this.spinPositions[1];
        reelconf.reel = config.reels[1];
        reelconf.spinTime += this.extraSpinTime;

        reelconf.containerX = 746;
        reelconf.containerY = 782;

        this.reels.push(new Reel(reelconf));

        reelconf.reelId = 2;
        reelconf.reelPosition = this.spinPositions[2];
        reelconf.reel = config.reels[2];
        reelconf.spinTime += this.extraSpinTime;

        reelconf.containerX = 961;
        reelconf.containerY = 782;

        this.reels.push(new Reel(reelconf));

        reelconf.reelId = 3;
        reelconf.reelPosition = this.spinPositions[3];
        reelconf.reel = config.reels[3];
        reelconf.spinTime += this.extraSpinTime;

        reelconf.containerX = 1175;
        reelconf.containerY = 782;

        this.reels.push(new Reel(reelconf));

        reelconf.reelId = 4;
        reelconf.reelPosition = this.spinPositions[4];
        reelconf.reel = config.reels[4];
        reelconf.spinTime += this.extraSpinTime;

        reelconf.containerX = 1389;
        reelconf.containerY = 782;

        this.reels.push(new Reel(reelconf));

        this.animationsComplete = 0;
        this.animationsTotal = 0;

        this.canShowStopBtn = true;

        this.spinResult = null;

        this.groupedSymbols = [];

        this.cs = 0;
    }

    update (time, delta) 
    {
        this.reels.forEach(reel => {reel.update(time, delta);});

        switch (this.state)
        {
            case RM_STATE_TOTAL_WIN:
                {
                    if (this.winTimer >= 0)
                    {
                        this.winTimer -= delta;
                        
                        if (this.winTimer < 0)
                        {
                            this.reels.forEach(reel => {reel.stopAnimations();});

                            if (this.spinResult.scattersInfo.length > 0)
                            {
                                this.winTimer = this.winTime;

                                this.animationsTotal = 0;

                                for (this.cs = 0; this.cs < this.spinResult.scattersInfo.length; ++this.cs)
                                {
                                    for (let i = 0; i < this.reels.length; ++i)
                                    {
                                        this.animationsTotal += this.reels[i].playScatterAnimation(this.spinResult.scattersInfo[this.cs].symbol);
                                    }
                                }
                    
                                this.state = RM_STATE_S_SCATTER_WIN;
                            }
                        }
                    }
                };break;
            case RM_STATE_S_SCATTER_WIN:
                {
                    if (this.winTimer >= 0)
                    {
                        this.winTimer -= delta;
                        
                        if (this.winTimer < 0)
                        {
                            this.reels.forEach(reel => {reel.stopAnimations();});
                        }
                    }
                };break;
    
            case RM_STATE_PLAY_WIN:
                {
                    this.winLineTimer -= delta;
                    
                    if (this.winLineTimer < 0)
                    {
                        this.winLineTimer = this.winLineTime;

                        if (++this.winLine >= this.winLines.length)
                        {
                            if (this.spinResult.scattersInfo.length > 0)
                            {
                                this.playScatters();
                                
                                return;
                            }
                            else
                            {
                                this.winLine = 0;

                                this.reels.forEach(reel => {reel.stopAnimations();});
                            }
                        }

                        this.reels.forEach(reel => {reel.setWinLine(this.winLine);});
                        this.reels.forEach(reel => {reel.playLineAnimation();});
                        
                        this.parentScene.txtWin.setText(this.parentScene.getText(GLOBAL_TXT_LINE) + " " + (this.spinResult.winLines[this.winLine].id + 1) + " " + this.parentScene.getText(GLOBAL_TXT_PAYS) + " " + this.getLineWin());
                    }                        
                };break;

            case RM_STATE_PLAY_S_SCATTERS:
                {
                    if (this.scatterAnimTimer > 0)
                    {
                        this.scatterAnimTimer -= delta;
                        
                        if (this.scatterAnimTimer < 0)
                        {
                            if (++this.cs == this.spinResult.scattersInfo.length)
                            {
                                if (this.winLines.length > 0)
                                {
                                    this.playWinLines();
                                }
                                else if (this.spinResult.scattersInfo.length > 0)
                                {
                                    this.playScatters();
                                }
                            }
                            else
                            {
                                this.scatterAnimTimer = this.scattersAnimTime;

                                this.reels.forEach(reel => {reel.stopAnimations();});
                
                                this.animationsTotal = 0;

                                for (let i = 0; i < this.reels.length; ++i)
                                {
                                    this.animationsTotal += this.reels[i].playScatterAnimation(this.spinResult.scattersInfo[this.cs].symbol);
                                }
        
                                this.parentScene.txtWin.setText(this.parentScene.getText(GLOBAL_TXT_SCATTER_PAYS) + " " + formatValue(this.spinResult.scattersInfo[this.cs].win, this.parentScene.currencyPrecision));
                            }
                        }
                    }    
                };break;
            
            case RM_STATE_SHAKE:
                {
                    if (this.shakeTimer > 0) 
                    {
                        this.shakeTimer -= delta;

                        if (this.shakeTimer <= 0) 
                        {
                            this.parentScene.time.delayedCall(2000, () => 
                            {
                                this.reels[2].sprites.forEach(sprite => 
                                {
                                    if (sprite.getTextureKey() == "break") 
                                    {
                                        sprite.anims.stop();   
                                        sprite.setFrame(0);     
                                        this.parentScene.tweens.killTweensOf(sprite); 
                                    }
                                });
                            });
                            
                            this.processWin(); 
                        }
                    }
                    break;
                }
        }
    }

    showWinCounter ()
    {
        this.parentScene.tw.setDisplayWinCombinations(false);
        this.parentScene.tw.setWin(this.parentScene.getTotalWin());
    }

    showWins ()
    {
        this.parentScene.txtWin.setVisible(true);

        if (this.winLines.length > 0)
        {
            this.playWinLines();
        }
        else if (this.spinResult.scattersInfo.length > 0)
        {
            this.playScatters();
        }
    }

    playTotalWin ()
    {
        this.reels.forEach(reel => {reel.destroyAnimations();});

        if (this.winLines.length > 0)
        {
            this.reels.forEach(reel => {reel.createLineAnimations();});
        }

        if (this.spinResult.scattersInfo.length > 0)
        {
            for (let i = 0; i < this.spinResult.scattersInfo.length; ++i)
            {
                this.reels.forEach(reel => {reel.createScatterAnimation(this.spinResult.scattersInfo[i].symbol, this.spinResult.scattersInfo[i].scattersField[reel.reelId]);});
            }
        }

        if (this.winLines.length > 0)
        {
            this.winTimer = this.winTime;

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

                v.push(this.groupedSymbols[0].mask[0][i]);
                v.push(this.groupedSymbols[0].mask[1][i]);
                v.push(this.groupedSymbols[0].mask[2][i]);

                this.reels[i].setWinGroup(v);
                this.animationsTotal += this.reels[i].playGroupAnimations();
            }
 
            this.parentScene.sndWin.play();
            
            this.state = RM_STATE_TOTAL_WIN;
        }
        else if (this.spinResult.scattersInfo.length > 0)//scatters
        {
            this.winTimer = this.winTime;

            for (this.cs = 0; this.cs < this.spinResult.scattersInfo.length; ++this.cs)
            {
                for (let i = 0; i < this.reels.length; ++i)
                {
                    this.animationsTotal += this.reels[i].playScatterAnimation(this.spinResult.scattersInfo[this.cs].symbol);
                }
            }

            this.parentScene.sndWin.play();
            
            this.state = RM_STATE_S_SCATTER_WIN;
        }

        this.showWinCounter();
    }

    playWinLines ()
    {
        this.reels.forEach(reel => { reel.stopAnimations(); });

        this.winLineTimer = this.winLineTime;
        this.winLine = 0;

        this.reels.forEach(reel => {reel.setWinLine(this.winLine);});
        this.reels.forEach(reel => {reel.playLineAnimation();});

        this.parentScene.txtWin.setText(this.parentScene.getText(GLOBAL_TXT_LINE) + " " + (this.winLines[this.winLine].id + 1) + " " + this.parentScene.getText(GLOBAL_TXT_PAYS) + " " + this.getLineWin());

        this.state = RM_STATE_PLAY_WIN;
    }

    playScatters ()
    {
        this.reels.forEach(reel => { reel.stopAnimations(); });

        this.scatterAnimTimer = this.scattersAnimTime;
        this.cs = 0;
    
        this.animationsTotal = 0;

        for (let i = 0; i < this.reels.length; ++i)
        {
            this.animationsTotal += this.reels[i].playScatterAnimation(this.spinResult.scattersInfo[this.cs].symbol);
        }

        this.parentScene.txtWin.setText(this.parentScene.getText(GLOBAL_TXT_SCATTER_PAYS) + " " + formatValue(this.spinResult.scattersInfo[this.cs].win, this.parentScene.currencyPrecision));

        this.state = RM_STATE_PLAY_S_SCATTERS;
    }

    beginSpinReels ()
    {
        this.parentScene.txtWin.setVisible(false);

        this.nmReelsStopped = 0;
        this.canShowStopBtn = true;

        this.animationsTotal = 0;
        this.animationsComplete = 0;

        if (!this.parentScene.isFastSpin())
        {
            this.parentScene.sndBackground.play();
        }

        this.reels.forEach(reel => {reel.beginSpin();});

        this.state = RM_STATE_SPIN;
    }

    spinReels ()
    {
        if (this.parentScene.isFastSpin())
        {
            this.reels.forEach(reel => { reel.fastSpin(); });
        }
        else
        {
            this.reels.forEach(reel => {reel.normalSpin();});
        }
    }

    reelStopped (reelId)
    {
        this.parentScene.reelStopped();

        if (this.reels[reelId].state == REEL_STATE_STOPPED && ++this.nmReelsStopped == this.reels.length)
        {
            if (this.parentScene.gameState == GAME_STATE_ERROR && this.parentScene.betlimit.scene.isVisible())
            {
                return;
            }

            if (this.spinResult.breakPresent)
            {
                this.beginBreak();
            }
            else
            {
                this.processWin();
            }
        }
    }

    beginBreak () 
    {
        this.reels[2].playBreakAnim();

        this.shakeTimer = this.shakeTime;

        this.reels.forEach(reel => 
        {
            reel.sprites.forEach(symbol => 
            {
                symbol.playShakeAnimation();
            });
        });

        this.parentScene.time.delayedCall(10 , () => 
        {
            this.parentScene.shatter.wake();
        });

        this.state = RM_STATE_SHAKE;
    }

    processWin ()
    {
        this.parentScene.sndBackground.pause(false);

        let tw = this.parentScene.getTotalWin();

        if (tw == 0)
        {
            this.parentScene.onReelsReady();
        }
        else
        { 
            this.parentScene.time.delayedCall(250, this.parentScene.onTotalWin, [], this.parentScene);
        }
    }

    setState (state)
    {
        this.state = state;
    }

    getState ()
    {
        return this.state;
    }

    playGame (spinResult)
    {
        this.spinResult = spinResult;

        this.reels.forEach((reel, i) => {reel.setSymbolField(spinResult.symbolField[i]);});

        this.winLines = spinResult.winLines;
        this.winLine = 0;

        this.reels.forEach(reel => {reel.setWinLines(this.winLines);});

        this.groupedSymbols = [];

        for (let i = 0; i < this.winLines.length; ++i)
        {
            if (this.groupedSymbols.length == 0)
            {
                let e = {};
                e.symbol = [];
                e.mask = [];
                
                e.mask.push([0, 0, 0, 0, 0]);
                e.mask.push([0, 0, 0, 0, 0]);
                e.mask.push([0, 0, 0, 0, 0]);
    
                this.groupedSymbols.push(e);
            }

            let lineid = this.winLines[i].id;
            let len = this.winLines[i].len;

            for (let j = 0; j < len; ++j)
            {
                let v = this.lines[lineid][j];

                switch(v)
                {
                    case -1: {this.groupedSymbols[0].mask[0][j] = 1;};break;
                    case 0: {this.groupedSymbols[0].mask[1][j] = 1;};break;
                    case 1: {this.groupedSymbols[0].mask[2][j] = 1;};break;
                }
            }
        }

        this.reels.forEach((reel, i) => {reel.setSpinTime(this.parentScene.responseTime, i * this.extraSpinTime);});
        
        this.spinReels();
    }

    onOrientationChange ()
    {
        if (this.parentScene.isLandscapeMode())
        {
            this.reelPanel.setPosition(960, 618);
            this.reelBack.setPosition(960, 591);
            this.parentScene.shatter.image.setPosition(966, 590);
        }
        else
        {
            this.reelPanel.setPosition(540, 954);
            this.reelBack.setPosition(540, 927);
            this.parentScene.shatter.image.setPosition(545, 930);
        }

        this.reels.forEach(reel => {reel.onOrientationChange();});
    }

    setVisible (v)
    {
        this.reelPanel.setVisible(v);
        this.reelBack.setVisible(v);

        this.reels.forEach(reel => {reel.setVisible(v);});
    }

    stopReels ()
    {
        this.parentScene.sndBackground.pause(false);

        this.parentScene.onFastStop();

        this.reels.forEach(reel => {reel.stop();});
    }

    errStopReels ()
    {
        this.reels.forEach(reel => {reel.errStop();});
    }

    hideStopBtn ()
    {
        if (this.parentScene.stopBtn.scene.isVisible() && !this.parentScene.spinHoldActive)
        {
            this.parentScene.stopBtn.sleep(true);
        }

        this.canShowStopBtn = false;
    }

    getLineWin ()
    {
        return formatValue(this.parentScene.gameSocket.getUnits() * this.parentScene.gameSocket.getBetPerLine() * this.winLines[this.winLine].win, this.parentScene.currencyPrecision);
    }
    
    animationComplete ()
    {
        if (this.state == RM_STATE_TOTAL_WIN  || this.state == RM_STATE_S_SCATTER_WIN || this.state == RM_STATE_PLAY_S_SCATTERS)
        {
            if (++this.animationsComplete == this.animationsTotal)
            {
                for (let i = 0; i < this.reels.length; ++i)
                {
                    this.reels[i].resetSymbolsZOrder();
                    this.animationsComplete = 0;
                }
            }
        }
        else if (this.state == RM_STATE_PLAY_WIN)
        {
            if (++this.animationsComplete == this.winLines[this.winLine].len)
            {
                for (let i = 0; i < this.reels.length; ++i)
                {
                    this.reels[i].resetSymbolsZOrder();
                    this.animationsComplete = 0;
                }
            }
        }
    }
}    