/* undo.c:
 *
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/char/str.h"
#include "hackerlab/char/char-class.h"
#include "hackerlab/fmt/cvt.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "tla/libfsutils/dir-listing.h"
#include "tla/libfsutils/rmrf.h"
#include "tla/libarch/make-changeset.h"
#include "tla/libarch/apply-changeset.h"
#include "tla/libarch/chatter.h"
#include "tla/libarch/undo.h"


/* __STDC__ prototypes for static functions */
static void undo_callback (void * vfd, const char * fmt, va_list ap);



void
arch_undo (int chatter_fd, t_uchar * dest_dir, int delete_changeset, t_uchar * tree_root,
           t_uchar * baseline_root, rel_table file_list, assoc_table inode_shortcut, int forward,   int escape_classes)
{
  struct arch_make_changeset_report make_report = {0, };
  struct arch_apply_changeset_report apply_report = {0, };

  if (!rel_n_records (file_list))
    arch_make_changeset (&make_report, baseline_root, tree_root, dest_dir, arch_unspecified_id_tagging, arch_inventory_unrecognized, rel_table_nil, inode_shortcut, 0, escape_classes);
  else
    arch_make_files_changeset (&make_report, dest_dir, file_list, baseline_root, tree_root, arch_unspecified_id_tagging, arch_inventory_unrecognized, escape_classes);

  arch_chatter (chatter_fd, "* reverting changes\n");
  if (chatter_fd >= 0)
    {
      apply_report.callback = undo_callback;
      apply_report.thunk = (void *)(long)chatter_fd;
    }

  arch_apply_changeset (&apply_report, dest_dir, tree_root, arch_unspecified_id_tagging, arch_inventory_unrecognized, 1, forward, 0, 0, 0, escape_classes);

  if (delete_changeset)
    rmrf_file (dest_dir);
}

t_uchar *
arch_latest_undo_changeset (t_ulong * level_n, t_uchar * tree_root)
{
  rel_table files = rel_table_nil;
  t_uchar * answer = 0;
  t_ulong latest_n = 0;
  int x;

  files = directory_files (tree_root);

  for (x = 0; x < rel_n_records (files); ++x)
    {
      if (!str_cmp_prefix (",,undo-", rel_peek_str (files, x, 0)))
        {
          int ign;
          const t_uchar * pos;
          t_ulong this_n;

          for (pos = rel_peek_str (files, x, 0) + sizeof (",,undo-") - 1; char_is_digit (*pos); ++pos)
            ;

          if (*pos)
            continue;

          pos = rel_peek_str (files, x, 0) + sizeof (",,undo-") - 1;
          if (cvt_decimal_to_ulong (&ign, &this_n, pos, str_length (pos)))
            continue;

          if (this_n >= latest_n)
            {
              lim_free (0, answer);
              answer = file_name_in_vicinity (0, tree_root, rel_peek_str (files, x, 0));
              if (level_n)
                *level_n = this_n;

              latest_n = this_n;
            }
        }
    }

  rel_free_table (files);
  return answer;
}

t_uchar *
arch_next_undo_changeset (t_ulong * level_n, t_uchar * tree_root)
{
  t_uchar * prev = 0;
  t_ulong prev_n;
  t_uchar * this = 0;
  t_uchar * answer = 0;

  prev = arch_latest_undo_changeset (&prev_n, tree_root);

  if (!prev)
    {
      if (level_n)
        *level_n = 1;
      this = str_save (0, ",,undo-1");
    }
  else
    {
      t_uchar buf[64];

      cvt_ulong_to_decimal (buf, prev_n + 1);
      this = str_alloc_cat (0, ",,undo-", buf);
    }

  answer = file_name_in_vicinity (0, tree_root, this);

  lim_free (0, prev);
  lim_free (0, this);
  return answer;
}




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

  fd = (int)(t_ulong)vfd;
  safe_printfmt_va_list (fd, fmt, ap);
  safe_flush (fd);
}





/* tag: Tom Lord Thu May 29 14:20:31 2003 (undo.c)
 */
