package org.jboss.forge.projects.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

import javax.inject.Inject;

import org.jboss.forge.container.addons.AddonRegistry;
import org.jboss.forge.container.services.ExportedInstance;
import org.jboss.forge.convert.Converter;
import org.jboss.forge.projects.Project;
import org.jboss.forge.projects.ProjectFactory;
import org.jboss.forge.projects.ProjectType;
import org.jboss.forge.projects.facets.MetadataFacet;
import org.jboss.forge.resource.DirectoryResource;
import org.jboss.forge.resource.Resource;
import org.jboss.forge.resource.ResourceFactory;
import org.jboss.forge.ui.context.UIBuilder;
import org.jboss.forge.ui.context.UIContext;
import org.jboss.forge.ui.context.UISelection;
import org.jboss.forge.ui.context.UIValidationContext;
import org.jboss.forge.ui.input.SingleValued;
import org.jboss.forge.ui.input.UIInput;
import org.jboss.forge.ui.input.UISelectOne;
import org.jboss.forge.ui.metadata.UICommandMetadata;
import org.jboss.forge.ui.metadata.WithAttributes;
import org.jboss.forge.ui.result.NavigationResult;
import org.jboss.forge.ui.result.Result;
import org.jboss.forge.ui.result.Results;
import org.jboss.forge.ui.util.Categories;
import org.jboss.forge.ui.util.Metadata;
import org.jboss.forge.ui.wizard.UIWizard;

public class NewProjectWizard implements UIWizard
{
   @Inject
   private AddonRegistry registry;

   @Inject
   private ProjectFactory projectFactory;

   @Inject
   private ResourceFactory resourceFactory;

   @Inject
   @WithAttributes(label = "Project name:", required = true)
   private UIInput<String> named;

   @Inject
   @WithAttributes(label = "Top level package:", required = true)
   private UIInput<String> topLevelPackage;

   @Inject
   @WithAttributes(label = "Version:", required = false)
   private UIInput<String> version;

   @Inject
   @WithAttributes(label = "Project location:")
   private UIInput<DirectoryResource> targetLocation;

   @Inject
   @WithAttributes(label = "Overwrite existing project location")
   private UIInput<Boolean> overwrite;

   @Inject
   @WithAttributes(label = "Project Type:", required = true)
   private UISelectOne<ProjectType> type;

   @Override
   public UICommandMetadata getMetadata()
   {
      return Metadata.forCommand(getClass()).name("New Project").description("Create a new project")
               .category(Categories.create("Project", "Generation"));
   }

   @Override
   public boolean isEnabled(UIContext context)
   {
      return true;
   }

   @Override
   public void initializeUI(final UIBuilder builder) throws Exception
   {
      version.setDefaultValue("1.0.0-SNAPSHOT");

      UISelection<Resource<?>> currentSelection = builder.getUIContext().getInitialSelection();
      if (currentSelection != null)
      {
         Resource<?> resource = currentSelection.get();
         if (resource instanceof DirectoryResource)
         {
            targetLocation.setDefaultValue((DirectoryResource) resource);
         }
      }
      else
      {
         targetLocation.setDefaultValue(resourceFactory.create(DirectoryResource.class, new File("")));
      }
      overwrite.setDefaultValue(false).setEnabled(new Callable<Boolean>()
      {
         @Override
         public Boolean call() throws Exception
         {
            String projectName = named.getValue();
            return targetLocation.getValue() != null && projectName != null
                     && targetLocation.getValue().getChild(projectName).exists()
                     && !targetLocation.getValue().getChild(projectName).listResources().isEmpty();
         }
      });

      type.setItemLabelConverter(new Converter<ProjectType, String>()
      {
         @Override
         public String convert(ProjectType source)
         {
            return source == null ? null : source.getType();
         }
      });

      // Add Project types
      List<ProjectType> projectTypes = new ArrayList<ProjectType>();
      for (ExportedInstance<ProjectType> instance : registry.getExportedInstances(ProjectType.class))
      {
         ProjectType projectType = instance.get();
         projectTypes.add(projectType);
         type.setDefaultValue(projectType);
      }
      type.setValueChoices(projectTypes);
      builder.add(named).add(topLevelPackage).add(version).add(targetLocation).add(overwrite).add(type);
   }

   @Override
   public void validate(UIValidationContext context)
   {
      if (!topLevelPackage.getValue().matches("(?i)(~\\.)?([a-z0-9_]+\\.?)+[a-z0-9_]"))
      {
         context.addValidationError(topLevelPackage, "Top level package must be a valid package name.");
      }

      if (overwrite.isEnabled() && overwrite.getValue() == false)
      {
         context.addValidationError(targetLocation, "Target location is not empty.");
      }

   }

   @Override
   public Result execute(UIContext context) throws Exception
   {
      Result result = Results.success("New project has been created.");
      DirectoryResource directory = targetLocation.getValue();
      DirectoryResource targetDir = directory.getChildDirectory(named.getValue());

      if (targetDir.mkdirs() || overwrite.getValue())
      {
         ProjectType value = type.getValue();

         Project project = null;
         if (value != null)
         {
            project = projectFactory.createProject(targetDir, value.getRequiredFacets());
         }
         else
         {
            project = projectFactory.createProject(targetDir);
         }

         if (project != null)
         {
            MetadataFacet metadataFacet = project.getFacet(MetadataFacet.class);
            metadataFacet.setProjectName(named.getValue());
            metadataFacet.setProjectVersion(version.getValue());
            metadataFacet.setTopLevelPackage(topLevelPackage.getValue());

            context.setAttribute(Project.class, project);
         }
         else
            result = Results.fail("Could not create project of type: [" + value + "]");
      }
      else
         result = Results.fail("Could not create target location: " + targetDir);

      return result;
   }

   public UIInput<String> getNamed()
   {
      return named;
   }

   public UIInput<DirectoryResource> getTargetLocation()
   {
      return targetLocation;
   }

   public UIInput<Boolean> getOverwrite()
   {
      return overwrite;
   }

   public UISelectOne<ProjectType> getType()
   {
      return type;
   }

   public SingleValued<UIInput<String>, String> getTopLevelPackage()
   {
      return topLevelPackage;
   }

   @Override
   public NavigationResult next(UIContext context) throws Exception
   {
      if (type.getValue() != null)
      {
         return Results.navigateTo(type.getValue().getSetupFlow());
      }
      else
      {
         return null;
      }
   }
}

@@ -78,24 +78,83 @@
 .ArrayList;%0A
+import java.util.Collections;%0Aimport java.util.Comparator;%0A
 import java.
@@ -4324,24 +4324,402 @@
 e);%0A      %7D%0A
+      Collections.sort(projectTypes, new Comparator%3CProjectType%3E()%0A      %7B%0A         @Override%0A         public int compare(ProjectType left, ProjectType right)%0A         %7B%0A            if (left == null %7C%7C left.getType() == null %7C%7C right == null %7C%7C right.getType() == null)%0A               return 0;%0A            return left.getType().compareTo(right.getType());%0A         %7D%0A      %7D);%0A
       type.s

Put project types in a consistent order