/* apply-changeset.c:
 *
 * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
 ****************************************************************
 * Copyright (C) 2004 Aaron Bentley
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */

#include "hackerlab/arrays/ar.h"
#include "hackerlab/bugs/panic.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/os/errno-to-string.h"
#include "hackerlab/os/sys/wait.h"
#include "hackerlab/fmt/cvt.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/mem/mem.h"
#include "hackerlab/vu/safe.h"

#include "libfsutils/copy-file.h"
#include "libfsutils/ensure-dir.h"
#include "libfsutils/tmp-files.h"
#include "libfsutils/rmrf.h"

#include "libarch/diffs.h"
#include "libarch/exec.h"
#include "libarch/invent.h"
#include "libarch/chatter.h"
#include "libarch/changelogs.h"
#include "libarch/conflict-handling.h"
#include "libarch/make-changeset.h"
#include "libarch/apply-changeset.h"
#include "libarch/inode-sig.h"
#include "libarch/project-tree.h"
#include "libarch/patch-logs.h"
#include "libarch/proj-tree-lint.h"

#include "merge-three-way.h"
static void
progress_dot_callback (void * vfd, char * fmt, va_list ap);

static void
three_way_callback (void * vfd, char * fmt, va_list ap);

static assoc_table tag_index_to_full_paths (arch_project_tree_t * tree);

/* returns
 * 0 on success
 * 1 on conflicts
 * 2 (or exit :[) on failure
 */
int
arch_merge3(int chatter_fd, arch_project_tree_t * mine_tree, arch_project_tree_t * base_tree, arch_project_tree_t * other_tree, int escape_classes, int show_noops)
{
  int dots_for_generation = 1;
  struct arch_make_changeset_report make_report = {0, };
  struct arch_apply_changeset_report * apply_report;

  t_uchar * tmp_dir = talloc_tmp_file_name (talloc_context, mine_tree->root, ",,merge-three-way");
  t_uchar * changeset = file_name_in_vicinity (0, tmp_dir, ",,changeset");
  assoc_table inode_shortcut = 0;

  t_uchar * base_revision = arch_tree_latest_revision (base_tree->root);
 
  assoc_table older_files_table;
  assoc_table yours_files_table;
  
  arch_apply_changeset_report_callback apply_callback = NULL;
  void * apply_thunk = NULL;

  rmrf_file (tmp_dir);
  safe_mkdir (tmp_dir, 0777);

  if (chatter_fd != -1)
    {
      if (dots_for_generation)
        make_report.callback = progress_dot_callback;
      else
        make_report.callback = three_way_callback;
      make_report.thunk = (void *)(long)chatter_fd;
      apply_callback = three_way_callback;
      apply_thunk = (void *)(long)chatter_fd;
    }
  older_files_table = tag_index_to_full_paths (base_tree);
  yours_files_table = tag_index_to_full_paths (other_tree);
  
  arch_read_inode_sig_ids (0, &inode_shortcut, base_tree->root, other_tree->root, base_revision);

  arch_chatter (chatter_fd, "* Comparing FROM and TO");
  if (dots_for_generation)
    arch_chatter (chatter_fd, ": ");
  else
    arch_chatter (chatter_fd, "\n");
    
  arch_make_changeset (&make_report, base_tree, other_tree, changeset, arch_unspecified_id_tagging, arch_inventory_unrecognized, 0, inode_shortcut, 0, escape_classes);
  if (dots_for_generation)
    arch_chatter (chatter_fd, " done.\n");
  arch_chatter (chatter_fd, "* Merging into tree\n");
  apply_report = arch_merge_from_changeset (changeset, talloc_context, mine_tree, arch_unspecified_id_tagging, arch_inventory_unrecognized, older_files_table, yours_files_table, escape_classes, show_noops, apply_callback, apply_thunk);
  rmrf_file (tmp_dir);
  lim_free (0, base_revision);
  lim_free (0, changeset);
  talloc_free (tmp_dir);
  arch_free_make_changeset_report_data (&make_report);
  talloc_free (apply_report);
  return arch_tree_conflicts_exist (mine_tree);
}


static void
progress_dot_callback (void * vfd, char * fmt, va_list ap)
{
  int fd;

  fd = (int)(t_ulong)vfd;
  if (fd >= 0)
    {
      safe_printfmt_va_list (fd, ".", ap);
      safe_flush (fd);
    }
}


static void
three_way_callback (void * vfd, char * fmt, va_list ap)
{
  int fd;

  fd = (int)(t_ulong)vfd;
  if (fd >= 0)
    {
      safe_printfmt_va_list (fd, fmt, ap);
      safe_flush (fd);
    }
}

static assoc_table
tag_index_to_full_paths (arch_project_tree_t * tree)
{
  rel_table index = 0;
  assoc_table answer = 0;
  int x;

  index = arch_source_inventory (tree, 1, 0, 0);
  for (x = 0; x < rel_n_records (index); ++x)
    {
      t_uchar * relpath = index[x][0];
      t_uchar * id = index[x][1];
      t_uchar * full_path = file_name_in_vicinity (0, tree->root, relpath);

      assoc_set (&answer, id, full_path);

      lim_free (0, full_path);
    }

  rel_free_table (index);

  return answer;
}

/* tag: 961f2509-ebf8-43aa-a14d-5b0df3090ec6 */


syntax highlighted by Code2HTML, v. 0.9.1