/*************************************************************
 *
 *  Copyright (c) 2018 The MathJax Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * @fileoverview  Implements the SVGmtr wrapper for the MmlMtr object
 *                and SVGmlabeledtr for MmlMlabeledtr
 *
 * @author dpvc@mathjax.org (Davide Cervone)
 */

import {SVGWrapper, SVGConstructor, Constructor} from '../Wrapper.js';
import {CommonMtr, CommonMtrMixin} from '../../common/Wrappers/mtr.js';
import {CommonMlabeledtr, CommonMlabeledtrMixin} from '../../common/Wrappers/mtr.js';
import {SVGmtable} from './mtable.js';
import {SVGmtd} from './mtd.js';
import {MmlMtr, MmlMlabeledtr} from '../../../core/MmlTree/MmlNodes/mtr.js';


/**
 * The data needed for placeCell()
 */
export type SizeData = {
    x: number,
    y: number,
    w: number,
    lSpace: number,
    rSpace: number,
    lLine: number,
    rLine: number
};

/*****************************************************************/
/**
 * The SVGmtr wrapper for the MmlMtr object
 *
 * @template N  The HTMLElement node class
 * @template T  The Text node class
 * @template D  The Document class
 */
export class SVGmtr<N, T, D> extends CommonMtrMixin<SVGmtd<any, any, any>, SVGConstructor<any, any, any>>(SVGWrapper) {

    public static kind = MmlMtr.prototype.kind;

    public parent: SVGmtable<N, T, D>;

    public H: number;       // height of row
    public D: number;       // depth of row
    public tSpace: number;  // space above row
    public bSpace: number;  // space below row
    public tLine: number;   // line space above
    public bLine: number;   // line space below

    /**
     * @override
     */
    public toSVG(parent: N) {
        const svg = this.standardSVGnode(parent);
        this.placeCells(svg);
        this.placeColor(svg);
    }

    /**
     * Set the location of the cell contents in the row and expand the cell background colors
     *
     * @param {N} svg   The container for the table
     */
    protected placeCells(svg: N) {
        const cSpace = this.parent.getColumnHalfSpacing();
        const cLines = [this.parent.fLine, ...this.parent.cLines, this.parent.fLine];
        const cWidth = this.parent.getComputedWidths();
        const [T, B] = [this.tLine / 2, this.bLine / 2];
        let x = cLines[0];
        for (let i = 0; i < this.numCells; i++) {
            const child = this.getChild(i);
            child.toSVG(svg);
            x += this.placeCell(child, {
                x: x, y: 0, lSpace: cSpace[i], rSpace: cSpace[i + 1], w: cWidth[i],
                lLine: cLines[i], rLine: cLines[i + 1]
            });
        }
    }

    /**
     * @param {SVGmtd} cell      The cell to place
     * @param {SizeData} sizes   The positioning information
     * @return {number}          The new x position
     */
    public placeCell(cell: SVGmtd<N, T, D>, sizes: SizeData) {
        const {x, y, lSpace, w, rSpace, lLine, rLine} = sizes;
        const [dx, dy] = cell.placeCell(x + lSpace, y, w, this.H, this.D);
        const W = lSpace + w + rSpace;
        const [H, D] = [this.H + this.tSpace, this.D + this.bSpace];
        cell.placeColor(-(dx + lSpace + lLine / 2), -(D + this.bLine / 2 + dy),
                        W + (lLine + rLine) / 2, H + D + (this.tLine + this.bLine) / 2);
        return W + rLine;
    }

    /**
     * Expand the backgound color to fill the entire row
     *
     * @param {N} svg   The container for the table
     */
    protected placeColor(svg: N) {
        const adaptor = this.adaptor;
        const child = adaptor.firstChild(this.element);
        if (child && adaptor.kind(child) === 'rect' && adaptor.getAttribute(child, 'data-bgcolor')) {
            const [TL, BL] = [this.tLine / 2, this.bLine / 2];
            const [TS, BS] = [this.tSpace, this.bSpace];
            const [H, D] = [this.H, this.D];
            adaptor.setAttribute(child, 'y', this.fixed(-(D + BS + BL)));
            adaptor.setAttribute(child, 'width', this.fixed(this.parent.getWidth()));
            adaptor.setAttribute(child, 'height', this.fixed(TL + TS + H + D + BS + BL));
        }
    }

}

/*****************************************************************/
/**
 * The SVGlabeledmtr wrapper for the MmlMlabeledtr object
 *
 * @template N  The HTMLElement node class
 * @template T  The Text node class
 * @template D  The Document class
 */
export class SVGmlabeledtr<N, T, D> extends
CommonMlabeledtrMixin<SVGmtd<any, any, any>, Constructor<SVGmtr<any, any, any>>>(SVGmtr) {

    public static kind = MmlMlabeledtr.prototype.kind;

    /**
     * @override
     */
    public toSVG(parent: N) {
        super.toSVG(parent);
        const child = this.childNodes[0];
        if (child) {
            child.toSVG(this.parent.labels);
        }
    }
}
