/**
 * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */

/**
 * @module table/converters/table-heading-rows-refresh-post-fixer
 */

import TableWalker from '../tablewalker';

/**
 * A table headings refresh handler which marks the table cells or rows in the differ to have it re-rendered
 * if the headings attribute changed.
 *
 * Table heading rows and heading columns are represented in the model by a `headingRows` and `headingColumns` attributes.
 *
 * When table headings attribute changes, all the cells/rows are marked to re-render to change between `<td>` and `<th>`.
 *
 * @param {module:engine/model/model~Model} model
 * @param {module:engine/controller/editingcontroller~EditingController} editing
 */
export default function tableHeadingsRefreshHandler( model, editing ) {
	const differ = model.document.differ;

	for ( const change of differ.getChanges() ) {
		let table;
		let isRowChange = false;

		if ( change.type == 'attribute' ) {
			const element = change.range.start.nodeAfter;

			if ( !element || !element.is( 'element', 'table' ) ) {
				continue;
			}

			if ( change.attributeKey != 'headingRows' && change.attributeKey != 'headingColumns' ) {
				continue;
			}

			table = element;
			isRowChange = change.attributeKey == 'headingRows';
		} else if ( change.name == 'tableRow' || change.name == 'tableCell' ) {
			table = change.position.findAncestor( 'table' );
			isRowChange = change.name == 'tableRow';
		}

		if ( !table ) {
			continue;
		}

		const headingRows = table.getAttribute( 'headingRows' ) || 0;
		const headingColumns = table.getAttribute( 'headingColumns' ) || 0;

		const tableWalker = new TableWalker( table );

		for ( const tableSlot of tableWalker ) {
			const isHeading = tableSlot.row < headingRows || tableSlot.column < headingColumns;
			const expectedElementName = isHeading ? 'th' : 'td';

			const viewElement = editing.mapper.toViewElement( tableSlot.cell );

			if ( viewElement && viewElement.is( 'element' ) && viewElement.name != expectedElementName ) {
				editing.reconvertItem( isRowChange ? tableSlot.cell.parent : tableSlot.cell );
			}
		}
	}
}
