class Car
{
    static WIDTH = 50;
    static HEIGHT = 70;
    static MAX_SPEED = 500;
    static RANGE = 30;
    static ACCELERATION = 300;
    static CAPACITY = 3;
    static MIN_DRIFTING_SPEED = 400;

    constructor( engine , map )
    {
        this.engine = engine;
        this.map = map;
        this.x = 0;
        this.y = 0;
        this.angle = 0;
        this.steeringAngle = Math.PI/100;
        this.driftingAngleOffset = 0;
        this.speed = 0;
        this.keys = {
            forward: false,
            backward: false,
            left: false,
            right: false,
            handbrake: false
        };
        this.quad = new Sparrow.Quad( this.engine , -Car.WIDTH/2 , -Car.HEIGHT/2 , Car.WIDTH , Car.HEIGHT , { file: "img/rover_empty.png" , filter: this.engine.gl.NEAREST } );
        this.wheelQuad = new Sparrow.Quad( this.engine , -Car.WIDTH/2 , -Car.HEIGHT/2 , Car.WIDTH , Car.HEIGHT , { file: "img/rover_wheels.png" , filter: this.engine.gl.NEAREST } );
        this.M_translation = new mat4();
        this.M_translation.data[12] = this.x;
        this.M_translation.data[13] = this.y;
        this.M_rotation = mat4.createRotationZ( this.angle );
        this.M_wheelTranslation = new mat4();
        this.M_wheelRotation = mat4.createRotationZ( this.angle );
        this.M_model = new mat4();
        this.M_markerRotation = mat4.createRotationZ( 0 );

        this.markerQuad = new Sparrow.Quad( this.engine , -5 , -70 , 10 , 10 , { file: "img/marker.png" , filter: this.engine.gl.NEAREST } );

        this.texture_empty = Sparrow.Texture.createFromFile( this.engine , "img/rover_empty.png" , "rover_empty" , { filter: this.engine.gl.NEAREST } );
        this.texture_some = Sparrow.Texture.createFromFile( this.engine , "img/rover_some.png" , "rover_some" , { filter: this.engine.gl.NEAREST } );
        this.texture_full = Sparrow.Texture.createFromFile( this.engine , "img/rover_full.png" , "rover_full" , { filter: this.engine.gl.NEAREST } );

        // this.maxSpeed = Car.MAX_SPEED;
        // this.acceleration = Car.ACCELERATION;
        // this.pickUpDistance = Car.PICKUP_DISTANCE;
        // this.numberOfCrystals = 0;
        // this.capacity = Car.CAPACITY;

        this.numberOfCrystals = 0;
        this.stats = new CarStats();

        this.camera = new Sparrow.Camera2D( engine , 0 , 0 );
        this.camera.setFocus( this.x , this.y );
        this.M_translation.data[12] = this.camera.x - this.x;
        this.M_translation.data[13] = this.camera.y - this.y;

        // this.debugText = new Sparrow.Text( this.engine , "-" , 10 , 200 );
        this.txt_maxSpeed = new Sparrow.Text( this.engine , "Max Speed: "+this.stats.maxSpeed , 5 , 5 , { font: "monospace" , color: Color4b.WHITE , size: 16 } );
        this.txt_acceleration = new Sparrow.Text( this.engine , "Acceleration: "+this.stats.acceleration , 5 , 25 , { font: "monospace" , color: Color4b.WHITE , size: 16 } );
        this.txt_pickUpDistance = new Sparrow.Text( this.engine , "Pickup Range: "+this.stats.range , 5 , 45 , { font: "monospace" , color: Color4b.WHITE , size: 16 } );
        this.txt_capacity = new Sparrow.Text( this.engine , "Capacity: "+this.stats.capacity , 5 , 65 , { font: "monospace" , color: Color4b.WHITE , size: 16 } );
        this.txt_crystals = new Sparrow.Text( this.engine , "0/"+this.stats.capacity , -16 , -60 , { font: "monospace" , color: Color4b.WHITE } );

        this.engineSound = new Audio( "sounds/engine.ogg" );
        this.engineSound.loop = true;
        this.engineSound.volume = 0;
        this.backwardsSound = new Audio( "sounds/backwards.ogg" );
        this.backwardsSound.loop = true;
        this.backwardsSound.volume = 0;
        this.pickupSound = new Audio( "sounds/pickup.wav" );
        this.unloadSound = new Audio( "sounds/unload.wav" );

        this.b_drifting = false;
        this.b_canMove = false;
    }

