import * as THREE from 'three';

export default class MazeMesh extends THREE.InstancedMesh {
    constructor( width, length, height, material ) {
        super( 
            new THREE.BoxGeometry( 1, height, 1 ),
            material,
            width*length - 2
        );
        this.length = length
        this.width = width
        this.map = new Array(length).fill().map(() => new Array(width).fill(1))
        this.start = new THREE.Vector3(width/2, .1, length/2)
        this.exit = new THREE.Vector3(Math.floor(width/2), 0, 1)
        this.count = length * width - 2

        this.dig(this.exit)
        this.dig(new THREE.Vector3(Math.floor(width/2), 0, 0))
        this.build ( this.exit )
        let matrix = new THREE.Matrix4()
        let i=0
        this.map.forEach((row, z) => {
            row.forEach((isWall, x) => {
                if (isWall) {
                    matrix.setPosition( x + .5 - width/2, 0.5, z + .5 - length/2)
                    this.setMatrixAt( i, matrix );
                    i++
                }
            })
        })
    }
    
    dig(position) {
        this.map[position.z][position.x] = 0
    }

    static DIRECTIONS = [
        new THREE.Vector3( 0, 0, -1),
        new THREE.Vector3( 0, 0,  1),
        new THREE.Vector3(-1, 0,  0),
        new THREE.Vector3( 1, 0,  0),
    ]
    build(position) {
        for (var direction of Array.from(this.constructor.DIRECTIONS).sort(x => .5 - Math.random())) {
            var step1 = position.clone().add(direction)
            var step2 = step1.clone().add(direction)
            if (this.isWall(step2) == 1) {
                this.dig(step1)
                this.dig(step2)
                this.count -= 2
                this.build(step2)
            }
        }
    }

    isWall(position) {
        if (0 <= position.x && position.x < this.width &&
            0 <= position.z && position.z < this.length) {
            return this.map[Math.floor(position.z)][Math.floor(position.x)]
        } else {
            return -1
        }
    }

    toString() {
        return this.map.map(row => 
            row.map(isWall => isWall? "██":"  ").join("")
        ).join("\n")
    }
}