/*******************************************************************************
 * Copyright (c) 2001, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Jens Lukowski/Innoopract - initial renaming/restructuring
 *     
 *******************************************************************************/
package org.eclipse.wst.xml.core.internal.parser;

import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredTextReParser;
import org.eclipse.wst.sse.core.internal.text.StructuredDocumentReParser;
import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;


public class XMLStructuredDocumentReParser extends StructuredDocumentReParser {

	public XMLStructuredDocumentReParser() {
		super();
	}

	protected IStructuredDocumentRegion findDirtyEnd(int end) {
		// Caution: here's one place we have to cast
		IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(end);
		// if not well formed, get one past, if there is something there
		if ((result != null) && (!result.isEnded())) {
			if (result.getNext() != null) {
				result = result.getNext();
			}
		}
		// also, get one past if exactly equal to the end (this was needed
		// as a simple fix to when a whole exact region is deleted.
		// there's probably a better way.
		if ((result != null) && (end == result.getEnd())) {
			if (result.getNext() != null) {
				result = result.getNext();
			}
		}

		// 12/6/2001 - Since we've changed the parser/scanner to allow a lone
		// '<' without
		// always interpretting it as start of a tag name, we need to be a
		// little fancier, in order
		// to "skip" over any plain 'ol content between the lone '<' and any
		// potential meating
		// regions past plain 'ol content.
		if (isLoneOpenFollowedByContent(result) && (result.getNext() != null)) {
			result = result.getNext();
		}

		if (result != null)
			fStructuredDocument.setCachedDocumentRegion(result);
		dirtyEnd = result;

		return dirtyEnd;
	}

	protected void findDirtyStart(int start) {
		IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(start);
		// heuristic: if the postion is exactly equal to the start, then
		// go back one more, if it exists. This prevents problems with
		// insertions
		// of text that should be merged with the previous node instead of
		// simply hung
		// off of it as a separate node (ex.: XML content inserted right
		// before an open
		// bracket should become part of the previous content node)
		if (result != null) {
			IStructuredDocumentRegion previous = result.getPrevious();
			if ((previous != null) && ((!(previous.isEnded())) || (start == result.getStart()))) {
				result = previous;
			}
			// If we are now at the end of a "tag dependent" content area (or
			// JSP area)
			// then we need to back up all the way to the beginning of that.
			IStructuredDocumentRegion potential = result;
			while (isPartOfBlockRegion(potential)) {
				potential = potential.getPrevious();
			}
			if (potential != null) {
				result = potential;
				fStructuredDocument.setCachedDocumentRegion(result);
			}
		}
		dirtyStart = result;
	}

	/**
	 * The rule is, that is we are content, preceded by lone <, then we need
	 * to advance one more for dirty end.
	 */
	protected boolean isLoneOpenFollowedByContent(IStructuredDocumentRegion flatNode) {
		boolean result = false;
		String type = flatNode.getType();
		if (type == DOMRegionContext.XML_CONTENT) {
			IStructuredDocumentRegion previous = flatNode.getPrevious();
			String previousType = null;
			if (previous != null) {
				previousType = previous.getType();
			}
			if (previousType != null) {
				result = (previousType == DOMRegionContext.XML_TAG_OPEN);
			}
		}
		return result;
	}

	protected boolean isPartOfBlockRegion(IStructuredDocumentRegion flatNode) {
		boolean result = false;
		String type = flatNode.getType();
		result = (type == DOMRegionContext.BLOCK_TEXT);
		return result;
	}

	public IStructuredTextReParser newInstance() {
		return new XMLStructuredDocumentReParser();
	}

}
