import { GraphContextFactory } from './graph-context-factory';
import { RendererFactory } from './renderers/renderer-factory';
import { ChartDimensionController, DEFAULT_LAYOUT } from './controllers/chart-dimension-controller';
import { InteractorFactory } from './interactors/interactor-factory';
/** This is a TypeScript class called `BaseChart` that serves as a base class for creating charts */
export class BaseChart {
  /**
   * This is a constructor function that initializes a chart with options and creates a chain of drawers for rendering.
   *
   * @param {ChartOptions<unknown>} options - generic type that represents the configuration options for the chart
   */
  constructor(options) {
    this.options = options;
    this.isLayoutSet = false;
    this.drawers = [];
    const context = GraphContextFactory.get(options.mode, options.container.shadowRoot ? options.container.shadowRoot : options.container);
    this.dimensionController = new ChartDimensionController(options.container);
    this.renderer = RendererFactory.get(context);
    this.interactor = InteractorFactory.get(context);
    this.initLayoutOptions(options);
  }
  /**
   * The function clears the renderer.
   */
  clear() {
    this.renderer.clear();
  }
  /**
   * This function updates the chart options, creates a new drawer chain, resets the layout, and renders the chart.
   *
   * @param {ChartOptions<unknown>} options - ChartOptions<T> is a generic type that represents the configuration options for a
   * chart. It can include properties such as the chart type, data, labels, colors, and other stylingoptions
   */
  updateOptions(options) {
    this.initLayoutOptions(options);
    this.isLayoutSet = false;
    this.render();
  }
  /**
   * re render the chart using existing options
   */
  reRender() {
    this.updateOptions(this.options);
  }
  /**
   * sets the layout if it hasn't been set yet, and executes all the drawers. unregister the interactor by drawer
   */
  render() {
    this.unregisterByDrawer();
    this.drawers = this.createDrawerChain(this.renderer, this.interactor);
    this.clear();
    if (!this.isLayoutSet) {
      this.setLayout();
      this.isLayoutSet = true;
    }
    this.drawers.forEach((drawer) => drawer.execute());
  }
  /**
   * sets the layout of a renderer using the options provided.
   */
  setLayout() {
    const layout = this.options.layout;
    const width = this.dimensionController.getContainerClientWidth(layout), height = this.dimensionController.getContainerClientHeight(layout), margin = (layout === null || layout === void 0 ? void 0 : layout.margin) || DEFAULT_LAYOUT.margin;
    this.renderer.setLayout(width, height, margin.top, margin.left);
  }
  /**
   * This function initializes layout options for a chart.
   *
   * @param {ChartOptions} options - ChartOptions<T> is a generic type that represents the configuration options for a
   * chart. It includes properties such as data, layout, and style.
   */
  initLayoutOptions(options) {
    const newLayout = this.dimensionController.mergeLayout(options.container.tagName, options.layout, options.legends && options.legends.length ? true : false);
    this.options = Object.assign(options, { layout: newLayout });
    this.dimensionController.setContainerWidthAndHeight(newLayout);
    this.options.container.style.display = 'block';
  }
  /**
   * This function un-registers drawers from the interactor.
   */
  unregisterByDrawer() {
    if (this.drawers) {
      this.drawers.forEach((drawer) => {
        this.interactor.unregisterByDrawer(drawer);
      });
    }
  }
}
