package com.dubture.composer.ui.wizard;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import javax.inject.Inject;
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.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IDLTKLanguageToolkit;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.internal.ui.util.CoreUtility;
import org.eclipse.dltk.internal.ui.wizards.BuildpathDetector;
import org.eclipse.dltk.internal.ui.wizards.NewWizardMessages;
import org.eclipse.dltk.ui.util.ExceptionHandler;
import org.eclipse.dltk.ui.wizards.CapabilityConfigurationPage;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.php.internal.core.PHPVersion;
import org.eclipse.php.internal.core.includepath.IncludePath;
import org.eclipse.php.internal.core.language.LanguageModelInitializer;
import org.eclipse.php.internal.core.project.PHPNature;
import org.eclipse.php.internal.core.project.ProjectOptions;
import org.eclipse.php.internal.ui.wizards.IPHPProjectCreateWizardPage;
import org.eclipse.php.internal.ui.wizards.PHPBuildpathDetector;
import org.eclipse.php.ui.util.PHPProjectUtils;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation;
import org.pdtextensions.core.exception.ExecutableNotFoundException;
import org.pdtextensions.core.launch.ScriptLauncher;
import org.pdtextensions.core.launch.ScriptLauncherManager;
import org.pdtextensions.core.ui.PEXUIPlugin;
import com.dubture.composer.core.ComposerPlugin;
import com.dubture.composer.core.ComposerPluginConstants;
import com.dubture.composer.core.ComposerPreferenceConstants;
import com.dubture.composer.core.launch.environment.ComposerEnvironmentFactory;
import com.dubture.composer.core.log.Logger;
import com.dubture.composer.ui.handler.ConsoleResponseHandler;
import com.dubture.composer.ui.job.runner.MissingExecutableRunner;
import com.dubture.getcomposer.core.ComposerPackage;
import com.dubture.getcomposer.core.VersionedPackage;
import com.dubture.getcomposer.core.objects.Namespace;
import com.dubture.getcomposer.packages.PharDownloader;
@SuppressWarnings("restriction")
public abstract class AbstractWizardSecondPage extends CapabilityConfigurationPage implements IPHPProjectCreateWizardPage, Observer {
protected final AbstractWizardFirstPage firstPage;
protected Boolean fIsAutobuild;
protected ScriptLauncher launcher;
protected PharDownloader downloader;
protected URI currentProjectLocation; // null if location is platform locatio
@Inject
protected ScriptLauncherManager launchManager;
public AbstractWizardSecondPage(AbstractWizardFirstPage mainPage, String title) {
super(title);
setPageComplete(false);
setTitle(getPageTitle());
setDescription(getPageDescription());
firstPage = mainPage;
fIsAutobuild = null;
currentProjectLocation = null;
ContextInjectionFactory.inject(this, PEXUIPlugin.getDefault().getEclipseContext());
}
@Override
public void initPage() {
changeToNewProject();
}
@Override
protected String getScriptNature() {
return PHPNature.ID;
}
protected void changeToNewProject() {
firstPage.getDetect();
final IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
if (fIsAutobuild == null) {
fIsAutobuild = Boolean.valueOf(CoreUtility.enableAutoBuild(false));
}
updateProject(monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
} catch (OperationCanceledException e) {
throw new InterruptedException();
} finally {
monitor.done();
}
}
};
try {
getContainer().run(true, false, new WorkspaceModifyDelegatingOperation(op));
} catch (InvocationTargetException e) {
final String title = NewWizardMessages.ScriptProjectWizardSecondPage_error_title;
final String message = NewWizardMessages.ScriptProjectWizardSecondPage_error_message;
ExceptionHandler.handle(e, getShell(), title, message);
} catch (InterruptedException e) {
// cancel pressed
}
}
protected void dumpAutoload(final IProgressMonitor monitor) throws Exception {
try {
launcher = launchManager.getLauncher(ComposerEnvironmentFactory.FACTORY_ID, getProject());
} catch (ExecutableNotFoundException e) {
Display.getDefault().asyncExec(new MissingExecutableRunner());
return;
}
launcher.addResponseListener(new ConsoleResponseHandler());
try {
launcher.launch("dumpautoload");
getProject().refreshLocal(IProject.DEPTH_INFINITE, monitor);
} catch (Exception e) {
Logger.logException(e);
}
}
protected void installComposer(IProgressMonitor monitor) throws CoreException {
// only download composer.phar when config is set to use project phar
IPreferenceStore prefs = ComposerPlugin.getDefault().getPreferenceStore();
if (prefs.getBoolean(ComposerPreferenceConstants.USE_PROJECT_PHAR)) {
downloader = new PharDownloader();
InputStream resource = downloader.download();
IFile file = getProject().getFile("composer.phar");
file.create(resource, true, monitor);
file.refreshLocal(IResource.DEPTH_ZERO, monitor);
}
}
protected void addComposerJson(IProgressMonitor monitor) throws CoreException {
IFile file = getProject().getFile(com.dubture.getcomposer.core.ComposerConstants.COMPOSER_JSON);
Namespace ns = firstPage.getPackage().getAutoload().getPsr4().getFirst();
if (ns != null) {
// if (ns.getNamespace().contains("\\")) {
// String[] split = ns.getNamespace().split("\\\\");
// IPath path = new Path(com.dubture.composer.core.ComposerPluginConstants.DEFAULT_SRC_FOLDER);
// for (String segment : split) {
// path = path.append(segment);
// IFolder folder = getProject().getFolder(path);
// if (!folder.exists()) {
// folder.create(false, true, monitor);
// }
// }
// } else {
// IPath path = new Path(com.dubture.composer.core.ComposerPluginConstants.DEFAULT_SRC_FOLDER).append(ns
// .getNamespace());
IPath path = new Path(com.dubture.composer.core.ComposerPluginConstants.DEFAULT_SRC_FOLDER);
IFolder folder = getProject().getFolder(path);
if (!folder.exists()) {
folder.create(false, true, monitor);
}
// }
}
if (file.exists()) {
Logger.debug("composer.json already exists in the location");
return;
}
ComposerPackage composerPackage = firstPage.getPackage();
VersionedPackage phpVersion = new VersionedPackage();
phpVersion.setName("php");
phpVersion.setVersion(">=" + firstPage.getPHPVersionValue().getAlias().replace("php", ""));
composerPackage.getRequire().add(phpVersion);
ByteArrayInputStream bis = new ByteArrayInputStream(composerPackage.toJson().getBytes());
file.create(bis, true, monitor);
getProject().refreshLocal(0, monitor);
}
protected void setPhpLangOptions() {
boolean useASPTags = false;
PHPVersion phpVersion = firstPage.versionGroup.fConfigurationBlock.getPHPVersionValue();
ProjectOptions.setSupportingAspTags(useASPTags, getProject());
ProjectOptions.setPhpVersion(phpVersion, getProject());
}
protected URI getProjectLocationURI() throws CoreException {
if (firstPage.isInWorkspace()) {
return null;
}
return firstPage.getLocationURI();
}
protected IProject getProject() {
IScriptProject scriptProject = getScriptProject();
if (scriptProject != null) {
return scriptProject.getProject();
}
return null;
}
public void createProject(IProject project, URI locationURI, IProgressMonitor monitor) throws CoreException {
PHPProjectUtils.createProjectAt(project, locationURI, monitor);
}
public IProject getCurrProject() {
return getProject();
}
protected IncludePath[] setProjectBaseIncludepath() {
return new IncludePath[] { new IncludePath(getProject(), getProject()) };
}
protected BuildpathDetector createBuildpathDetector(IProgressMonitor monitor, IDLTKLanguageToolkit toolkit)
throws CoreException {
BuildpathDetector detector = new PHPBuildpathDetector(getProject(), toolkit);
detector.detectBuildpath(new SubProgressMonitor(monitor, 20));
return detector;
}
public void cancel() {
if (downloader != null) {
downloader.abort();
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void updateProject(IProgressMonitor monitor) throws CoreException, InterruptedException {
IProject projectHandle = firstPage.getProjectHandle();
IScriptProject create = DLTKCore.create(projectHandle);
super.init(create, null, false);
currentProjectLocation = getProjectLocationURI();
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
monitor.beginTask("Initializing project", 70);
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
createProject(getProject(), currentProjectLocation, new SubProgressMonitor(monitor, 20));
IBuildpathEntry[] buildpathEntries = null;
//TODO: see https://github.com/pulse00/Composer-Eclipse-Plugin/issues/37
IPath srcPath = new Path(ComposerPluginConstants.DEFAULT_SRC_FOLDER);
if (srcPath.segmentCount() > 0) {
IFolder folder = getProject().getFolder(srcPath);
CoreUtility.createFolder(folder, true, true, new SubProgressMonitor(monitor, 10));
} else {
monitor.worked(10);
}
final IPath projectPath = getProject().getFullPath();
// configure the buildpath entries, including the default
// InterpreterEnvironment library.
List cpEntries = new ArrayList();
cpEntries.add(DLTKCore.newSourceEntry(projectPath.append(srcPath)));
cpEntries.add(DLTKCore.newContainerEntry(LanguageModelInitializer.LANGUAGE_CONTAINER_PATH));
cpEntries.add(DLTKCore.newSourceEntry(projectPath.append("vendor").append("composer")));
buildpathEntries = (IBuildpathEntry[]) cpEntries.toArray(new IBuildpathEntry[cpEntries.size()]);
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
init(DLTKCore.create(getProject()), buildpathEntries, false);
setPhpLangOptions();
configureScriptProject(new SubProgressMonitor(monitor, 30));
// adding build paths, and language-Container:
getScriptProject().setRawBuildpath(buildpathEntries, new NullProgressMonitor());
LanguageModelInitializer.enableLanguageModelFor(getScriptProject());
} finally {
monitor.done();
}
}
public void performFinish(IProgressMonitor monitor) throws CoreException, InterruptedException {
try {
beforeFinish(monitor);
monitor.beginTask("Initializing buildpaths", 10);
if (getProject() == null || !getProject().exists()) {
updateProject(new SubProgressMonitor(monitor, 3));
}
finishPage(monitor);
} catch(Exception e) {
Logger.logException(e);
} finally {
monitor.done();
if (fIsAutobuild != null) {
CoreUtility.enableAutoBuild(fIsAutobuild.booleanValue());
fIsAutobuild = null;
}
}
}
protected void refreshProject(String projectName) {
final IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
if (project == null) {
Logger.log(ERROR, "Error finishing create-project installation. Could not obtain project from workspace: " + projectName);
return;
}
new WorkspaceJob("Refreshing " + projectName) {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
return Status.OK_STATUS;
}
}.schedule();
}
abstract public void update(Observable o, Object arg);
abstract protected String getPageTitle();
abstract protected String getPageDescription();
/**
* Run any logic before the actual project is being created.
*
* @param monitor
* @throws Exception
*/
protected abstract void beforeFinish(IProgressMonitor monitor) throws Exception;
/**
* Run any logic after the project has been created and is ready to use.
*
* @param monitor
* @throws Exception
*/
protected abstract void finishPage(IProgressMonitor monitor) throws Exception;
}