/*
 * Copyright 2000-2010 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.compiler.impl;

import com.intellij.compiler.impl.generic.GenericCompilerCache;
import com.intellij.compiler.impl.generic.GenericCompilerPersistentData;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.RunResult;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.compiler.CompilerPaths;
import com.intellij.openapi.compiler.generic.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.io.KeyDescriptor;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @author nik
 */
public class GenericCompilerRunner {
  private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.GenericCompilerRunner");
  private static final Logger FULL_LOG = Logger.getInstance("#com.intellij.full-generic-compiler-log");
  private CompileContext myContext;
  private final boolean myForceCompile;
  private final boolean myOnlyCheckStatus;
  private final GenericCompiler<?,?,?>[] myCompilers;
  private final Project myProject;

  public GenericCompilerRunner(CompileContext context,
                               boolean forceCompile,
                               boolean onlyCheckStatus, final GenericCompiler[] compilers) {
    myContext = context;
    myForceCompile = forceCompile;
    myOnlyCheckStatus = onlyCheckStatus;
    myCompilers = compilers;
    myProject = myContext.getProject();
  }

  public boolean invokeCompilers(GenericCompiler.CompileOrderPlace place) throws ExitException {
    boolean didSomething = false;
    try {
      for (GenericCompiler<?,?,?> compiler : myCompilers) {
        if (compiler.getOrderPlace().equals(place)) {
          didSomething |= invokeCompiler(compiler);
        }
      }
    }
    catch (IOException e) {
      LOG.info(e);
      myContext.requestRebuildNextTime(e.getMessage());
      throw new ExitException(ExitStatus.ERRORS);
    }
    catch (ExitException e) {
      throw e;
    }
    catch (ProcessCanceledException e) {
      throw e;
    }
    catch (Exception e) {
      LOG.info(e);
      myContext.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1);
    }
    return didSomething;
  }

  private <Key, SourceState, OutputState> boolean invokeCompiler(GenericCompiler<Key, SourceState, OutputState> compiler) throws IOException,
                                                                                                                                 ExitException {
    return invokeCompiler(compiler, compiler.createInstance(myContext));
  }

  private <T extends BuildTarget, Item extends CompileItem<Key, SourceState, OutputState>, Key, SourceState, OutputState>
  boolean invokeCompiler(GenericCompiler<Key, SourceState, OutputState> compiler, final GenericCompilerInstance<T, Item, Key, SourceState, OutputState> instance) throws IOException,
                                                                                                                                                                         ExitException {
    final GenericCompilerCache<Key, SourceState, OutputState> cache = CompilerCacheManager.getInstance(myProject).getGenericCompilerCache(compiler);
    GenericCompilerPersistentData
      data = new GenericCompilerPersistentData(getGenericCompilerCacheDir(myProject, compiler), compiler.getVersion());
    if (data.isVersionChanged()) {
      LOG.info("Clearing cache for " + compiler.getDescription());
      cache.wipe();
      data.save();
    }

    final Set<String> targetsToRemove = new HashSet<String>(data.getAllTargets());
    new ReadAction() {
      protected void run(final Result result) {
        for (T target : instance.getAllTargets()) {
          targetsToRemove.remove(target.getId());
        }
      }
    }.execute();

    if (!myOnlyCheckStatus) {
      for (final String target : targetsToRemove) {
        final int id = data.removeId(target);
        if (LOG.isDebugEnabled()) {
          LOG.debug("Removing obsolete target '" + target + "' (id=" + id + ")");
        }

        final List<Key> keys = new ArrayList<Key>();
        CompilerUtil.runInContext(myContext, "Processing obsolete targets...", new ThrowableRunnable<IOException>() {
          @Override
          public void run() throws IOException {
            cache.processSources(id, new CommonProcessors.CollectProcessor<Key>(keys));
            List<GenericCompilerCacheState<Key, SourceState, OutputState>> obsoleteSources = new ArrayList<GenericCompilerCacheState<Key,SourceState,OutputState>>();
            for (Key key : keys) {
              final GenericCompilerCache.PersistentStateData<SourceState, OutputState> state = cache.getState(id, key);
              obsoleteSources.add(new GenericCompilerCacheState<Key,SourceState,OutputState>(key, state.mySourceState, state.myOutputState));
            }
            instance.processObsoleteTarget(target, obsoleteSources);
          }
        });
        checkForErrorsOrCanceled();
        for (Key key : keys) {
          cache.remove(id, key);
        }
      }
    }

    final List<T> selectedTargets = new ReadAction<List<T>>() {
      protected void run(final Result<List<T>> result) {
        result.setResult(instance.getSelectedTargets());
      }
    }.execute().getResultObject();

    boolean didSomething = false;
    for (T target : selectedTargets) {
      int id = data.getId(target.getId());
      didSomething |= processTarget(target, id, compiler, instance, cache);
    }

    data.save();
    return didSomething;
  }

  private void checkForErrorsOrCanceled() throws ExitException {
    if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
      throw new ExitException(ExitStatus.ERRORS);
    }
    if (myContext.getProgressIndicator().isCanceled()) {
      throw new ExitException(ExitStatus.CANCELLED);
    }
  }

  public static File getGenericCompilerCacheDir(Project project, GenericCompiler<?,?,?> compiler) {
    return new File(CompilerPaths.getCacheStoreDirectory(project), compiler.getId());
  }

  private <T extends BuildTarget, Item extends CompileItem<Key, SourceState, OutputState>, Key, SourceState, OutputState>
  boolean processTarget(T target, final int targetId, final GenericCompiler<Key, SourceState, OutputState> compiler, final GenericCompilerInstance<T, Item, Key, SourceState, OutputState> instance,
                        final GenericCompilerCache<Key, SourceState, OutputState> cache) throws IOException, ExitException {
    if (LOG.isDebugEnabled()) {
      LOG.debug("Processing target '" + target + "' (id=" + targetId + ") by " + compiler);
    }
    final List<Item> items = instance.getItems(target);
    checkForErrorsOrCanceled();

    final List<GenericCompilerProcessingItem<Item, SourceState, OutputState>> toProcess = new ArrayList<GenericCompilerProcessingItem<Item,SourceState,OutputState>>();
    final THashSet<Key> keySet = new THashSet<Key>(new SourceItemHashingStrategy<Key>(compiler));
    final Ref<IOException> exception = Ref.create(null);
    final Map<Item, SourceState> sourceStates = new HashMap<Item,SourceState>();
    DumbService.getInstance(myProject).runReadActionInSmartMode(new Runnable() {
      @Override
      public void run() {
        try {
          for (Item item : items) {
            final Key key = item.getKey();
            keySet.add(key);
            if (item.isExcluded()) continue;

            final GenericCompilerCache.PersistentStateData<SourceState, OutputState> data = cache.getState(targetId, key);
            SourceState sourceState = data != null ? data.mySourceState : null;
            final OutputState outputState = data != null ? data.myOutputState : null;
            if (myForceCompile || sourceState == null || !item.isSourceUpToDate(sourceState)
                               || outputState == null || !item.isOutputUpToDate(outputState)) {
              sourceStates.put(item, item.computeSourceState());
              toProcess.add(new GenericCompilerProcessingItem<Item,SourceState,OutputState>(item, sourceState, outputState));
            }
          }
        }
        catch (IOException e) {
          exception.set(e);
        }
      }
    });
    if (!exception.isNull()) {
      throw exception.get();
    }

    final List<Key> toRemove = new ArrayList<Key>();
    cache.processSources(targetId, new Processor<Key>() {
      @Override
      public boolean process(Key key) {
        if (!keySet.contains(key)) {
          toRemove.add(key);
        }
        return true;
      }
    });

    if (LOG.isDebugEnabled()) {
      LOG.debug(toProcess.size() + " items will be processed, " + toRemove.size() + " items will be removed");
      for (int i = 0; i < getItemsCountToShowInLog(toProcess.size()); i++) {
        LOG.debug("to process:" + toProcess.get(i).getItem().getKey());
      }
      for (int i = 0; i < getItemsCountToShowInLog(toRemove.size()); i++) {
        LOG.debug("to delete:" + toRemove.get(i));
      }
    }

    if (toProcess.isEmpty() && toRemove.isEmpty()) {
      return false;
    }

    if (myOnlyCheckStatus) {
      throw new ExitException(ExitStatus.CANCELLED);
    }

    List<GenericCompilerCacheState<Key, SourceState, OutputState>> obsoleteItems = new ArrayList<GenericCompilerCacheState<Key,SourceState,OutputState>>();
    for (Key key : toRemove) {
      final GenericCompilerCache.PersistentStateData<SourceState, OutputState> data = cache.getState(targetId, key);
      obsoleteItems.add(new GenericCompilerCacheState<Key,SourceState,OutputState>(key, data.mySourceState, data.myOutputState));
    }

    final List<Item> processedItems = new ArrayList<Item>();
    final List<File> filesToRefresh = new ArrayList<File>();
    final List<File> dirsToRefresh = new ArrayList<File>();
    instance.processItems(target, toProcess, obsoleteItems, new GenericCompilerInstance.OutputConsumer<Item>() {
      @Override
      public void addFileToRefresh(@NotNull File file) {
        filesToRefresh.add(file);
      }

      @Override
      public void addDirectoryToRefresh(@NotNull File dir) {
        dirsToRefresh.add(dir);
      }

      @Override
      public void addProcessedItem(@NotNull Item sourceItem) {
        processedItems.add(sourceItem);
      }
    });
    checkForErrorsOrCanceled();

    CompilerUtil.runInContext(myContext, CompilerBundle.message("progress.updating.caches"), new ThrowableRunnable<IOException>() {
      @Override
      public void run() throws IOException {
        for (Key key : toRemove) {
          cache.remove(targetId, key);
        }
        CompilerUtil.refreshIOFiles(filesToRefresh);
        CompilerUtil.refreshIODirectories(dirsToRefresh);
        if (LOG.isDebugEnabled()) {
          LOG.debug("refreshed " + filesToRefresh.size() + " files and " + dirsToRefresh.size() + " dirs");
          for (int i = 0; i < getItemsCountToShowInLog(filesToRefresh.size()); i++) {
            LOG.debug("file: " + filesToRefresh.get(i));
          }
          for (int i = 0; i < getItemsCountToShowInLog(dirsToRefresh.size()); i++) {
            LOG.debug("dir: " + dirsToRefresh.get(i));
          }
        }

        final RunResult runResult = new ReadAction() {
          protected void run(final Result result) throws Throwable {
            for (Item item : processedItems) {
              SourceState sourceState = sourceStates.get(item);
              if (sourceState == null) {
                sourceState = item.computeSourceState();
              }
              cache.putState(targetId, item.getKey(), sourceState, item.computeOutputState());
            }
          }
        }.executeSilently();
        Throwable throwable = runResult.getThrowable();
        if (throwable instanceof IOException) throw (IOException) throwable;
        else if (throwable != null) throw new RuntimeException(throwable);
      }
    });

    return true;

  }

  private static int getItemsCountToShowInLog(final int size) {
    if (size > 100 && !FULL_LOG.isDebugEnabled()) {
      return 100;
    }
    return size;
  }

  private class SourceItemHashingStrategy<S> implements TObjectHashingStrategy<S> {
    private KeyDescriptor<S> myKeyDescriptor;

    public SourceItemHashingStrategy(GenericCompiler<S, ?, ?> compiler) {
      myKeyDescriptor = compiler.getItemKeyDescriptor();
    }

    @Override
    public int computeHashCode(S object) {
      return myKeyDescriptor.getHashCode(object);
    }

    @Override
    public boolean equals(S o1, S o2) {
      return myKeyDescriptor.isEqual(o1, o2);
    }
  }
}
