import Condition from "../Conditions/Condition";
import FormBuilder from "../FormBuilder";
import Structure from "./Structure/Structure";
import Form from "./Structure/Form/Form";
import {setElementVisibility} from "../Utility/ElementVisibility";

export default abstract class Component {
    protected placedHtml: HTMLElement[] = [];
    protected conditions: Condition[] = [];
    protected _visible: boolean = false;
    public formBuilder: FormBuilder;
    public parent: Structure|null = null;
    public id: string;
    public idPrefix: string|null;

    protected constructor(params: Partial<Component> = {}) {
        Object.assign(this, params);
    }

    public abstract placeHtml(container: HTMLElement): void;

    public cleanHtml(): void {
        this.placedHtml.forEach(html => html.remove());
    }

    public addConditions(...conditions: Condition[]):this{
        conditions.forEach(condition => {
            this.conditions.push(condition)
            condition.onChange.add(() => this.checkVisibility());
        });

        return this;
    }

    public checkVisibility(updatedValue: boolean|null = null): void {
        if (updatedValue === this._visible) return;
        if (updatedValue === false) this._visible = false;
        if (updatedValue === true || updatedValue === null){
            this._visible = this.conditions.every(condition => condition.check());
        }

        this.updateVisibility();
    }

    public updateVisibility(): void {
        this.placedHtml.forEach(html => setElementVisibility(html, this.visible));
    }

    get visible(): boolean {
        return this._visible;
    }

    public getOwnerForm(): Form {
        let currentParent = this.parent;
        while (currentParent !== null && !(currentParent instanceof Form)) {
            currentParent = currentParent.parent;
        }

        if (currentParent === null) return this.formBuilder.form;
        return currentParent as Form;
    }
}