package jetbrains.mps.lang.resources.plugin;

/*Generated by MPS */

import jetbrains.mps.make.facet.IFacet;
import jetbrains.mps.logging.Logger;
import java.util.List;
import jetbrains.mps.make.facet.ITarget;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.make.resources.IPropertiesPersistence;
import jetbrains.mps.make.facet.ITargetEx2;
import jetbrains.mps.make.script.IJob;
import jetbrains.mps.make.script.IResult;
import jetbrains.mps.make.resources.IResource;
import jetbrains.mps.make.script.IJobMonitor;
import jetbrains.mps.make.resources.IPropertiesAccessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.smodel.resources.MResource;
import jetbrains.mps.internal.make.runtime.java.FileProcessor;
import jetbrains.mps.make.delta.IDelta;
import org.jetbrains.mps.openapi.module.SRepository;
import jetbrains.mps.baseLanguage.closures.runtime.Wrappers;
import org.jetbrains.mps.openapi.model.SModel;
import java.util.stream.Stream;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.project.facets.GenerationTargetFacet;
import java.util.Objects;
import jetbrains.mps.make.facets.Make_Facet.Target_make;
import jetbrains.mps.baseLanguage.tuples.runtime.Tuples;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations;
import jetbrains.mps.lang.resources.behavior.Resource__BehaviorDescriptor;
import jetbrains.mps.internal.collections.runtime.NotNullWhereFilter;
import jetbrains.mps.lang.resources.behavior.ResourceGenerationException;
import jetbrains.mps.make.script.IFeedback;
import jetbrains.mps.internal.make.runtime.java.FileDeltaCollector;
import jetbrains.mps.internal.make.runtime.util.FilesDelta;
import jetbrains.mps.internal.make.runtime.util.DeltaKey;
import jetbrains.mps.internal.make.runtime.util.StaleFilesCollector;
import jetbrains.mps.smodel.resources.DResource;
import jetbrains.mps.vfs.FileSystem;
import jetbrains.mps.make.script.IConfig;
import java.util.Map;
import jetbrains.mps.make.script.IPropertiesPool;
import org.jetbrains.mps.openapi.language.SInterfaceConcept;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;

