 /*******************************************************************************
  * 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
  *
  * Contributor:
  *     Red Hat, Inc. - initial API and implementation
  ******************************************************************************/
package org.jboss.tools.seam.internal.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.XModelObjectConstants;
import org.jboss.tools.common.model.filesystems.impl.FileAnyImpl;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
import org.jboss.tools.seam.core.ISeamComponent;
import org.jboss.tools.seam.core.ISeamElement;
import org.jboss.tools.seam.core.ISeamProject;
import org.jboss.tools.seam.core.ISeamProperty;
import org.jboss.tools.seam.core.ISeamXmlComponentDeclaration;
import org.jboss.tools.seam.core.SeamCorePlugin;
import org.jboss.tools.seam.core.event.ISeamValue;
import org.jboss.tools.seam.core.event.ISeamValueList;
import org.jboss.tools.seam.core.event.ISeamValueString;

/**
 * @author Viacheslav Kabanovich
 */
public class SeamMessagesLoader {
	static class MessageBundle {
		String bundle;
		List<XModelObject> files = new ArrayList<XModelObject>();
		 MessageBundle(String bundle, List<XModelObject> files) {
			 this.bundle = bundle;
			 this.files = files;
		 }
	}
	static List<MessageBundle> EMPTY = new ArrayList<MessageBundle>();
	List<MessageBundle> resources = EMPTY; // Maps the bundleName to the IResource
	Map<String, Long> timestamps = null;
	Set<String> keys = null;
	Map<String, List<XModelObject>> properties = null;
	
	ISeamElement object;
	
	/**
	 *  In Seam 1.2 "org.jboss.seam.core.resourceBundle"
	 *  In Seam 2.0 "org.jboss.seam.core.resourceLoader"
	 */
	String resourceComponent;
	
	public SeamMessagesLoader(ISeamElement object, String resourceComponent) {
		this.object = object;
		this.resourceComponent = resourceComponent;
	}

	public void revalidate() {
		List<MessageBundle> resources2 = getResources();
		if(changed(resources2)) {
			timestamps = new HashMap<String, Long>();
			for (int i = 0; i < resources2.size(); i++) {
				List<XModelObject> r = resources2.get(i).files;
				long q = 0;
				for (XModelObject o: r) q += o.getTimeStamp();
				timestamps.put(resources2.get(i).bundle, q);
			}
			resources = resources2;
			keys = null;
			properties = null;
		}
	}
	
	private boolean changed(List<MessageBundle> resources2) {
		if(resources == resources2) return false;
		if(resources2.size() != resources.size()) return true;
		if(timestamps == null) return true;
		for (int i = 0; i < resources2.size(); i++) {
			List<XModelObject> r2 = resources2.get(i).files;
			List<XModelObject> r1 = resources.get(i).files;
			if(r1 == null || r2.size() == r1.size()) return true;
			long l1 = 0;
			for (XModelObject o: r1) l1 += o.getTimeStamp();
			Long l2 = timestamps.get(resources2.get(i).bundle);
			if(l2 == null || l1 != l2.longValue()) return true;
		}
		
		return false;		
	}	
	
	public List<MessageBundle> getResources() {
		ISeamProject p = object.getSeamProject();
		if(p == null) return EMPTY;
		IResource[] srcs = EclipseResourceUtil.getJavaSourceRoots(p.getProject());
		List<String> names = getNames();
		return names.isEmpty() ? EMPTY : getResources(names, srcs);
	}

	private List<String> getNames() {
		ISeamProject p = object.getSeamProject();
		if(p == null) {
			return new ArrayList<String>();
		}
		ISeamComponent c = p.getComponent(resourceComponent);
		if(c == null) {
			return new ArrayList<String>();
		}
		List<String> names = new ArrayList<String>();
		Set<ISeamXmlComponentDeclaration> ds = c.getXmlDeclarations();
		for (ISeamXmlComponentDeclaration d: ds) {
			ISeamProperty property = d.getProperty("bundleNames");
			if(property == null) continue;
			ISeamValue v = property.getValue();
			if(v == null) continue;
			if(v instanceof ISeamValueList) {
				List<ISeamValueString> vs = ((ISeamValueList)v).getValues();
				for (ISeamValueString s: vs) {
					if(s.getValue() == null) continue;
					String b = s.getValue().getValue();
					names.add(b);
				}
			} else if(v instanceof ISeamValueString) {
				ISeamValueString s = (ISeamValueString)v;
				if(s.getValue() == null) continue;
				String b = s.getValue().getValue();
				if(b == null || b.length() == 0) continue;
				String[] bi = b.split(",");
				for (int i = 0; i < bi.length; i++) {
					names.add(bi[i].trim());
				}
			}
		}
		if(ds.isEmpty()) {
			names.add("messages");
		}
		return names;
	}

	public Collection<ISeamProperty> getProperties() {
		throw new IllegalStateException("Not implemented");
	}

	public Map<String, List<XModelObject>> getPropertiesMap() {
		if(properties == null) {
			properties = new HashMap<String, List<XModelObject>>();
			for (int i = 0; i < resources.size(); i++) {
				List<XModelObject> list = resources.get(i).files;
				for (XModelObject o: list) {
					XModelObject[] ps = o.getChildren();
					for (XModelObject p: ps) {
						String propertyName = p.getAttributeValue(XModelObjectConstants.ATTR_NAME);
						List<XModelObject> vs = properties.get(propertyName);
						if(vs == null) {
							vs = new ArrayList<XModelObject>();
							properties.put(propertyName, vs);
						}
						vs.add(p);
					}
				}
			}
		}
		return properties;
	}
	
	private List<MessageBundle> getResources(List<String> names, IResource[] srcs) {
		List<MessageBundle> rs = new ArrayList<MessageBundle>();
		for (String name: names) {
			String n = name.replace('.', '/');
			int k = n.lastIndexOf('/');
			String p = k < 0 ? null : n.substring(0, k);
			if(k >= 0) n = n.substring(k + 1);
			IResource result = null;
			for (int j = 0; j < srcs.length && result == null; j++) {
				result = find(p, n, srcs[j]);
			}
			if(result != null) {
				List<XModelObject> l = new ArrayList<XModelObject>();
				XModelObject o = EclipseResourceUtil.createObjectForResource(result);
				if(o != null) {
					XModelObject[] os = o.getParent().getChildren();
					String dn = o.getAttributeValue(XModelObjectConstants.ATTR_NAME);
					for (XModelObject c: os) {
						String fileName = FileAnyImpl.toFileName(c);
						if(fileName.endsWith(".properties") && (c == o || fileName.startsWith(dn + "_"))) {
							l.add(c);
						}
					}
					rs.add(new MessageBundle(name, l));
				}
			}
		}
		return rs;
	}
	
	private IResource find(String pack, String name, IResource src) {
		if(!(src instanceof IContainer)) return null;
		IContainer c = (IContainer)src;
		if(pack != null) {
			c = c.getFolder(new Path(pack));
		}
		if(c == null || !c.exists()) return null;
		String suffix = ".properties";
		String name_ = name + "_";
		String name_p = name + suffix;
		IResource result = null;
		try {
			IResource[] rs = c.members();
			for (int i = 0; i < rs.length; i++) {
				String n = rs[i].getName();
				if(name_p.equals(n)) return rs[i];
				if(result == null && n.startsWith(name_) && n.endsWith(suffix)) {
					result = rs[i];
				}
			}
		} catch (CoreException e) {
			SeamCorePlugin.getPluginLog().logError(e);
		}
		
		return result;
	}

}
