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

#include "hackerlab/arrays/ar.h"
#include "hackerlab/char/str.h"
#include "tla/libarch/archives.h"
#include "tla/libarch/namespace.h"
#include "tla/libarch/merge-points.h"
#include "tla/libarch/ancestry.h"


/* __STDC__ prototypes for static functions */
static struct arch_archive * find_or_maybe_connect (struct arch_archive *** cache, t_uchar * name);



rel_table
arch_trace_ancestry (struct arch_archive * arch, t_uchar * archive, t_uchar * revision, int merges)
{
  struct arch_archive ** archives = 0;
  rel_table answer = rel_table_nil;
  int done = 0;

  archive = str_save (0, archive);
  revision = str_save (0, revision);

  if (arch)
    *(struct arch_archive **)ar_push ((void **)&archives, 0, sizeof (struct arch_archive *)) = arch;

  while (!done)
    {
      t_uchar * fq_rev = 0;
      struct arch_archive * this_arch = 0;

      fq_rev = arch_fully_qualify (archive, revision);
      this_arch = find_or_maybe_connect (&archives, archive);

      if (!this_arch)
        {
          rel_add_records (&answer, rel_make_record_2_taking (rel_make_field_str (fq_rev), rel_make_field_str ("???")), rel_record_null);
          done = 1;
        }
      else
        {
          t_uchar * ancestor = 0;

          if (!merges)
            rel_add_records (&answer, rel_make_record_2_taking (rel_make_field_str (fq_rev), rel_make_field_str (fq_rev)), rel_record_null);
          else
            {
              enum arch_revision_type type;

              arch_revision_type (&type, 0, this_arch, revision);

              if (type == arch_continuation_revision)
                {
                  rel_add_records (&answer, rel_make_record_2_taking (rel_make_field_str (fq_rev), rel_make_field_str (fq_rev)), rel_record_null);
                }
              else
                {
                  rel_table merges = rel_table_nil;
                  int x;

                  merges = arch_archive_merge_points (this_arch, revision, 0, 0, 0);
                  for (x = 0; x < rel_n_records (merges); ++x)
                    {
                      rel_add_records (&answer, rel_make_record_2_taking (rel_make_field_str (fq_rev), rel_get_field (merges, x, 1)), rel_record_null);
                    }
                  rel_free_table (merges);
                }
            }

          ancestor = arch_ancestor_revision (this_arch, revision);

          if (!ancestor)
            {
              done = 1;
            }
          else
            {
              lim_free (0, archive);
              lim_free (0, revision);

              archive = arch_parse_package_name (arch_ret_archive, 0, ancestor);
              revision = arch_parse_package_name (arch_ret_non_archive, 0, ancestor);
            }

          lim_free (0, ancestor);
        }

      lim_free (0, fq_rev);
    }

  {
    int a;

    for (a = 0; a < ar_size ((void *)archives, 0, sizeof (struct arch_archive *)); ++a)
      {
        if (archives[a] != arch)
          arch_archive_close (archives[a]);
      }
    ar_free ((void **)&archives, 0);
  }

  lim_free (0, archive);
  lim_free (0, revision);
  return answer;
}



static struct arch_archive *
find_or_maybe_connect (struct arch_archive *** cache, t_uchar * name)
{
  int a;
  t_uchar * loc = 0;
  struct arch_archive * arch = 0;

  for (a = 0; a < ar_size ((void *)(*cache), 0, sizeof (struct arch_archive *)); ++a)
    {
      if (!str_cmp (name, (*cache)[a]->name))
        return (*cache)[a];
    }

  loc = arch_archive_location (name, 1);

  if (loc)
    {
      arch = arch_archive_connect (name, 0);
      *(struct arch_archive **)ar_push ((void **)cache, 0, sizeof (struct arch_archive **)) = arch;
    }

  lim_free (0, loc);
  return arch;
}




/* tag: Tom Lord Thu Jun 26 18:41:53 2003 (ancestry.c)
 */