public class Binaries_Facet extends IFacet.Stub {
  private static final Logger LOG = Logger.getLogger(Binaries_Facet.class);
  private List<ITarget> targets = ListSequence.fromList(new ArrayList<ITarget>());
  private IFacet.Name name = new IFacet.Name("jetbrains.mps.lang.resources.Binaries");
  public Binaries_Facet() {
    ListSequence.fromList(targets).addElement(new Target_copyBinaries());
  }
  public Iterable<ITarget> targets() {
    return targets;
  }
  public Iterable<IFacet.Name> optional() {
    return null;
  }
  public Iterable<IFacet.Name> required() {
    return Sequence.fromArray(new IFacet.Name[]{new IFacet.Name("jetbrains.mps.make.facets.Make"), new IFacet.Name("jetbrains.mps.make.facets.Generate")});
  }
  public Iterable<IFacet.Name> extended() {
    return null;
  }
  public IFacet.Name getName() {
    return this.name;
  }
  public IPropertiesPersistence propertiesPersistence() {
    return new TargetProperties();
  }
  public static class Target_copyBinaries implements ITargetEx2 {
    private static final ITarget.Name name = new ITarget.Name("jetbrains.mps.lang.resources.Binaries.copyBinaries");
    public Target_copyBinaries() {
    }
    public IJob createJob() {
      return new IJob.Stub() {
        @Override
        public IResult execute(final Iterable<IResource> rawInput, final IJobMonitor monitor, final IPropertiesAccessor pa, @NotNull final ProgressMonitor progressMonitor) {
          Iterable<IResource> _output_8acy7z_a0a = null;
          final Iterable<MResource> input = (Iterable<MResource>) (Iterable) rawInput;
          switch (0) {
            case 0:
              progressMonitor.start("Copying resources", 2);
              progressMonitor.step("Collecting");

              final FileProcessor fp = new FileProcessor(monitor.getSession().getMessageHandler());
              try {
                final List<IDelta> deltaList = ListSequence.fromList(new ArrayList<IDelta>());

                // XXX there seems to be no need to depend from Generate task now?
                final SRepository repository = monitor.getSession().getProject().getRepository();
                final Wrappers._boolean fail = new Wrappers._boolean(false);
                repository.getModelAccess().runReadAction(() -> {
                  for (final SModel model : Sequence.fromIterable(input).translate((res) -> Sequence.fromIterable(res.models()).ofType(SModel.class))) {
                    Stream<IFile> possibleLocations = GenerationTargetFacet.stream(model).map((GenerationTargetFacet f) -> f.getOutputLocation(model));
                    IFile outputLocation = possibleLocations.filter(Objects::nonNull).findFirst().orElse(null);
                    final IFile outputDir = Target_make.vars(pa.global()).alternateOutput().invoke(outputLocation);
                    Iterable<Tuples._2<IFile, byte[]>> generatedBinaryFiles;
                    try {
                      generatedBinaryFiles = ListSequence.fromList(SModelOperations.nodes(model, CONCEPTS.Resource$gs)).translate((it) -> (List<Tuples._2<IFile, byte[]>>) Resource__BehaviorDescriptor.generate_id7Mb2akaesv8.invoke(it, outputDir)).where(new NotNullWhereFilter()).toList();
                    } catch (ResourceGenerationException rge) {
                      monitor.reportFeedback(new IFeedback.ERROR(String.valueOf(rge.getMessage())));
                      if (LOG.isErrorLevel()) {
                        LOG.error("", rge);
                      }
                      fail.value = true;
                      break;
                    }
                    if (Sequence.fromIterable(generatedBinaryFiles).isEmpty()) {
                      continue;
                    }

                    final FileDeltaCollector fdc = new FileDeltaCollector(new FilesDelta(new DeltaKey(model.getModule(), model)), outputDir, fp);
                    Sequence.fromIterable(generatedBinaryFiles).visitAll((d) -> {
                      if (d._1() != null) {
                        fdc.saveStream(d._0(), d._1());
                      }
                    });
                    if (!(monitor.getSession().isCleanMake())) {
                      // though StaleFilesCollector is discouraged, we need to delete old resource files, therefore we have to use it here unless we move Resource processing into textgen aspect
                      // In case of 'clean' session, it's TextGen facet that collects (and reports as stale) all files under output dir.
                      // For an ordinary build (clean == false), I leave this code as I suppose it may report outdated (aka stale) resource files.
                      // Java files, or anything coming from TextGen facet, are handled by files recorded in 'generated'.
                      // I hope to refactor the whole Make process to keep content creation logic separate from delta authoring, so that we won't need to 
                      // deal with stale 'Resource' artifacts here explicitly, but until then, have to keep ordinary build and renamed resource file scenario in mind
                      new StaleFilesCollector(outputDir).updateDelta(fdc.getDelta());
                    }
                    ListSequence.fromList(deltaList).addElement(fdc.getDelta());
                  }
                });
                if (fail.value) {
                  return new IResult.FAILURE(_output_8acy7z_a0a);
                }

                _output_8acy7z_a0a = Sequence.fromIterable(_output_8acy7z_a0a).concat(Sequence.fromIterable(Sequence.<IResource>singleton(new DResource(deltaList))));

                progressMonitor.advance(1);
                progressMonitor.step("Copying content");

                FileSystem.getInstance().runWriteTransaction(() -> fp.flushChanges());
              } finally {
                progressMonitor.done();
              }
            default:
              progressMonitor.done();
              return new IResult.SUCCESS(_output_8acy7z_a0a);
          }
        }
      };
    }
    public IConfig createConfig() {
      return null;
    }
    public Iterable<ITarget.Name> notAfter() {
      return null;
    }
    public Iterable<ITarget.Name> after() {
      return Sequence.fromArray(new ITarget.Name[]{new ITarget.Name("jetbrains.mps.make.facets.Generate.configure")});
    }
    public Iterable<ITarget.Name> notBefore() {
      return null;
    }
    public Iterable<ITarget.Name> before() {
      return Sequence.fromArray(new ITarget.Name[]{new ITarget.Name("jetbrains.mps.make.facets.Make.make"), new ITarget.Name("jetbrains.mps.make.facets.Make.reconcile")});
    }
    public ITarget.Name getName() {
      return name;
    }
    public boolean isOptional() {
      return false;
    }
    public boolean requiresInput() {
      return true;
    }
    public boolean producesOutput() {
      return true;
    }
    public Iterable<Class<? extends IResource>> expectedInput() {
      List<Class<? extends IResource>> rv = ListSequence.fromList(new ArrayList<Class<? extends IResource>>());
      ListSequence.fromList(rv).addElement(MResource.class);
      return rv;
    }
    public Iterable<Class<? extends IResource>> expectedOutput() {
      return null;
    }
    public <T> T createParameters(Class<T> cls) {
      return null;
    }
    public <T> T createParameters(Class<T> cls, T copyFrom) {
      T t = createParameters(cls);
      return t;
    }
    public int workEstimate() {
      return 100;
    }
  }
  public static class TargetProperties implements IPropertiesPersistence {
    public TargetProperties() {
    }
    public void storeValues(Map<String, String> store, IPropertiesPool properties) {
    }
    public void loadValues(Map<String, String> store, IPropertiesPool properties) {
      try {
      } catch (RuntimeException re) {
      }
    }
  }

  private static final class CONCEPTS {
    /*package*/ static final SInterfaceConcept Resource$gs = MetaAdapterFactory.getInterfaceConcept(0x982eb8df2c964bd7L, 0x996311712ea622e5L, 0x7c8b08a50a39c6caL, "jetbrains.mps.lang.resources.structure.Resource");
  }
}
