package org.jboss.tools.jsf.project;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.jboss.tools.common.model.XModel;
import org.jboss.tools.common.model.XModelConstants;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.XModelObjectConstants;
import org.jboss.tools.common.model.filesystems.FileSystemsHelper;
import org.jboss.tools.common.model.impl.XModelImpl;
import org.jboss.tools.common.model.project.IAutoLoad;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
import org.jboss.tools.common.model.util.XModelObjectUtil;
import org.jboss.tools.common.util.FileUtil;
import org.jboss.tools.jsf.model.pv.JSFProjectsTree;
import org.jboss.tools.jst.web.WebUtils;
import org.jboss.tools.jst.web.model.pv.WebProjectNode;

public class JSFAutoLoad implements IAutoLoad, XModelObjectConstants {
	static String WEB_INF = "WEB-INF"; //$NON-NLS-1$
	static String WEB_ROOT = "WEB-ROOT"; //$NON-NLS-1$

	public void load(XModel model) {
		XModelObject fs = FileSystemsHelper.getFileSystems(model);
		IProject project = EclipseResourceUtil.getProject(fs);
		if(project == null) return;
		
		fs.setAttributeValue("application name", project.getName()); //$NON-NLS-1$
		
		XModelObject s = createFileSystemFolder(model, project.getName(), project.getLocation().toString());
		fs.addChild(s);
		
		XModelObject webinf = createFileSystemFolder(model, WEB_INF, XModelConstants.WORKSPACE_REF);
		fs.addChild(webinf);

		String webInfLocation = XModelObjectUtil.expand(XModelConstants.WORKSPACE_REF, model, null);
		List<String> webRootLocations = getWebRootPaths(project, webInfLocation);

		int i = 0;
		for (String webRootLocation: webRootLocations) {
			String name = WEB_ROOT;
			if(i > 0) name += "-" + i;
			XModelObject webroot = createFileSystemFolder(model, name, webRootLocation);
			fs.addChild(webroot);
			i++;		
		}

		XModelObject lib = createFileSystemFolder(model, "lib", XModelConstants.WORKSPACE_REF + "/lib"); //$NON-NLS-1$ //$NON-NLS-2$
		fs.addChild(lib);		
		
	}
	XModelObject createFileSystemFolder(XModel model, String name, String location) {
		XModelObject f = model.createModelObject(ENT_FILE_SYSTEM_FOLDER, null);
		f.setAttributeValue(ATTR_NAME, name);
		f.setAttributeValue(ATTR_NAME_LOCATION, location);
		return f;
	}
	

	public void update(XModel model) {
		XModelObject fs = FileSystemsHelper.getFileSystems(model);
		IProject project = EclipseResourceUtil.getProject(fs);
		if(project == null) return;

		String webInfLocation = XModelObjectUtil.expand(XModelConstants.WORKSPACE_REF, model, null);
		List<String> webRootLocations = getWebRootPaths(project, webInfLocation);

		boolean modified = false;
		XModelObject webinf = fs.getChildByPath(WEB_INF);
		String rWebInfLocation = getWebInfPath(project, webInfLocation);
		if(rWebInfLocation != null) {
			if(webinf != null && !rWebInfLocation.equals(webinf.getAttributeValue(ATTR_NAME_LOCATION))) {
				webinf.removeFromParent();
				webinf = null;
				modified = true;
			}
			if(webinf == null) {
				webinf = createFileSystemFolder(model, WEB_INF, rWebInfLocation);
				fs.addChild(webinf);
				modified = true;
			}
		} else if(webinf != null) {
			webinf.removeFromParent();
			modified = true;
		}
		
		List<XModelObject> existingRoots = getExistingWebRoots(fs);
		boolean rootsChanged = rootsChanged(webRootLocations, existingRoots);
		if(rootsChanged) {
			modified = true;
			for (XModelObject c: existingRoots) {
				c.removeFromParent();
			}
			int i = 0;
			for (String webRootLocation: webRootLocations) {
				String name = WEB_ROOT;
				if(i > 0) name += "-" + i;
				XModelObject webroot = createFileSystemFolder(model, name, webRootLocation);
				fs.addChild(webroot);
				i++;		
			}
		}
		
		if(modified) {
			((XModelImpl)fs.getModel()).fireStructureChanged(fs);
			WebProjectNode n = JSFProjectsTree.getProjectsRoot(model);
			if(n != null) {
				n.invalidate();
			}
		}
	}

	boolean rootsChanged(List<String> webRootLocations, List<XModelObject> rs) {
		if(webRootLocations.size() != rs.size()) return true;
		for (int i = 0; i < webRootLocations.size(); i++) {
			String s = webRootLocations.get(i);
			XModelObject o = rs.get(i);
			if(!o.getAttributeValue(ATTR_NAME_LOCATION).equals(s)) {
				return true;
			}
		}
		return false;
	}

	List<XModelObject> getExistingWebRoots(XModelObject fs) {
		List<XModelObject> result = new ArrayList<XModelObject>();
		XModelObject[] cs = fs.getChildren(ENT_FILE_SYSTEM_FOLDER);
		for (XModelObject c: cs) {
			if(c.getAttributeValue(ATTR_NAME).startsWith(WEB_ROOT)) {
				result.add(c);
			}
		}
		return result;
	}

	static List<String> getWebRootPaths(IProject project, String webInfLocation) {
		List<String> result = new ArrayList<String>();
		IContainer[] cs = WebUtils.getWebRootFolders(project);
		for (IContainer c: cs) {
			IPath path = c.getLocation();
			if(path == null) continue;
			String webRootLocation = null;
			try {
				webRootLocation = path.toFile().getCanonicalPath().replace('\\', '/');
				String relative = FileUtil.getRelativePath(webInfLocation, webRootLocation);
				if(relative != null) {
					webRootLocation = XModelConstants.WORKSPACE_REF + relative;
				}
				result.add(webRootLocation);
			} catch (IOException e) {
				continue;
			}
		}
		return result;
	}

	static String getWebInfPath(IProject project, String webInfLocation) {
		IVirtualComponent component = ComponentCore.createComponent(project);	
		if(component != null && component.getRootFolder() != null) {
			String virtual = null;
			IContainer[] cs = WebUtils.getWebRootFolders(project, true);
			for (IContainer c: cs) {
				if(c.exists()) {
					IFolder f = c.getFolder(new Path("/WEB-INF")); //$NON-NLS-1$
					if(f.exists()) {
						//If one of web roots contains WEB-INF, return it.
						try {
							String location = f.getLocation().toFile().getCanonicalPath().replace('\\', '/');
							String relative = FileUtil.getRelativePath(webInfLocation, location);
							return (relative != null) ? XModelConstants.WORKSPACE_REF + relative : location;
						} catch (IOException e) {
							continue;
						}
					} else if(virtual == null) {
						//Find the first web root without WEB-INF, and return it if there is no web root with WEB-INF.
						//For advanced servers, WEB-INF folder is not required.
						try {
							String location = c.getLocation().toFile().getCanonicalPath().replace('\\', '/') + "/WEB-INF";
							String relative = FileUtil.getRelativePath(webInfLocation, location);
							virtual = (relative != null) ? XModelConstants.WORKSPACE_REF + relative : location;
						} catch (IOException e) {
							continue;
						}
					}
				}
			}
			if(virtual != null) {
				return virtual;
			}
		}
		return null;
	}

}