    start()
    {
        this.engineSound.play();
        this.backwardsSound.play();
        this.b_canMove = true;
    }

    stop()
    {
        this.engineSound.pause();
        this.backwardsSound.pause();
    }

    restart()
    {
        this.x = 0;
        this.y = 0;
        this.angle = 0;
        this.steeringAngle = Math.PI/100;
        this.driftingAngleOffset = 0;
        this.speed = 0;
        this.keys = {
            forward: false,
            backward: false,
            left: false,
            right: false,
            handbrake: false
        };
        this.M_translation = new mat4();
        this.M_translation.data[12] = this.x;
        this.M_translation.data[13] = this.y;
        this.M_rotation = mat4.createRotationZ( this.angle );
        this.M_wheelTranslation = new mat4();
        this.M_wheelRotation = mat4.createRotationZ( this.angle );
        this.M_model = new mat4();
        this.M_markerRotation = mat4.createRotationZ( 0 );
        this.numberOfCrystals = 0;
        this.stats = new CarStats();
        this.txt_maxSpeed.setStr( "Max Speed: "+this.stats.maxSpeed );
        this.txt_acceleration.setStr( "Acceleration: "+this.stats.acceleration );
        this.txt_pickUpDistance.setStr( "Pickup Range: "+this.stats.range );
        this.txt_capacity.setStr( "Capacity: "+this.stats.capacity );
        this.quad.setTexture( this.texture_empty );

        this.stop();
    }

    move( event )
    {
        // console.log( event );
        if ( event.type == "keydown" )
        {
            if ( event.code == "KeyW" || event.code == "ArrowUp" )
            {
                this.keys.forward = true;
            }
            if ( event.code == "KeyS" || event.code == "ArrowDown" )
            {
                this.keys.backward = true;
            }
            if ( event.code == "KeyA" || event.code == "ArrowLeft" )
            {
                this.keys.left = true;
            }
            if ( event.code == "KeyD" || event.code == "ArrowRight" )
            {
                this.keys.right = true;
            }
            if ( event.code == "Space" ) this.keys.handbrake = true;
        }
        else if ( event.type == "keyup" )
        {
            if ( event.code == "KeyW" || event.code == "ArrowUp" )
            {
                this.keys.forward = false;
            }
            if ( event.code == "KeyS" || event.code == "ArrowDown" )
            {
                this.keys.backward = false;
            }
            if ( event.code == "KeyA" || event.code == "ArrowLeft" )
            {
                this.keys.left = false;
            }
            if ( event.code == "KeyD" || event.code == "ArrowRight" )
            {
                this.keys.right = false;
            }
            if ( event.code == "Space" ) this.keys.handbrake = false;
            if ( event.code == "KeyE" )
            {
                if ( this.map.b_canUnload )
                {
                    this.txt_crystals.setStr( "0/"+this.stats.capacity );
                    this.map.unload();
                    this.numberOfCrystals = 0;
                    this.quad.setTexture( this.texture_empty );
                    this.unloadSound.play();
                }
            }
            if ( event.code == "KeyF" )
            {
                if ( this.map.b_canUnload )
                {
                    this.map.ui.shop.show();
                }
            }
            if ( event.code == "KeyR" )
            {
                this.map.restart();
            }
        }
    }

