/*******************************************************************************
 * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is 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:
 *     Exadel, Inc. and Red Hat, Inc. - initial API and implementation
 ******************************************************************************/ 
package org.jboss.tools.common.model.util;

import java.util.*;
import org.w3c.dom.*;

public class XMLMapper {
	Map<Node, int[]> mapping = new HashMap<Node, int[]>();
	String text;
	
	public XMLMapper(Document document, String text) {
		this.text = text;
		process(document);
	}
	
	int process(Node node, int index) {
		int type = node.getNodeType();
		switch (type) {
			case Node.TEXT_NODE : return processText((Text)node, index);
			case Node.CDATA_SECTION_NODE : return processCDATA((CharacterData)node, index);
			case Node.ELEMENT_NODE : return processElement((Element)node, index);
			case Node.ATTRIBUTE_NODE : return processAttr((Attr)node, index);
			case Node.COMMENT_NODE : return processComment((Comment)node, index);
		}
		return index;
	}
	
	int process(Document document) {
		int index = 0;
		NodeList n = document.getChildNodes();
		for (int i = 0; i < n.getLength(); i++) {
			Node node = n.item(i);
			index = process(node, index);
		}
		return index;
	}
	
	int processElement(Element node, int index) {
		NodeList n = node.getChildNodes();
		int start = text.indexOf("<" + node.getNodeName(), index); //$NON-NLS-1$
		
		NamedNodeMap as = node.getAttributes();
		if(as != null) for (int i = 0; i < as.getLength(); i++) {
			Attr a = (Attr)as.item(i);
			String name = a.getNodeName();
			int ns = text.indexOf(name, start);
			if(ns < 0) continue;
			int q1 = text.indexOf('"', ns);
			int q2 = text.indexOf('"', q1 + 1);
			mapping.put(a, new int[]{ns, q2 + 1 - ns});			
			put(node, ns, q2 + 1 - ns);
		}
		
		int headerEnd = text.indexOf('>', start);
		if(text.charAt(headerEnd - 1) == '/') {
			put(node, start, headerEnd + 1);
			return headerEnd + 1;
		}
		int ciindex = headerEnd + 1;
		for (int i = 0; i < n.getLength(); i++) {
			Node cn = n.item(i);
			ciindex = process(cn, ciindex);
		}
		String token = "</" + node.getNodeName() + ">"; //$NON-NLS-1$ //$NON-NLS-2$
		int end = text.indexOf(token, ciindex) + token.length();
		put(node, start, end);
		
		return end;
	}

	int processText(Text node, int index) {
		int start = index;
		int end = text.indexOf('<', index);
		put(node, start, end);
		return end;
	}

	int processCDATA(CharacterData node, int index) {
		int start = text.indexOf("<![CDATA[", index); //$NON-NLS-1$
		int end = text.indexOf("]]>", index) + 3; //$NON-NLS-1$
		put(node, start, end);
		return end;
	}
	
	int processAttr(Attr node, int index) {
		
		return index;
	}

	int processComment(Comment node, int index) {
		int start = text.indexOf("<!--", index); //$NON-NLS-1$
		int end = text.indexOf("-->", index) + 3; //$NON-NLS-1$
		put(node, start, end);
		return end;
	}
	
	void put(Node node, int start, int end) {
		mapping.put(node, new int[]{start, end - start});
	}


}
