/**
 * Bar Chart
 */
class BarChart extends Chart {
    /**
    * Creates a new instance of the BarChart class
    *
    * @param {HTMLCanvasElement} canvas - The canvas element to draw the chart on
    * @param {Array<Object>} data - The data to visualize on the chart
    * @param {Object} settings - The settings for the chart
    * @param {ZoomManager} zoom - The zoom manager for the chart.
     */
    constructor(canvas, data, settings, zoom) {
        // Call the constructor of the parent class (Chart)
        super(canvas, data, settings, zoom)
    }

    /**
     * Draws the bar chart on the canvas.
     * @param {Boolean} async - Says if the chart should be drawn synchronously or asynchronously
     */
    draw(async = true) {
        // Calculate the number of bars/categories in the chart
        this.clear()
        let barCount = this.data.length

        // Draw the axis without displaying axis values
        this.drawAxis(false)
        // Define function for async
        let fn = () => {
            // Divide the space into equal section
            // Calculate section size
            let size = this.zoomBounds.width / this.dataLen
            // Callculate inner size with margin
            let innerSize = size * 0.8
            // Width of each chart
            let bar_width = innerSize * 0.7 / barCount // this.zoom.scaleX

            // Iterate over each data point to draw the bars
            for (let i = 0; i < this.dataLen; i++) {
                // Counter to determine the position of each bar within a data point
                let num = 0

                this.data.forEach((categ, colId) => {
                    // Value of the bar
                    let value = categ.values[i]
                    // The left position of the bar in section
                    let left = this.zoomBounds.left + (size * (i + 0.15) + (innerSize * num / barCount))
                    // The height of the bar relative to the chart scale
                    let bar_height = value / this.extreme * this.scale * this.zoom.scaleY
                    // The top position of the bar
                    let top = this.zoomBounds.xAxis - categ.values[i] / this.extreme * this.scale * this.zoom.scaleY

                    // Increment the bar count
                    num++

                    // Create a new Rectangle object representing the current bar
                    let newObject = new Rectangle(this.ctx, value, colId, left, top, bar_width, bar_height)
                    // Add the new Rectangle object to the list of objects
                    this.objects.push(newObject)

                    // Check if the center of the new bar is within the bounds
                    if (this.isInBounds(newObject.getCenter())) {
                        // Set the fill color to the category color
                        this.ctx.fillStyle = categ.color
                        // Set the line width to 0 to prevent drawing the border
                        this.ctx.lineWidth = 0
                        // Draw the filled rectangle representing the current bar
                        newObject.draw()
                    }
                })
            }

            // Draw x-axis labels if enabled
            if (this.settings.displayAxisValues) {
                // Restore canvas state to undo region clipping
                this.ctx.restore()
                // Loop through each data point to draw the labels
                for (let i = 0; i < this.dataLen; i++) {
                    let text = (i + 1).toString()

                    // Begin drawing the text
                    this.ctx.beginPath()
                    this.ctx.font = "16px Arial"
                    this.ctx.fillStyle = "black"
                    this.ctx.textAlign = "center"

                    // Calculate the position of the label
                    let x = this.zoomBounds.left + this.zoomBounds.width / this.dataLen * i + size / 2
                    let y = this.bounds.bottom + 15

                    // Draw the label text
                    this.ctx.fillText(text, x, y)
                    // Stroke the text
                    this.ctx.stroke()
                    // Close the path
                    this.ctx.closePath()
                }
            }
        }

        // Draw the chart
        if (this.settings.displayPoints)
            async ? setTimeout(() => fn(), 0) : fn()
    }
}