    update( dt )
    {
        if ( !this.b_canMove )
        {
            this.camera.setFocus( this.x , this.y );
            this.M_translation.data[12] = this.camera.x - this.x;
            this.M_translation.data[13] = this.camera.y - this.y;
            return;
        }

        var a = 0;
        if ( this.keys.forward )
        {
            a = this.stats.acceleration;
            if ( this.keys.handbrake ) a = -this.stats.acceleration*2;
        }
        else if ( this.keys.backward )
        {
            a = -this.stats.acceleration*2;
            if ( this.keys.handbrake ) a = -this.stats.acceleration*2;
        }
        else
        {
            if ( !this.keys.handbrake )
            {
                if ( Math.abs( this.speed ) > 5 ) a = -this.speed/2;
                else
                {
                    a = 0;
                    this.speed = 0;
                }
            }
            else a = -this.stats.acceleration*2;
        }
        

        this.M_wheelRotation.updateRotationZ( this.angle );
        this.b_drifting = false;
        if ( this.keys.left )
        {
            this.angle -= this.steeringAngle;

            if ( this.keys.forward && this.speed >= Car.MIN_DRIFTING_SPEED )
            {
                this.b_drifting = true;
                var driftingPercent = (this.speed-Car.MIN_DRIFTING_SPEED)/1000;
                if ( driftingPercent > 1 ) driftingPercent = 1;
                this.angle -= (this.steeringAngle*driftingPercent);
                this.driftingAngleOffset = -Math.PI/10*driftingPercent;
                this.M_wheelRotation.updateRotationZ( this.angle+this.driftingAngleOffset-Math.PI/40 );
            }
            else
            {
                this.M_wheelRotation.updateRotationZ( this.angle-Math.PI/40 );
            }
        }
        if ( this.keys.right )
        {
            this.angle += this.steeringAngle;

            if ( this.keys.forward && this.speed >= Car.MIN_DRIFTING_SPEED )
            {
                this.b_drifting = true;
                var driftingPercent = (this.speed-Car.MIN_DRIFTING_SPEED)/1000;
                if ( driftingPercent > 1 ) driftingPercent = 1;
                this.angle += (this.steeringAngle*driftingPercent);
                this.driftingAngleOffset = Math.PI/10*driftingPercent;
                this.M_wheelRotation.updateRotationZ( this.angle+this.driftingAngleOffset+Math.PI/40 );
            }
            else
            {
                this.M_wheelRotation.updateRotationZ( this.angle+Math.PI/40 );
            }
        }

        if ( this.angle >= 2*Math.PI ) this.angle -= 2*Math.PI;
        if ( this.angle <= -2*Math.PI ) this.angle += 2*Math.PI;

        this.speed += a*dt;

        if ( this.speed < -this.stats.maxSpeed/4 ) this.speed = -this.stats.maxSpeed/4;
        if ( this.speed > this.stats.maxSpeed ) this.speed = this.stats.maxSpeed;
        if ( this.keys.handbrake && this.speed < 0 ) this.speed = 0;

        if ( this.speed < 0 )
        {
            this.backwardsSound.volume = 1;
        }
        else
        {
            this.backwardsSound.volume = 0;
        }

        // set audio volume based on speed
        this.engineSound.volume = Math.abs( this.speed/this.stats.maxSpeed );

        var oldX = this.x;
        var oldY = this.y;
        this.x += Math.sin( this.angle ) * this.speed * dt;
        this.y -= Math.cos( this.angle ) * this.speed * dt;

        if ( this.x < -Map.SIZE/2 )
        {
            this.x = -Map.SIZE/2;
            this.y = oldY;
            this.speed = 0;
        }
        else if ( this.x > Map.SIZE/2 )
        {
            this.x = Map.SIZE/2;
            this.y = oldY;
            this.speed = 0;
        }
        if ( this.y < -Map.SIZE/2 )
        {
            this.x = oldX;
            this.y = -Map.SIZE/2;
            this.speed = 0;
        }
        else if ( this.y > Map.SIZE/2 )
        {
            this.x = oldX;
            this.y = Map.SIZE/2;
            this.speed = 0;
        }

        this.camera.setFocus( this.x , this.y );
        // this.debugText.setStr( (Math.floor(this.x*100)/100)+","+(Math.floor(this.y*100)/100) );

        if ( this.map.unloadingArea.inBounds( this.x , this.y ) )
        {
            this.map.b_canUnload = true;
        }
        else
        {
            this.map.b_canUnload = false;
        }

        if ( this.numberOfCrystals < this.stats.capacity )
        {
            for ( let i = 0 ; i < this.map.crystals.length ; ++i )
            {
                if ( this.map.crystals[i].isNear( -this.x , -this.y ) )
                {
                    this.numberOfCrystals++;
                    this.txt_crystals.setStr( this.numberOfCrystals+"/"+this.stats.capacity );
                    this.map.crystals[i].delete();
                    this.map.crystals.splice( i , 1 );
                    if ( this.numberOfCrystals == this.stats.capacity )
                    {
                        this.quad.setTexture( this.texture_full );
                    }
                    else
                    {
                        this.quad.setTexture( this.texture_some );
                    }
                    this.pickupSound.play();
                    break;
                }
            }
        }

        // console.log( this.camera.x+" , "+this.camera.y );

        this.M_translation.data[12] = this.camera.x - this.x;
        this.M_translation.data[13] = this.camera.y - this.y;
        if ( this.b_drifting ) this.M_rotation.updateRotationZ( this.angle + this.driftingAngleOffset );
        else this.M_rotation.updateRotationZ( this.angle );
        // if ( this.keys.handbrake ) this.M_rotation.updateRotationZ( this.angle+Math.PI/50 );

        

        if ( Math.abs( this.x ) > 100 || Math.abs( this.y ) > 100 )
        {
            this.b_drawMarker = true;
            // var markerAngle = Math.atan( this.y/this.x );
            var markerAngle = 0;

            if ( this.x >= 0 )
            {
                markerAngle = Math.atan( this.y/this.x ) + Math.PI/2;
            }
            else
            {
                markerAngle = Math.atan( this.y/this.x ) + Math.PI + Math.PI/2;
            }

            this.M_markerRotation.updateRotationZ( markerAngle );
        }
        else
        {
            this.b_drawMarker = false;
        }

        // console.log( this.x+" , "+this.y );
    }

