/******************************************************************************* 
 * Copyright (c) 2007 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: 
 * Red Hat, Inc. - initial API and implementation 
 ******************************************************************************/ 
package org.jboss.tools.cdi.xml.beans.model;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.jboss.tools.common.meta.XMapping;
import org.jboss.tools.common.meta.XModelMetaData;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.util.NamespaceMapping;
import org.jboss.tools.common.model.util.XModelObjectLoaderUtil;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

public class CDINamespaces {
	private static Map<String,CDINamespaces> map = new HashMap<String, CDINamespaces>();
	
	public static CDINamespaces getInstance(XModelMetaData meta, String version) {
		CDINamespaces instance = map.get(version);
		if(instance == null) {
			instance = new CDINamespaces(meta, version);
		}
		return instance;
	}
	
	String versionSuffix = null;
	
	private Map<String, String> namespaceToURI = new HashMap<String, String>();
	private Map<String, String> uriToNamespace = new HashMap<String, String>();
	private Map<String, String> namespaceToSchema = new HashMap<String, String>();
	
	private CDINamespaces(XModelMetaData meta, String versionSuffix) {
		XMapping m = meta.getMapping("CDINamespaces"); //$NON-NLS-1$
		if(m == null) return;
		this.versionSuffix = versionSuffix;
		String[] keys = m.getKeys();
		for (int i = 0; i < keys.length; i++) {
			String v = m.getValue(keys[i]);
			namespaceToURI.put(keys[i], v);
			uriToNamespace.put(v, keys[i]);
		}
		m = meta.getMapping("CDISchemas"); //$NON-NLS-1$
		if(m == null) return;
		keys = m.getKeys();
		for (int i = 0; i < keys.length; i++) {
			if(!keys[i].endsWith(versionSuffix)) continue;
			String v = m.getValue(keys[i]);
			String key = keys[i].substring(0, keys[i].length() - versionSuffix.length());
			namespaceToSchema.put(key, v);
		}
	}
	
	static String XMLNS_PREFIX = "xmlns:";	 //$NON-NLS-1$

	public NamespaceMapping getNamespaceMapping(Element element) {
		NamespaceMapping mapping = new NamespaceMapping();
		NamedNodeMap as = element.getAttributes();
		for (int i = 0; i < as.getLength(); i++) {
			Node n = as.item(i);
			String name = n.getNodeName();
			if(name.startsWith(XMLNS_PREFIX)) {
				String actualNamespace = name.substring(XMLNS_PREFIX.length());
				String uri = n.getNodeValue();
				String defaultNamespace = getDefaultNamespace(uri);
				if(defaultNamespace == null) {
					defaultNamespace = name.substring(XMLNS_PREFIX.length());
				}
				if(defaultNamespace == null) continue;
				mapping.addNamespace(defaultNamespace, actualNamespace, uri);
			}
		}
		return mapping;
	}
	
	public String getDefaultNamespace(String uri) {
		return uriToNamespace.get(uri);
	}
	
	public String getURI(String namespace) {
		return namespaceToURI.get(namespace);
	}
	
	public String getSchema(String namespace) {
		return namespaceToSchema.get(namespace);
	}
	
	public void validateNamespaces(XModelObject object, Element element) {
		NamespaceMapping namespaceMapping = NamespaceMapping.load(object);
		if(namespaceMapping == null) namespaceMapping = new NamespaceMapping();
		StringBuffer loc = new StringBuffer();
		loc.append(object.getAttributeValue("xsi:schemaLocation")); //$NON-NLS-1$
		
		doValidateNamespaces(object, element, namespaceMapping, loc);

		object.setAttributeValue("xsi:schemaLocation", loc.toString()); //$NON-NLS-1$
	}

	void doValidateNamespaces(XModelObject object, Element element, NamespaceMapping namespaceMapping, StringBuffer loc) {
		XModelObject[] cs = object.getChildren();
		Set<String> ns = new HashSet<String>();
		for (int i = 0; i < cs.length; i++) {
			String n = null;
			if(cs[i].getModelEntity().getName().equals(XModelObjectLoaderUtil.ENT_ANY_ELEMENT)) {
				n = cs[i].getAttributeValue("tag");
				doValidateNamespaces(cs[i], element, namespaceMapping, loc);
			} else {
				n = cs[i].getModelEntity().getXMLSubPath();
			}
			int k = n.indexOf(':');
			if(k < 0) continue;
			String defaultNamespace = n.substring(0, k);
			if(ns.contains(defaultNamespace)) continue;
			ns.add(defaultNamespace);
			String uri = getURI(defaultNamespace);
			if(uri == null) {
				uri = namespaceMapping.getURIForDefaultNamespace(defaultNamespace);
			}
			if(uri == null) continue;
			String actualNamespace = namespaceMapping.getActualNamespace(defaultNamespace);
			if(actualNamespace == null) actualNamespace = defaultNamespace;
			element.setAttribute(XMLNS_PREFIX + actualNamespace, uri);
			String schema = getSchema(defaultNamespace);
			if(loc.indexOf(uri) < 0 && schema != null) {
				loc.append(' ').append(uri).append(' ').append(schema);
			}
			
		}
	}

}
