@SuppressWarnings("unchecked")
  private static void fillStates(
      @NotNull Collection<Module> modules,
      @NotNull Map<Module, AndroidFileSetState> resourcesStates,
      @NotNull Map<Module, AndroidFileSetState> assetsStates)
      throws IOException {
    for (Module module : modules) {
      final AndroidFacet facet = AndroidJpsUtil.getFacet(module);

      if (facet != null) {
        final File resourceDir = facet.getResourceDir();
        final List<String> resourceDirs =
            resourceDir != null
                ? Arrays.asList(resourceDir.getPath())
                : Collections.<String>emptyList();
        resourcesStates.put(module, new AndroidFileSetState(resourceDirs, Condition.TRUE, true));

        final File assetsDir = facet.getAssetsDir();
        final List<String> assetDirs =
            assetsDir != null
                ? Arrays.asList(assetsDir.getPath())
                : Collections.<String>emptyList();
        assetsStates.put(module, new AndroidFileSetState(assetDirs, Condition.TRUE, true));
      }
    }
  }
  @SuppressWarnings("unchecked")
  private static AndroidFileSetState buildCurrentApkBuilderState(
      @NotNull Project project,
      @NotNull String resPackagePath,
      @NotNull String classesDexFilePath,
      @NotNull String[] nativeLibDirs,
      @NotNull String[] sourceRoots,
      @NotNull String[] externalJars,
      boolean release) {
    final List<String> roots = new ArrayList<String>();
    roots.add(resPackagePath);
    roots.add(classesDexFilePath);
    roots.addAll(Arrays.asList(externalJars));

    for (String sourceRootPath : sourceRoots) {
      final List<File> files = new ArrayList<File>();
      AndroidApkBuilder.collectStandardSourceFolderResources(
          new File(sourceRootPath), files, new MyExcludedSourcesFilter(project));
      roots.addAll(AndroidJpsUtil.toPaths(files));
    }

    for (String nativeLibDir : nativeLibDirs) {
      final List<File> files = new ArrayList<File>();
      AndroidApkBuilder.collectNativeLibraries(new File(nativeLibDir), files, !release);
      roots.addAll(AndroidJpsUtil.toPaths(files));
    }

    return new AndroidFileSetState(roots, Condition.TRUE, false);
  }
    public <T> void logMany(final PrintStream stream, final Collection<T> list) {
      final String[] a = new String[list.size()];
      int i = 0;

      for (T e : list) {
        a[i++] = e.toString();
      }

      Arrays.sort(a);

      for (String o : a) {
        stream.println(o);
      }
    }
  public ModuleLevelBuilder.ExitCode build(final CompileContext context, ModuleChunk chunk)
      throws ProjectBuildException {
    try {
      final List<File> toCompile = collectChangedFiles(context, chunk);
      if (toCompile.isEmpty()) {
        return ExitCode.NOTHING_DONE;
      }

      String moduleOutput = getModuleOutput(context, chunk);
      String compilerOutput = getCompilerOutput(moduleOutput);

      final Set<String> toCompilePaths = new LinkedHashSet<String>();
      for (File file : toCompile) {
        toCompilePaths.add(FileUtil.toSystemIndependentName(file.getPath()));
      }

      Map<String, String> class2Src =
          buildClassToSourceMap(chunk, context, toCompilePaths, moduleOutput);

      String ideCharset = chunk.getProject().getProjectCharset();
      String encoding =
          !Comparing.equal(CharsetToolkit.getDefaultSystemCharset().name(), ideCharset)
              ? ideCharset
              : null;
      List<String> patchers = Collections.emptyList(); // todo patchers
      final File tempFile =
          GroovycOSProcessHandler.fillFileWithGroovycParameters(
              compilerOutput,
              toCompilePaths,
              FileUtil.toSystemDependentName(moduleOutput),
              class2Src,
              encoding,
              patchers);

      // todo different outputs in a chunk
      // todo xmx
      final List<String> cmd =
          ExternalProcessUtil.buildJavaCommandLine(
              getJavaExecutable(chunk),
              "org.jetbrains.groovy.compiler.rt.GroovycRunner",
              Collections.<String>emptyList(),
              new ArrayList<String>(generateClasspath(context, chunk)),
              Arrays.asList(
                  "-Xmx384m",
                  "-Dfile.encoding=" + CharsetToolkit.getDefaultSystemCharset().name() /*,
                      "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5239"*/),
              Arrays.<String>asList(myForStubs ? "stubs" : "groovyc", tempFile.getPath()));

      final Process process = Runtime.getRuntime().exec(ArrayUtil.toStringArray(cmd));
      GroovycOSProcessHandler handler =
          GroovycOSProcessHandler.runGroovyc(
              process,
              new Consumer<String>() {
                public void consume(String s) {
                  context.processMessage(new ProgressMessage(s));
                }
              });

      if (handler.shouldRetry()) {
        if (CHUNK_REBUILD_ORDERED.get(context) != null) {
          CHUNK_REBUILD_ORDERED.set(context, null);
        } else {
          CHUNK_REBUILD_ORDERED.set(context, Boolean.TRUE);
          return ExitCode.CHUNK_REBUILD_REQUIRED;
        }
      }

      if (myForStubs) {
        JavaBuilder.addTempSourcePathRoot(context, new File(compilerOutput));
      }

      for (CompilerMessage message : handler.getCompilerMessages()) {
        context.processMessage(message);
      }
      if (!myForStubs
          && updateDependencies(
              context, chunk, toCompile, moduleOutput, handler.getSuccessfullyCompiled())) {
        return ExitCode.ADDITIONAL_PASS_REQUIRED;
      }
      return ExitCode.OK;
    } catch (Exception e) {
      throw new ProjectBuildException(e);
    }
  }