/*******************************************************************************
 * Copyright (c) 2001, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Jens Lukowski/Innoopract - initial renaming/restructuring
 *     
 *******************************************************************************/
package org.eclipse.wst.dtd.core.internal;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.swt.graphics.Image;
import org.eclipse.wst.dtd.core.internal.parser.DTDRegionTypes;
import org.eclipse.wst.dtd.core.internal.text.RegionIterator;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.w3c.dom.Node;


public class Element extends NamedTopLevelNode {

	List attListList = new ArrayList();

	List attributes = new ArrayList();

	protected CMNode fContentModel;

	public Element(DTDFile dtdFile, IStructuredDocumentRegion flatNode) {
		super(dtdFile, flatNode, DTDRegionTypes.ELEMENT_TAG);
	}

	public void addAttribute(String name) {
		beginRecording(this, DTDCoreMessages._UI_LABEL_ELEMENT_ADD_ATTR); //$NON-NLS-1$
		List attLists = getAttributeLists();
		if (attLists.size() == 0) {
			getDTDFile().createAttributeList(this, getName(), true);
			attLists = getAttributeLists();
		}
		if (attLists.size() > 0) {
			AttributeList attList = (AttributeList) attLists.get(attLists.size() - 1);
			attList.addAttribute(name);
		}
		endRecording(this);
	}

	public void addChild() {
		beginRecording(this, DTDCoreMessages._UI_LABEL_ELEMENT_ADD_CHILD); //$NON-NLS-1$
		addContent(this, " EMPTY"); //$NON-NLS-1$
		endRecording(this);
	}

	protected void addContent(Object requestor, String content) {
		ITextRegion whitespace = getWhitespaceAfterName();
		int startOffset = 0;
		int length = 0;
		if (whitespace != null) {
			startOffset = getStructuredDTDDocumentRegion().getStartOffset(whitespace);
			length = whitespace.getLength() >= 2 ? 1 : 0;
		}
		else {
			ITextRegion nameRegion = getNameRegion();
			if (nameRegion != null) {
				startOffset = getStructuredDTDDocumentRegion().getEndOffset(nameRegion);
			}
			else {
				ITextRegion elementTag = getNextRegion(iterator(), DTDRegionTypes.ELEMENT_TAG);
				startOffset = getStructuredDTDDocumentRegion().getEndOffset(elementTag);
			}
		}
		replaceText(requestor, startOffset, length, content);
	}

	public void addGroup() {
		beginRecording(this, DTDCoreMessages._UI_LABEL_ELEMENT_ADD_GRP); //$NON-NLS-1$
		addContent(this, " ()"); //$NON-NLS-1$
		endRecording(this);
	}

	public Node cloneNode(boolean deep) {
		return new Element(dtdFile, flatNode);
	}

	public List getAttributeLists() {
		attListList.clear();
		String elementName = getName();
		Iterator iter = dtdFile.getNodes().iterator();
		while (iter.hasNext()) {
			DTDNode node = (DTDNode) iter.next();
			if (node instanceof AttributeList && node.getName().equals(elementName)) {
				attListList.add(node);
			}
		}
		return attListList;
	}



	public CMNode getContentModel() {
		// Object[] children = getChildren()
		return (CMNode) getFirstChild();// contentModel;
	}

	public List getElementAttributes() {
		attributes.clear();
		Iterator attLists = getAttributeLists().iterator();
		while (attLists.hasNext()) {
			AttributeList attList = (AttributeList) attLists.next();

			Object[] children = attList.getChildren();
			for (int i = 0; i < children.length; i++) {
				attributes.add(children[i]);
			}
		}
		return attributes;
	}

	public Image getImage() {
		return DTDCorePlugin.getInstance().getImage(DTDResource.ELEMENTICON);
	}

	public short getNodeType() {
		return Node.ELEMENT_NODE;
	}

	public void replaceContentModel(Object requestor, CMNode node) {
		replaceContentModel(requestor, node.getNodeText());
	}

	public void replaceContentModel(Object requestor, String nodeText) {
		int offset = 0;
		int length = 0;
		CMNode contentModel = getContentModel();
		if (contentModel != null) {
			offset = contentModel.getStartOffset();
			length = contentModel.getWhitespaceEndOffset() - offset;
			replaceText(requestor, offset, length, nodeText);
		}
		else {
			addContent(requestor, nodeText);
		}
	}

	public void resolveRegions() {
		// System.out.println("element node stream = " +
		// tokenStream.getString());
		fContentModel = null;
		removeChildNodes();
		RegionIterator iter = iterator();

		if (getNameRegion() != null) {
			// we skip past the name token is our name
			skipPastName(iter);
		}

		while (iter.hasNext()) {
			ITextRegion currentRegion = iter.next();

			if (fContentModel == null) {
				if (currentRegion.getType().equals(DTDRegionTypes.NAME)) {
					fContentModel = new CMBasicNode(getDTDFile(), getStructuredDTDDocumentRegion());
				}
				else if (currentRegion.getType().equals(DTDRegionTypes.CONTENT_PCDATA)) {
					fContentModel = new CMBasicNode(getDTDFile(), getStructuredDTDDocumentRegion());
				}
				else if (currentRegion.getType().equals(DTDRegionTypes.LEFT_PAREN)) {
					fContentModel = new CMGroupNode(getDTDFile(), getStructuredDTDDocumentRegion());
				}
			}

			if (fContentModel != null) {
				if (!currentRegion.getType().equals(DTDRegionTypes.END_TAG)) {
					// content model gets all regions except for the '>'
					fContentModel.addRegion(currentRegion);
				}
				else {
					// if it is equal to the end tag, then don't add anymore
					// regions
					// for the content model
					break;
				}

			}

		}
		if (fContentModel != null) {
			appendChild(fContentModel);
			// this is the root element content so set it true
			fContentModel.setRootElementContent(true);
			// now tell the content model to resolve it's regions
			fContentModel.resolveRegions();

		}
	}

	public void setContentModel(CMNode contentModel) {
		this.fContentModel = contentModel;
	}
}
