package org.applause.lang.ui.builder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.ArrayUtils;
import org.applause.lang.applauseDsl.Application;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xpand2.XpandExecutionContextImpl;
import org.eclipse.xpand2.XpandFacade;
import org.eclipse.xpand2.output.FileHandle;
import org.eclipse.xpand2.output.Outlet;
import org.eclipse.xpand2.output.Output;
import org.eclipse.xpand2.output.OutputImpl;
import org.eclipse.xpand2.output.VetoException;
import org.eclipse.xtend.expression.Variable;
import org.eclipse.xtend.type.impl.java.JavaBeansMetaModel;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.builder.IXtextBuilderParticipant.IBuildContext;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescription.Delta;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
public abstract class AbstractBuildStrategy {
private IProject modelProject;
private IProject platformProject;
private IBuildContext context;
protected IBuildContext getContext() {
return context;
}
public void setContext(IBuildContext context) {
this.context = context;
}
public IProject getModelProject() {
return modelProject;
}
public void setModelProject(IProject modelProject) {
this.modelProject = modelProject;
}
public IProject getPlatformProject() {
return platformProject;
}
public void setPlatformProject(IProject platformProject) {
this.platformProject = platformProject;
}
protected abstract boolean canBuildProject();
public void build(IProgressMonitor monitor) throws CoreException {
if (canBuildProject()) {
final IFolder folder = getPlatformProject().getFolder(getGeneratedSourcesFolderName());
// FIXME: maybe we should just create the folder if it's missing?!
if (!folder.exists())
return;
List<EObject> objects = new ArrayList<EObject>();
for (Delta d : context.getDeltas()) {
if (d.getNew() != null) {
for (IEObjectDescription desc : d.getNew().getExportedObjects()) {
EObject obj = context.getResourceSet().getEObject(desc.getEObjectURI(), true);
EcoreUtil2.resolveAll(context.getResourceSet());
objects.add(obj);
}
}
}
Iterable<Application> applicationObjects = Iterables.filter(objects, Application.class);
if(!Iterables.isEmpty(applicationObjects)) {
deletePreviouslyGeneratedFiles(monitor, folder);
}
for (Application app : applicationObjects) {
OutputImpl output = new OutputImpl();
Outlet outlet = createOutlet(folder);
configureOutlet(outlet);
output.addOutlet(outlet);
// IFolder rootFolder = (IFolder) getPlatformProject().getAdapter(IFolder.class);
// // IPath location = getPlatformProject().getFullPath();
// // IFolder rootFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(location);
// Outlet projectRootOutlet = createOutlet(rootFolder);
// projectRootOutlet.setName("ROOT");
// output.addOutlet(projectRootOutlet);
generate(app, output);
copyResources(app, getModelProject().getFolder("/Images"));
getPlatformProject().build(IncrementalProjectBuilder.CLEAN_BUILD, monitor);
return;
}
}
}
protected boolean isFileInHighResFolder(IFile file) {
String[] segments = file.getFullPath().segments();
return ArrayUtils.contains(segments, "highres");
}
protected void copyResources(Application app, IFolder sourceFolder) throws CoreException {
Collection<IFile> allImageFiles = collectAllImageFiles(sourceFolder);
Predicate<IFile> highresPredicate = new Predicate<IFile>() {
@Override
public boolean apply(IFile input) {
if (input.getName().contains("@2x")) {
return true;
}
else if (isFileInHighResFolder(input)) {
return true;
}
return false;
}
};
Iterable<IFile> highresImages = Iterables.filter(allImageFiles, highresPredicate);
Predicate<IFile> lowresPredicate = Predicates.not(highresPredicate);
Iterable<IFile> lowresImages = Iterables.filter(allImageFiles, lowresPredicate);
copyLowResImages(lowresImages);
copyHighResImages(highresImages);
copySplash(app, sourceFolder);
}
protected abstract void copySplash(Application app, IFolder folder) throws CoreException;
protected abstract IFolder getHighResImageDestinationFolder(IFile file);
protected abstract String getHighResImageFileName(String normalizedFileName);
protected abstract IFolder getImageDestinationFolder(IFile file);
protected abstract String getImageFileName(String normalizedFileName);
private String getNormalizedFileName(IFile file) {
String baseName = FilenameUtils.getBaseName(file.getName());
if (baseName.endsWith("@2x")) {
return baseName.substring(0, baseName.lastIndexOf("@2x")) + "." + file.getFileExtension();
}
else {
return file.getName();
}
}
private void copyHighResImages(Iterable<IFile> highresImages) throws CoreException {
for (IFile file : highresImages) {
IFolder destinationFolder = getHighResImageDestinationFolder(file);
String imageFileName = getHighResImageFileName(getNormalizedFileName(file));
if ( (destinationFolder != null) && (imageFileName != null)) {
if (isValidFilename(FilenameUtils.getBaseName(imageFileName))) {
IFile targetFile = destinationFolder.getFile(imageFileName);
if (!targetFile.exists()) {
file.copy(targetFile.getFullPath(), true, null);
}
}
}
}
}
private void copyLowResImages(Iterable<IFile> lowresImages) throws CoreException {
for (IFile file : lowresImages) {
IFolder destinationFolder = getImageDestinationFolder(file);
String imageFileName = getImageFileName(getNormalizedFileName(file));
if ( (destinationFolder != null) && (imageFileName != null)) {
if (isValidFilename(FilenameUtils.getBaseName(imageFileName))) {
IFile targetFile = destinationFolder.getFile(imageFileName);
if (!targetFile.exists()) {
file.copy(targetFile.getFullPath(), true, null);
}
}
}
}
}
protected static final String[] IMAGE_FILE_EXTS = {"png", "jpg"};
protected boolean isImageFile(IFile file) {
return (ArrayUtils.contains(IMAGE_FILE_EXTS, file.getFileExtension()));
}
protected boolean isValidFilename(String filename) {
return true;
}
protected Collection<IFile> collectAllImageFiles(IFolder sourceFolder) throws CoreException {
Collection<IFile> files = new ArrayList<IFile>();
IResource[] members = sourceFolder.members();
for (IResource resource : members) {
if (resource instanceof IFile) {
IFile file = (IFile)resource;
if (isImageFile(file)) {
files.add(file);
}
}
else if (resource instanceof IFolder) {
files.addAll(collectAllImageFiles((IFolder)resource));
}
}
return files;
}
private Outlet createOutlet(final IFolder folder) {
Outlet outlet = new Outlet() {
@Override
public FileHandle createFileHandle(String qualifiedName) throws VetoException {
return AbstractBuildStrategy.this.createFileHandle(folder, this, qualifiedName);
}
};
return outlet;
}
protected void deletePreviouslyGeneratedFiles(IProgressMonitor monitor, final IFolder folder) throws CoreException {
for (IResource res : folder.members()) {
if (res instanceof IFile) {
IFile file = (IFile) res;
file.delete(true, monitor);
}
}
}
protected abstract void configureOutlet(Outlet outlet);
protected FileHandle createFileHandle(IFolder folder, Outlet outlet, String qualifiedName) {
IFile file = folder.getFile(new Path(qualifiedName));
try {
file.setDerived(true, new NullProgressMonitor());
} catch (CoreException e) {
}
return new EclipseBasedFileHandle(file, outlet);
}
protected abstract String getGeneratedSourcesFolderName();
public void generate(Application app, Output output) {
System.out.println("Generating code for platform project " + getPlatformProject().getName() + " from model in model project " + context.getBuiltProject());
XpandExecutionContextImpl ctx = new XpandExecutionContextImpl(output, null, Collections.<String, Variable>emptyMap(), null, null);
ctx.registerMetaModel(new JavaBeansMetaModel());
try {
XpandFacade.create(ctx).evaluate(getMainTemplateName(), app);
} catch (Exception e) {
e.printStackTrace();
}
}
protected abstract String getMainTemplateName();
protected IFile findFile(IContainer container, String fileSpec) {
Pattern pattern = Pattern.compile(fileSpec);
try {
IResource[] members = container.members();
for (IResource resource : members) {
if (resource instanceof IFile) {
IFile file = (IFile) resource;
if (pattern.matcher(file.getName()).matches()) {
return file;
}
}
}
} catch (CoreException e) {
e.printStackTrace();
}
return null;
}
public abstract String getName();
}