/*!
 * VisualEditor DataModel CommentNode class.
 *
 * @copyright See AUTHORS.txt
 */

/**
 * @class
 * @abstract
 * @extends ve.dm.LeafNode
 * @mixes ve.dm.FocusableNode
 *
 * @constructor
 * @param {Object} element Reference to element in meta-linmod
 */
ve.dm.CommentNode = function VeDmCommentNode( element ) {
	// Parent constructor
	ve.dm.CommentNode.super.call( this, element );

	// Mixin constructors
	ve.dm.FocusableNode.call( this );
};

/* Inheritance */

OO.inheritClass( ve.dm.CommentNode, ve.dm.LeafNode );

OO.mixinClass( ve.dm.CommentNode, ve.dm.FocusableNode );

/* Static Properties */

ve.dm.CommentNode.static.isContent = true;

ve.dm.CommentNode.static.preserveHtmlAttributes = false;

ve.dm.CommentNode.static.toDataElement = function ( domElements, converter ) {
	let text;
	if ( domElements[ 0 ].nodeType === Node.COMMENT_NODE ) {
		text = ve.safeDecodeEntities( domElements[ 0 ].data );
	} else {
		text = domElements[ 0 ].getAttribute( 'data-ve-comment' );
	}
	return {
		// Disallows comment nodes between table rows and such
		type: converter.isValidChildNodeType( 'comment' ) && text !== '' ? 'comment' : 'commentMeta',
		attributes: {
			text: text
		}
	};
};

ve.dm.CommentNode.static.toDomElements = function ( dataElement, doc, converter ) {
	if ( converter.isForClipboard() ) {
		// Fake comment node
		const span = doc.createElement( 'span' );
		span.setAttribute( 'rel', 've:Comment' );
		span.setAttribute( 'data-ve-comment', dataElement.attributes.text );
		span.appendChild( doc.createTextNode( '\u00a0' ) );
		return [ span ];
	} else if ( converter.isForPreview() ) {
		// isForPreview(), use CE rendering
		const modelNode = ve.dm.nodeFactory.createFromElement( dataElement );
		modelNode.setDocument( converter.internalList.getDocument() );
		const viewNode = ve.ce.nodeFactory.createFromModel( modelNode );
		viewNode.updateInvisibleIconSync( true );
		viewNode.$element.attr( 'title', dataElement.attributes.text );
		const els = viewNode.$element.toArray();
		viewNode.destroy();
		return els;
	} else {
		// Real comment node
		// Encode & - > (see T95040, T144708)
		const data = dataElement.attributes.text.replace( /[-&>]/g, ( c ) => '&#x' + c.charCodeAt( 0 ).toString( 16 ).toUpperCase() + ';' );
		return [ doc.createComment( data ) ];
	}
};

ve.dm.CommentNode.static.describeChange = function ( key, change ) {
	if ( key === 'text' ) {
		const diff = this.getAttributeDiff( change.from, change.to );
		if ( diff ) {
			// TODO: Use a word-break based diff for comment text
			return ve.htmlMsg( 'visualeditor-changedesc-comment-diff', diff );
		} else {
			return ve.htmlMsg( 'visualeditor-changedesc-comment', this.wrapText( 'del', change.from ), this.wrapText( 'ins', change.to ) );
		}
	}
};