import { assert } from "../../../core/assert.js";
import { isDefined } from "../../../core/process/matcher/isDefined.js";
import LabelView from "../../common/LabelView.js";
import SVG from "../../SVG.js";
import View from "../../View.js";
import EmptyView from "../EmptyView.js";
import ImageView from "../image/ImageView.js";

export class WindRoseDiagram extends View {

    /**
     *
     * @param {{name:string,icon?:(View|string),value?:number,tooltip?:function, tooltipContext?:*}[]} axes
     * @param {number} value_mark_stride
     * @param {number} angular_offset
     * @param {number} radius
     * @param {number} value_max
     * @param {DomTooltipManager} [tooltips]
     */
    constructor({
                    axes,
                    angular_offset = 0,
                    radius_inner = 200,
                    radius_outer = radius_inner,
                    value_max = 10,
                    value_mark_stride = value_max / 5,

                    icon_size = 32,

                    tooltips,

                    backplate_stroke_width = 2,
                    backplate_stroke_color = 'rgba(0,0,0,1)',
                    backplate_fill_color = 'rgba(99,99,99,1)',
                    display_backplate = true,

                    graph_stroke_width = 1,
                    graph_stroke_color = 'rgba(0,0,0,1)',
                    graph_fill_color = 'rgba(0,0,0,0.1)',

                    mark_stroke_width = 1,
                    mark_stroke_color = 'rgba(0,0,0,0.13)',
                    display_marks = true,

                    origin_radius = 8,
                    origin_stroke_width = 0,
                    origin_stroke_color = 'transparent',
                    origin_fill_color = 'red',
                    display_origin = true,
                    classList = []
                }) {
        super();

        this.__axes = axes;
        this.__settings_value_max = value_max;
        this.__settings_value_mark_stride = value_mark_stride;
        this.__settings_angular_offset = angular_offset;
        this.__settings_icon_size = icon_size;

        this.__settings_graph_stroke_width = graph_stroke_width;
        this.__settings_graph_stroke_color = graph_stroke_color;
        this.__settings_graph_fill_color = graph_fill_color;

        this.__settings_backplate_stroke_width = backplate_stroke_width;
        this.__settings_backplate_stroke_color = backplate_stroke_color;
        this.__settings_backplate_fill_color = backplate_fill_color;
        this.__settings_display_backplate = display_backplate;

        this.__settings_mark_stroke_width = mark_stroke_width;
        this.__settings_mark_stroke_color = mark_stroke_color;
        this.__settings_display_marks = display_marks;

        this.__settings_origin_radius = origin_radius;
        this.__settings_origin_stroke_width = origin_stroke_width;
        this.__settings_origin_stroke_color = origin_stroke_color;
        this.__settings_origin_fill_color = origin_fill_color;
        this.__settings_display_origin = display_origin;

        this.__settings_radius_inner = radius_inner;
        this.__settings_radius_outer = radius_outer;

        this.__tooltips = tooltips;

        this.__values = new Float32Array(axes.length);

        this.el = document.createElement('div');
        this.addClass('ui-wind-rose-diagram-view');
        this.addClasses(classList);

        const has_icons = axes.some(isDefined);

        const size = radius_outer * 2 + (has_icons ? icon_size * (Math.SQRT1_2 + 0.5) * 2 : 0);

        this.size.set(size, size);


        this.__vCanvas = new EmptyView({
            classList: ['canvas']
        });

        this.addChild(this.__vCanvas);

        this.__vGraph = new EmptyView({
            classList: ["graph"],
            el: SVG.createElement('svg'),
            attr: {
                width: this.size.x * 2,
                height: this.size.y * 2
            },
            css: {
                position: 'absolute',
                left: 0,
                top: 0,
                overflow: 'visible'
            }
        });
        this.addChild(this.__vGraph);

        this.__svg_graph_path = SVG.createElement('path');
        this.__svg_graph_path.classList.add('graph-path-main');
        this.__svg_graph_path.setAttribute('stroke-width', this.__settings_graph_stroke_width);
        this.__svg_graph_path.setAttribute('stroke', this.__settings_graph_stroke_color);
        this.__svg_graph_path.setAttribute('fill', this.__settings_graph_fill_color);

        this.__vGraph.el.appendChild(this.__svg_graph_path);

        this.on.linked.add(this.draw, this);

        // process input axes
        for (let i = 0; i < axes.length; i++) {
            const axis = axes[i];

            assert.defined(axis, 'axis');
            assert.notNull(axis, 'axis');

            if (axis.value !== undefined) {
                this.set_axis_value(i, axis.value);
            }
        }
    }

    /**
     *
     * @param {number} index
     * @param {number} value
     */
    set_axis_value(index, value) {
        assert.isNonNegativeInteger(index, 'index');
        assert.isFinite(value, 'value');

        assert.lessThan(index, this.__axes.length, 'index overflow');

        this.__values[index] = value;
    }

    draw() {
        this.draw_canvas();
        this.draw_values();
    }

    __get_axis_count() {
        return this.__axes.length;
    }

    __get_axis_angle(index) {
        const axis_count = this.__get_axis_count();
        return index * Math.PI * (2 / axis_count) + this.__settings_angular_offset - Math.PI * 0.5;
    }

