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

        this.state = RM_STATE_READY;
        this.nmReelsStopped = 0;//at the end of spin, number of reels that are stopped
        this.nmReelsShowCompleted = 0;//at the start, number of reels already completed their appearance
        this.reelSpeedIndex = config.reels_speed;

        this.reelSpeed = [2.0, 2.5, 3.0];//slow, medium, fast
//        this.reelSpeed = [0.1, 0.1, 0.1];//slow, medium, fast
        this.timeToSpin = 1000;//base spin time

        this.timeToSpinExtra = [350, 300, 250];//slow, medium, fast

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

        this.scaleTimers = [];
        this.scaleTimerIndex = 0;

        this.totalWinTime = 2000;// total win scene time
        this.totalWinTimer = 0;
      
        this.scattersAnimTime = 3000;
        this.scatterAnimTimer = 0;

        this.shakeTime = 3000;
        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.lineInfo = [];
        this.currentWinLine = 0;
        
        this.scattersInfo = [];
        this.currentScatter = 0;
        
        this.rt = this.scene.add.renderTexture(0, 0 + this.vDelta, 1280, 658);

        this.reels = [];

        let reelconf = 
        {
            scene: this.scene,
            manager: this,
            target_spin_position: 0,
            reel: [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9],
            symbols: this.symbols,
            lines: this.lines,
            nm_lines: 3,
            reel_speed: this.reelSpeed[this.reelSpeedIndex],
            time_to_spin: this.timeToSpin,
            reel_back_speed:  0.8,
            time_to_spin_back:  100,
            reel_forth_speed: Math.abs(this.reelSpeed[this.reelSpeedIndex]),
            reel_stop_speed: 1.0,
            time_to_spin_stop: 70,
            extended_spin_time: 1900,
            vDelta: this.vDelta,
            rt: this.rt,
            rt_draw_y: this.vDelta,
        }            

        reelconf.id = 0;
        reelconf.target_spin_position = this.spinPositions[0];
        reelconf.reel = config.reels[0];
        reelconf.rt_draw_x = 60;
        this.reels.push(new Reel(reelconf));

        reelconf.id = 1;
        reelconf.target_spin_position = this.spinPositions[1];
        reelconf.reel = config.reels[1];
        reelconf.time_to_spin += this.timeToSpinExtra[this.reelSpeedIndex];//300;
        reelconf.rt_draw_x = 295;
        this.reels.push(new Reel(reelconf));

        reelconf.id = 2;
        reelconf.target_spin_position = this.spinPositions[2];
        reelconf.reel = config.reels[2];
        reelconf.time_to_spin += this.timeToSpinExtra[this.reelSpeedIndex];
        reelconf.rt_draw_x = 529;
        this.reels.push(new Reel(reelconf));

        reelconf.id = 3;
        reelconf.target_spin_position = this.spinPositions[3];
        reelconf.reel = config.reels[3];
        reelconf.time_to_spin += this.timeToSpinExtra[this.reelSpeedIndex];
        reelconf.rt_draw_x = 764;
        this.reels.push(new Reel(reelconf));

        reelconf.id = 4;
        reelconf.target_spin_position = this.spinPositions[4];
        reelconf.reel = config.reels[4];
        reelconf.time_to_spin += this.timeToSpinExtra[this.reelSpeedIndex];
        reelconf.rt_draw_x = 999;
        this.reels.push(new Reel(reelconf));

        this.stopBtnCanShow = true;

        this.breakPresent = false;

        this.sndSpecial = this.scene.sound.add('special');
    }
    
    update(time, delta) 
    {
        this.rt.clear();

        if(this.state == RM_STATE_TOTAL_WIN || this.state == RM_STATE_S_SCATTER_WIN)
        {
            this.reels.forEach(reel => {reel.update_symbols(time, delta);});
            this.rt.draw("overlay", 0, 0);
            this.reels.forEach(reel => {reel.update_active_symbols(time, delta);});
        }
        else
        {
            this.reels.forEach(reel => {reel.update(time, delta);});
        }

        switch (this.state)
        {
            case RM_STATE_TOTAL_WIN:
                {
                    if(this.scaleTimers[this.scaleTimerIndex] >= 0)
                    {
                        this.scaleTimers[this.scaleTimerIndex] -= delta;

                        if(this.scaleTimers[this.scaleTimerIndex] < 0 && ++this.scaleTimerIndex < this.scaleTimers.length)
                        {
                            this.reels[this.scaleTimerIndex].start_animation_scalling();
                        }
                    }                        

                    if(this.totalWinTimer >= 0)
                    {
                        this.totalWinTimer -= delta;
                        if(this.totalWinTimer < 0)
                        {
                            this.reels.forEach(reel => {reel.stop_animations();});
                            if(++this.currentWinLine >= this.lineInfo.length)
                            {
                                if(this.scattersInfo.length > 0)
                                {
                                    this.totalWinTimer = this.totalWinTime;
                                    this.currentScatter = 0;
                        
                                    this.reels.forEach(reel => {reel.create_scatter_animation(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["scatters_field"][reel.reel_id]);});
                                    this.reels.forEach(reel => {reel.play_scatter_animations(this.scattersInfo[this.currentScatter]["symbol"]);});
                                    this.reels.forEach(reel => {reel.set_state(REEL_STATE_SCATTER_WIN);});            
                        
                                    this.state = RM_STATE_S_SCATTER_WIN;
                                }
                                else
                                {    
                                    this.showTotalWinCounter();
                                }
                            }
                            else
                            {
                                this.totalWinTimer = this.totalWinTime;

                                this.reels.forEach(reel => {reel.set_winning_line(this.currentWinLine);});
                                this.reels.forEach(reel => {reel.play_line_animation();});
                                                    
                                this.scaleTimers = [200, 200, 200, 200, 200];
                                this.scaleTimerIndex = 0;
                                this.reels[0].start_animation_scalling();
                            }
                        }
                    }
                };break;
                
            case RM_STATE_S_SCATTER_WIN:
                {
                    if(this.totalWinTimer >= 0)
                    {
                        this.totalWinTimer -= delta;
                        if(this.totalWinTimer < 0)
                        {
                            if(++this.currentScatter == this.scattersInfo.length)
                            {
                                this.showTotalWinCounter();
                            }
                            else
                            {
                                this.totalWinTimer = this.totalWinTime;
                    
                                this.reels.forEach(reel => {reel.create_scatter_animation(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["scatters_field"][reel.reel_id]);});
                                this.reels.forEach(reel => {reel.play_scatter_animations(this.scattersInfo[this.currentScatter]["symbol"]);});
                            }                                    
                        }
                    }                        
                };break;
    
            case RM_STATE_PLAY_WIN_LINES:
                {
                    if(this.scaleTimers[this.scaleTimerIndex] >= 0)
                    {
                        this.scaleTimers[this.scaleTimerIndex] -= delta;

                        if(this.scaleTimers[this.scaleTimerIndex] < 0 && ++this.scaleTimerIndex < this.scaleTimers.length)
                        {
                            this.reels[this.scaleTimerIndex].start_animation_scalling();
                        }
                    }                        

                    this.winLineTimer -= delta;
                    if(this.winLineTimer < 0)
                    {
                        this.reels.forEach(reel => {reel.stop_animations();});

                        this.winLineTimer = this.winLineTime;

                        if(++this.currentWinLine >= this.lineInfo.length)
                        {
                            if(this.scattersInfo.length > 0)
                            {
                                this.scatterAnimTimer = this.scattersAnimTime;
                                this.currentScatter = 0;
                                
                                this.reels.forEach(reel => {reel.create_scatter_animation(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["scatters_field"][reel.reel_id]);});
                                this.reels.forEach(reel => {reel.play_scatter_animations(this.scattersInfo[this.currentScatter]["symbol"]);});
                                this.reels.forEach(reel => {reel.set_state(REEL_STATE_SCATTER_WIN);});
                                
                                this.scene.paytable.highlightWinSymbols(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["len"]);

                                this.state = RM_STATE_PLAY_S_SCATTERS;
                            }
                            else
                            {
                                this.currentWinLine = 0;

                                this.reels.forEach(reel => {reel.set_winning_line(this.currentWinLine);});
                                this.reels.forEach(reel => {reel.play_line_animation();});

                                this.scaleTimers = [200, 200, 200, 200, 200];
                                this.scaleTimerIndex = 0;
                                this.reels[0].start_animation_scalling();
        
                                this.scene.paytable.highlightWinSymbols(this.lineInfo[this.currentWinLine].symbol, this.lineInfo[this.currentWinLine].len);
                            }
                        }
                        else
                        {
                            this.reels.forEach(reel => {reel.set_winning_line(this.currentWinLine);});
                            this.reels.forEach(reel => {reel.play_line_animation();});

                            this.scaleTimers = [200, 200, 200, 200, 200];
                            this.scaleTimerIndex = 0;
                            this.reels[0].start_animation_scalling();
    
                            this.scene.paytable.highlightWinSymbols(this.lineInfo[this.currentWinLine].symbol, this.lineInfo[this.currentWinLine].len);
                        }
                    }                        
                };break;

            case RM_STATE_PLAY_S_SCATTERS:
                {
                    if (this.scatterAnimTimer > 0)
                    {
                        this.scatterAnimTimer -= delta;
                        if(this.scatterAnimTimer < 0)
                        {
                            if(++this.currentScatter < this.scattersInfo.length)
                            {
                                this.scatterAnimTimer = this.scattersAnimTime;
                      
                                this.reels.forEach(reel => {reel.create_scatter_animation(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["scatters_field"][reel.reel_id]);});
                                this.reels.forEach(reel => {reel.play_scatter_animations(this.scattersInfo[this.currentScatter]["symbol"]);});
                                this.scene.paytable.highlightWinSymbols(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["len"]);
                            }
                            else
                            {
                                this.reels.forEach(reel => {reel.stop_animations();});
                                this.onWin();
                            }
                        }                        
                    }    
                };break;

                case RM_STATE_SHAKE:
                    {
                        if (this.shakeTimer > 0)
                        {
                            this.shakeTimer -= delta;
                            if(this.shakeTimer < 0)
                            {
                                this.reels[2].destroy_animations();
                                this.onWinResult();
                            }                        
                        }    
                    };break;
        }
    }

    showTotalWinCounter()
    {
        this.state = RM_STATE_READY;
        this.reels.forEach(reel => {reel.set_state(REEL_STATE_STOPPED);});
        this.reels.forEach(reel => {reel.stop_animations();});
        this.scene.onShowTotalWinCounter();
    }

    onWin()
    {
        if(this.lineInfo.length > 0)
        {
            this.playWinLines();
        }
        else if(this.scattersInfo.length > 0)
        {
            this.playScatters();
        }
    }

    queryLineInfoLength()
    {
        return this.lineInfo.length;
    }

    playTotalWin()
    {
        this.reels.forEach(reel => {reel.destroy_animations();});
        
        if(this.lineInfo.length > 0)
        {
            this.reels.forEach(reel => {reel.create_line_animations();});
        }

        if(this.lineInfo.length > 0)
        {
            this.totalWinTimer = this.totalWinTime;
            this.currentWinLine = 0;
            
            this.reels.forEach(reel => {reel.set_state(REEL_STATE_TOTAL_WIN);});
            
            this.reels.forEach(reel => {reel.set_winning_line(this.currentWinLine);});
            this.reels.forEach(reel => {reel.play_line_animation();});
            
            this.scaleTimers = [200, 200, 200, 200, 200];
            this.scaleTimerIndex = 0;
            this.reels[0].start_animation_scalling();
 
            this.scene.sndWin.play();
            
            this.state = RM_STATE_TOTAL_WIN;
        }
        else if(this.scattersInfo.length > 0)
        {
            this.totalWinTimer = this.totalWinTime;
            this.currentScatter = 0;

            this.reels.forEach(reel => {reel.create_scatter_animation(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["scatters_field"][reel.reel_id]);});
            this.reels.forEach(reel => {reel.play_scatter_animations(this.scattersInfo[this.currentScatter]["symbol"]);});
            this.reels.forEach(reel => {reel.set_state(REEL_STATE_SCATTER_WIN);});            

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

    playWinLines()
    {
        this.winLineTimer = this.winLineTime;
        this.currentWinLine = 0;

        this.reels.forEach(reel => {reel.set_winning_line(this.currentWinLine);});
        this.reels.forEach(reel => {reel.set_state(REEL_STATE_PLAY_WIN_LINES);});
        this.reels.forEach(reel => {reel.play_line_animation();});

        this.scaleTimers = [200, 200, 200, 200, 200];
        this.scaleTimerIndex = 0;
        this.reels[0].start_animation_scalling();

        this.scene.paytable.highlightWinSymbols(this.lineInfo[this.currentWinLine].symbol, this.lineInfo[this.currentWinLine].len);
        
        this.state = RM_STATE_PLAY_WIN_LINES;
    }

    playScatters()
    {
        this.scatterAnimTimer = this.scattersAnimTime;
        this.currentScatter = 0;
        
        this.reels.forEach(reel => {reel.create_scatter_animation(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["scatters_field"][reel.reel_id]);});
        this.reels.forEach(reel => {reel.play_scatter_animations(this.scattersInfo[this.currentScatter]["symbol"]);});
        this.reels.forEach(reel => {reel.set_state(REEL_STATE_SCATTER_WIN);});            
        
        this.scene.paytable.highlightWinSymbols(this.scattersInfo[this.currentScatter]["symbol"], this.scattersInfo[this.currentScatter]["len"]);

        this.state = RM_STATE_PLAY_S_SCATTERS;
    }

    beginBreak()
    {
        this.shakeTimer = this.shakeTime;
        this.reels.forEach(reel => {reel.set_state(REEL_STATE_SHAKE);});
        this.reels[2].create_break_animation();
        this.reels[2].play_break_animation();
        
        this.sndSpecial.once('complete', this.onSpecialSoundComplete.bind(this));
        this.sndSpecial.play();
        
        this.state = RM_STATE_SHAKE;
    }

    onSpecialSoundComplete()
    {
        this.scene.sound.play("special_end");
    }

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

        this.nmReelsStopped = 0;
        this.stopBtnCanShow = true;
        this.state = RM_STATE_SPIN;
        this.scene.sndBackground.play();
    }

    canShowStopBtn()
    {
        if(!this.stopBtnCanShow)
        {
            return false;
        }

        this.reels.forEach(reel => {if(reel.get_state() != REEL_STATE_SPIN){return false;};});
        
        return true;
    }

    onStart()
    {
        this.state = RM_STATE_READY;
        this.reels.forEach(reel => {reel.on_start();});
        
        this.scattersInfo = [];
    }

    queryPrevReelStopped(reel_id)
    {
        return this.nmReelsStopped == reel_id;
    }

    onReelStopped(reel_id)
    {
        this.scene.onReelStopped(reel_id);

        ++this.nmReelsStopped;

        if(this.nmReelsStopped == this.reels.length)
        {
            this.scene.sndBackground.pause(false);

            if(this.breakPresent)
            {
                this.beginBreak();
            }
            else
            {
                this.onWinResult();
            }
        }
    }

    onWinResult()
    {
        let tw = this.scene.getTotalWin();

        if(tw == 0)
        {
            this.reels.forEach(reel => {reel.set_state(REEL_STATE_STOPPED);});
    
            this.state = RM_STATE_READY;
            this.scene.onReelsReady();
        }
        else
        { 
            setTimeout(this.scene.onTotalWin.bind(this.scene), 250);
        }
    }

    onShowReelsCompleted(reel_id)
    {
        if(++this.nmReelsShowCompleted == this.reels.length)
        {
            this.scene.onShowReelsCompleted();
        }
    }

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

    getState()
    {
        return this.state;
    }

    playGame(spinResult)
    {
        this.breakPresent = spinResult.break_present;
        this.scattersInfo = spinResult.scatters_info;
        this.setSymbolField(spinResult.symbol_field);
        this.setLineInfo(spinResult.line_info);
        
        this.spinReels();
    }

    setSymbolField(symbolField)
    {
        for(let i = 0; i < this.reels.length; ++i )
        {
            this.reels[i].set_spin_symbols(symbolField[i]);
        }
    }

    setLineInfo(lineInfo)
    {
        this.lineInfo = lineInfo;
        this.reels.forEach(reel => {reel.set_line_info(this.lineInfo);});
    }        

    setReelsSpeed(v)//0 slow, 1 medium, 2 fast
    {   
        if(v >= 0 && v < this.reelSpeed.length)
        {
            this.reels.forEach(reel => {reel.set_reel_speed(this.reelSpeed[v], this.timeToSpin + this.timeToSpinExtra[v] * reel.reel_id);});
        }            
    }

    onOrientationChange(v)
    {
        this.rt.clear();
        
        this.vDelta = v;

        this.rt.setPosition(this.rt.x, 0 + this.vDelta);
        this.reels.forEach(reel => {reel.set_vertical_offset(v);});
    }

    setVisible(v)
    {
        this.rt.setVisible(v);
    }

    stopReels()
    {
        this.scene.onReelEarlyStopped();
        this.scene.sndBackground.pause();
        this.scene.sndStopEarly.play();
        this.reels.forEach(reel => {reel.stop();});
    }

    hideStopBtn()
    {
        this.scene.onHideStopBtn();
        this.stopBtnCanShow = false;
    }
}    