    draw()
    {
        mat4.multiplyInPlace( this.M_model , this.M_translation , this.M_wheelRotation );
        this.engine.defaultShader2D.setUniformModel( this.M_model );
        this.wheelQuad.draw();

        mat4.multiplyInPlace( this.M_model , this.M_translation , this.M_rotation );
        this.engine.defaultShader2D.setUniformModel( this.M_model );
        this.quad.draw();

        if ( this.b_drawMarker )
        {
            mat4.multiplyInPlace( this.M_model , this.M_translation , this.M_markerRotation );
            this.engine.defaultShader2D.setUniformModel( this.M_model );
            this.markerQuad.draw();
        }

        this.engine.defaultShader2D.setUniformModel( this.M_translation );
        this.txt_crystals.draw();
    }

    upgradeSpeed()
    {
        this.stats.upgradeSpeed();
        this.txt_maxSpeed.setStr( "Max Speed: "+this.stats.maxSpeed );
    }

    upgradeAcceleration()
    {
        this.stats.upgradeAcceleration();
        this.txt_acceleration.setStr( "Acceleration: "+this.stats.acceleration );
    }

    upgradeRange()
    {
        this.stats.upgradeRange();
        this.txt_pickUpDistance.setStr( "Pickup Range: "+this.stats.range );
    }

    upgradeCapacity()
    {
        this.stats.upgradeCapacity();
        this.txt_capacity.setStr( "Capacity: "+this.stats.capacity );
        this.txt_crystals.setStr( "0/"+this.stats.capacity );
    }
}