// Copyright 2008-2010 Victor Iacoban
//
// 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 org.zmlx.hg4idea.command;

import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.messages.MessageBus;
import com.intellij.vcsUtil.VcsFileUtil;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.HgFile;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.HgVcsMessages;
import org.zmlx.hg4idea.execution.HgCommandException;
import org.zmlx.hg4idea.execution.HgCommandExecutor;
import org.zmlx.hg4idea.util.HgEncodingUtil;
import org.zmlx.hg4idea.util.HgUtil;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import static org.zmlx.hg4idea.HgErrorHandler.ensureSuccess;

public class HgCommitCommand {

  private static final String TEMP_FILE_NAME = ".hg4idea-commit.tmp";

  private final Project myProject;
  private final VirtualFile myRoot;
  private final String myMessage;

  private Set<HgFile> myFiles = Collections.emptySet();

  public HgCommitCommand(Project project, @NotNull VirtualFile root, String message) {
    myProject = project;
    myRoot = root;
    myMessage = message;
  }

  public void setFiles(@NotNull Set<HgFile> files) {
    myFiles = files;
  }

  public void execute() throws HgCommandException, VcsException {
    if (StringUtil.isEmptyOrSpaces(myMessage)) {
      throw new HgCommandException(HgVcsMessages.message("hg4idea.commit.error.messageEmpty"));
    }
    List<String> relativePaths = HgUtil.getRelativePathsByRepository(myFiles).get(myRoot);
    //if it's merge commit, so myFiles is Empty. Need to commit all files in changeList, can't call setFiles() method.
    // see HgCheckinEnviroment->commit() method
    if (relativePaths == null) {
      List<String> parameters = new LinkedList<String>();
      parameters.add("--logfile");
      parameters.add(saveCommitMessage().getAbsolutePath());
      ensureSuccess(new HgCommandExecutor(myProject).executeInCurrentThread(myRoot, "commit", parameters));
    }
    else {
      for (List<String> chunk : VcsFileUtil.chunkRelativePaths(relativePaths)) {
        List<String> parameters = new LinkedList<String>();
        parameters.add("--logfile");
        parameters.add(saveCommitMessage().getAbsolutePath());
        parameters.addAll(chunk);
        ensureSuccess(new HgCommandExecutor(myProject).executeInCurrentThread(myRoot, "commit", parameters));
      }
    }
    final MessageBus messageBus = myProject.getMessageBus();
    messageBus.syncPublisher(HgVcs.REMOTE_TOPIC).update(myProject, null);
    messageBus.syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null);
  }

  private File saveCommitMessage() throws VcsException {
    File systemDir = new File(PathManager.getSystemPath());
    File tempFile = new File(systemDir, TEMP_FILE_NAME);
    
    try {
      FileUtil.writeToFile(tempFile, myMessage.getBytes(HgEncodingUtil.getDefaultCharset()));
    } catch (IOException e) {
      throw new VcsException("Couldn't prepare commit message", e);
    }
    return tempFile;
  }

}

@@ -898,24 +898,110 @@
 irtualFile;%0A
+import com.intellij.util.Function;%0Aimport com.intellij.util.containers.ContainerUtil;%0A
 import com.i
@@ -1374,45 +1374,8 @@
 til;
-%0Aimport org.zmlx.hg4idea.util.HgUtil;
 %0A%0Aim
@@ -2315,99 +2315,8 @@
   %7D%0A
-    List%3CString%3E relativePaths = HgUtil.getRelativePathsByRepository(myFiles).get(myRoot);%0A
     
@@ -2402,38 +2402,8 @@
 List
-, can't call setFiles() method
 .%0A  
@@ -2460,80 +2460,191 @@
 if (
-relativePaths == null) %7B%0A      List%3CString%3E parameters = new LinkedList%3C
+myFiles.isEmpty()) %7B%0A      commitChunkFiles(Collections.%3CString%3EemptyList());%0A    %7D%0A    else %7B%0A      List%3CString%3E relativePaths = ContainerUtil.map2List(myFiles, new Function%3CHgFile, 
 Stri
@@ -2652,214 +2652,115 @@
 g%3E()
-;
+ %7B
 %0A      
-parameters.add(%22--logfile%22);%0A      parameters.add(saveCommitMessage().getAbsolutePath());%0A      ensureSuccess(new HgCommandExecutor(myProject).executeInCurrentThread(myRoot, %22commit%22, parameters)
+  @Override%0A        public String fun(HgFile file) %7B%0A          return file.getRelativePath(
 );%0A
+    
     
@@ -2761,30 +2761,29 @@
       %7D%0A    
-else %7B
+  %7D);
 %0A      for (
@@ -2852,24 +2852,355 @@
 ths)) %7B%0A    
+    commitChunkFiles(chunk);%0A      %7D%0A    %7D%0A    final MessageBus messageBus = myProject.getMessageBus();%0A    messageBus.syncPublisher(HgVcs.REMOTE_TOPIC).update(myProject, null);%0A    messageBus.syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null);%0A  %7D%0A%0A  private void commitChunkFiles(List%3CString%3E chunk) throws VcsException %7B%0A
     List%3CStr
@@ -3239,28 +3239,24 @@
 %3CString%3E();%0A
-    
     paramete
@@ -3276,20 +3276,16 @@
 file%22);%0A
-    
     para
@@ -3335,20 +3335,16 @@
 ath());%0A
-    
     para
@@ -3365,20 +3365,16 @@
 chunk);%0A
-    
     ensu
@@ -3475,231 +3475,8 @@
 ));%0A
-      %7D%0A    %7D%0A    final MessageBus messageBus = myProject.getMessageBus();%0A    messageBus.syncPublisher(HgVcs.REMOTE_TOPIC).update(myProject, null);%0A    messageBus.syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null);%0A
   %7D%0A

Refactor (CR-26): get just relative paths for files, instead of getRelativePathsByRepository(), delete code duplication