/**
 * Stacked Chart
 */
class StackedChart extends BarChart {
    /**
     * Creates a new instance of the StackedChart 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 stacked bar chart on the canvas.
     */
    draw() {
        // Calculate the largest total value across all categories for normalization
        let largest = 0
        for (let i = 0; i < this.dataLen; i++) {
            let sum = 0
            this.data.forEach(categ => {
                categ.values[i] = Math.abs(categ.values[i]) || 0
                sum += categ.values[i]
            })
            largest = sum > largest ? sum : largest
        }

        // Clear the canvas
        this.clear()
        // Draw the axis without displaying axis values
        this.drawAxis(false)

        // Calculate the size of each bar segment based on the canvas width and number of data points
        let size = this.zoomBounds.width / this.dataLen
        // Calculate the actual width of each bar, making it 70% of the calculated size
        let bar_width = size * 0.7

        // Iterate over each data point to draw the stacked bars
        for (let i = 0; i < this.dataLen; i++) {
            // The top position of the last stacked bar segment
            let last_top = this.zoomBounds.xAxis

            this.data.forEach((categ, colId) => {
                // Value of the bar segment
                let value = categ.values[i] || 0
                // The height of the bar segment relative to the largest total value
                let bar_height = value / largest * this.zoomBounds.height
                // The left position of the bar segment
                let left = this.zoomBounds.left + size * (i + 0.15)
                // The top position of the bar segment
                let top = last_top - bar_height

                // Update the last top position for the next iteration
                last_top = top

                // 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()
            }
        }
    }
}