    __create_loop_path(radius) {
        const axis_count = this.__get_axis_count();
        const offset_x = this.size.x * 0.5;
        const offset_y = this.size.y * 0.5;

        let path = 'M';

        for (let i = 0; i < axis_count; i++) {

            const angle = this.__get_axis_angle(i);
            const cos = Math.cos(angle);
            const sin = Math.sin(angle);

            path += cos * radius + offset_x;
            path += ','
            path += sin * radius + offset_y;

            if (i < axis_count - 1) {
                path += 'L'
            } else {
                path += 'Z';
            }
        }

        return path;
    }

    draw_canvas() {
        const container = this.__vCanvas;
        container.removeAllChildren();

        const axis_count = this.__get_axis_count();
        const offset_x = this.size.x * 0.5;
        const offset_y = this.size.y * 0.5;


        // draw background and marks
        const svg_main = SVG.createElement('svg');
        svg_main.setAttribute('width', String(this.size.x));
        svg_main.setAttribute('height', String(this.size.y));

        if (this.__settings_display_backplate) {
            const svg_path = SVG.createElement('path');

            svg_path.classList.add('backplate');

            svg_path.setAttribute('d', this.__create_loop_path(this.__settings_radius_outer + this.__settings_backplate_stroke_width / 2));
            svg_path.setAttribute('stroke-width', String(this.__settings_backplate_stroke_width));
            svg_path.setAttribute('stroke', this.__settings_backplate_stroke_color);
            svg_path.setAttribute('fill', this.__settings_backplate_fill_color);

            svg_main.appendChild(svg_path);
        }

        if (this.__settings_display_marks) {
            for (let i = this.__settings_value_mark_stride; i < this.__settings_value_max; i += this.__settings_value_mark_stride) {
                const svg_path = SVG.createElement('path');
                svg_path.classList.add('mark');

                const f = i / this.__settings_value_max;

                const radius = f * this.__settings_radius_inner;

                svg_path.setAttribute('d', this.__create_loop_path(radius));
                svg_path.setAttribute('fill', 'none');
                svg_path.setAttribute('stroke-width', this.__settings_mark_stroke_width);
                svg_path.setAttribute('stroke', this.__settings_mark_stroke_color);

                svg_main.appendChild(svg_path);
            }
        }

        if (this.__settings_display_origin) {
            const svg_path = SVG.createElement('path');

            svg_path.classList.add('origin');

            svg_path.setAttribute('d', this.__create_loop_path(this.__settings_origin_radius));
            svg_path.setAttribute('fill', this.__settings_origin_fill_color);
            svg_path.setAttribute('stroke-width', this.__settings_origin_stroke_width);
            svg_path.setAttribute('stroke', this.__settings_origin_stroke_color);

            svg_main.appendChild(svg_path);
        }

        const vSvgMain = new EmptyView({
            el: svg_main,
            css: {
                position: 'absolute',
                top: 0,
                left: 0
            }
        });

        container.addChild(vSvgMain);

        for (let i = 0; i < axis_count; i++) {

            // draw axis name
            const axis = this.__axes[i];

            if (axis === undefined) {
                continue;
            }

            const angle = this.__get_axis_angle(i);
            const cos = Math.cos(angle);
            const sin = Math.sin(angle);

            if (axis.name !== undefined) {
                const vName = new LabelView(axis.name, {
                    classList: ['axis-name'],
                    css: {
                        position: "absolute",
                        top: "0",
                        left: "0"
                    }
                });

                const label_offset = this.__settings_radius_inner;
                vName.position.set(
                    cos * label_offset + offset_x,
                    sin * label_offset + offset_y
                );

                if (this.__tooltips !== undefined && axis.tooltip !== undefined) {
                    this.__tooltips.add(vName, axis.tooltip, axis.tooltipContext);
                }

                container.addChild(vName);
            }

            // process icon
            if (axis.icon !== undefined) {
                let vIcon;
                if (typeof axis.icon === "string") {
                    vIcon = new ImageView(axis.icon);
                } else {
                    vIcon = axis.icon;
                }

                const icon_size = this.__settings_icon_size;
                vIcon.css({
                    position: 'absolute',
                    left: `-${icon_size * 0.5}px`,
                    top: `-${icon_size * 0.5}px`
                });

                const icon_offset = this.__settings_radius_outer + icon_size * Math.SQRT1_2;

                vIcon.position.set(
                    cos * icon_offset + offset_x,
                    sin * icon_offset + offset_y
                );

                vIcon.size.set(
                    icon_size,
                    icon_size
                );

                if (this.__tooltips !== undefined && axis.tooltip !== undefined) {
                    this.__tooltips.add(vIcon, axis.tooltip, axis.tooltipContext);
                }

                container.addChild(vIcon);
            }
        }
    }

    draw_values() {

        const axis_count = this.__get_axis_count();
        const offset_x = this.size.x * 0.5;
        const offset_y = this.size.y * 0.5;

        let path = 'M';

        for (let i = 0; i < axis_count; i++) {

            const angle = this.__get_axis_angle(i);
            const cos = Math.cos(angle);
            const sin = Math.sin(angle);

            const f = this.__values[i] / this.__settings_value_max;
            const radius = this.__settings_radius_inner * f;

            path += cos * radius + offset_x;
            path += ','
            path += sin * radius + offset_y;

            if (i < axis_count - 1) {
                path += 'L'
            } else {
                path += 'Z';
            }
        }

        this.__svg_graph_path.setAttribute('d', path);
    }
}
