/* archive-setup.c:
 *
 * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/bugs/panic.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/arrays/ar.h"
#include "hackerlab/char/str.h"
#include "hackerlab/vu/safe.h"
#include "libawk/associative.h"
#include "libarch/chatter.h"
#include "libarch/namespace.h"
#include "libarch/archive.h"
#include "libarch/tag.h"
#include "libarch/archive-cache.h"
#include "libarch/archive-setup.h"


/* __STDC__ prototypes for static functions */
static struct arch_archive * find_archive (struct arch_archive ** archs, t_uchar * name);



void
arch_setup_archive_simple (int chatter_fd,
                           t_uchar * archive_spec,
                           t_uchar * revision_spec)
{
  rel_table wants = 0;

  rel_add_records (&wants, rel_make_record (archive_spec, revision_spec, 0), 0);
  arch_setup_archive (chatter_fd, wants, arch_archive_setup_no_tags, 0);

  rel_free_table (wants);
}

/**
 * \brief setup a branch in an archive somewhere
 *
 * TODO: FIXME-REMOVENAME give .._ext url + namespace elements, 
 * not registered-names. then we can change registered_name to location
 * below
 */
void
arch_setup_archive_simple_ext (int chatter_fd,
			       struct arch_archive * arch,
			       t_uchar * revision_spec)
{
  rel_table wants = 0;

  rel_add_records (&wants, rel_make_record (arch->registered_name, revision_spec, 0), 0);
  arch_setup_archive_ext (chatter_fd, wants, arch_archive_setup_no_tags, 0, arch);

  rel_free_table (wants);
}

void
arch_setup_archive (int chatter_fd, rel_table wants, enum arch_archive_setup_tag_op tag_op, int archive_cache)
{
    arch_setup_archive_ext (chatter_fd, wants, tag_op, archive_cache, NULL);
}

static void
arch_archive_populate_fqcategory_exists (struct arch_archive *arch, assoc_table * fqcategory_exists)
{
    int c;
    rel_table categories = arch_archive_categories (arch);
    for (c = 0; c < rel_n_records (categories); ++c)
      {
	t_uchar * cat = 0;
	
	cat = arch_fully_qualify (arch->official_name, categories[c][0]);
	assoc_set (fqcategory_exists, cat, "yes");
	
	lim_free (0, cat);
      }
    
    rel_free_table (categories);
}

void
arch_setup_archive_ext (int chatter_fd, rel_table wants, enum arch_archive_setup_tag_op tag_op, int archive_cache, struct arch_archive * initial_arch)
{
  t_uchar * errstr = 0;
  struct arch_archive ** archs = 0;
  assoc_table fqcategories_checked = 0;
  assoc_table fqbranches_checked = 0;
  assoc_table fqcategory_exists = 0;
  assoc_table fqbranch_exists = 0;
  assoc_table fqversion_exists = 0;
  int x;


  if (initial_arch)
      ar_push_arch_archive (&archs, initial_arch);

  for (x = 0; x < rel_n_records (wants); ++x)
    {
      t_uchar * archive;
      struct arch_archive * arch = 0;
      t_uchar * spec;
      t_uchar * category = 0;
      t_uchar * fqcategory = 0;

      archive = wants[x][0];

      arch = find_archive (archs, archive);

      if (!arch)
        {
          arch = arch_archive_connect_branch (archive, NULL);
          if (!arch)
            {
              safe_printfmt (2, "Could not connect to archive %s ", archive);
              exit (2);
            }
          ar_push_arch_archive (&archs, arch);

	  arch_archive_populate_fqcategory_exists (arch, &fqcategory_exists);
	}

      if (!fqcategory_exists)
	  arch_archive_populate_fqcategory_exists (arch, &fqcategory_exists);

      spec = wants[x][1];

      category = arch_parse_package_name (arch_ret_category, 0, spec);
      fqcategory = arch_fully_qualify (arch->official_name, category);

      if (arch->type != arch_archive_baz && !assoc_ref (fqcategory_exists, fqcategory))
        {
          arch_chatter (chatter_fd, "* creating category %s/%s\n", arch->official_name, category);
          if (arch_make_category (&errstr, arch, category))
            {
              safe_printfmt (2, "archive-setup: error making category %s/%s in %s (%s)\n", arch->official_name, category, arch->location, errstr);
              exit (1);
            }
          assoc_set (&fqcategory_exists, fqcategory, "yes");
        }

      if (str_cmp (spec, category))
        {
          if (arch_valid_package_name (spec, arch_no_archive, arch_req_package, 1))
            {
              t_uchar * branch = 0;
              t_uchar * fqbranch = 0;

              branch = arch_parse_package_name (arch_ret_package, 0, spec);
              fqbranch = arch_fully_qualify (arch->official_name, branch);

              if (!assoc_ref (fqcategories_checked, fqcategory))
                {
                  rel_table branches = 0;
                  int b;

                  branches = arch_archive_branches (arch, category);
                  for (b = 0; b < rel_n_records (branches); ++b)
                    {
                      t_uchar * bran = 0;

                      bran = arch_fully_qualify (arch->official_name, branches[b][0]);
                      assoc_set (&fqbranch_exists, bran, "yes");

                      lim_free (0, bran);
                    }

                  rel_free_table (branches);
                }

              if (arch->type != arch_archive_baz && !assoc_ref (fqbranch_exists, fqbranch))
                {
                  arch_chatter (chatter_fd, "* creating branch %s/%s\n", arch->official_name, branch);
                  if (arch_make_branch (&errstr, arch, branch))
                    {
                      safe_printfmt (2, "archive-setup: error making branch %s/%s (%s)\n", arch->official_name, branch, errstr);
                      exit (1);
                    }
                  assoc_set (&fqbranch_exists, fqbranch, "yes");
                }

              if (arch_valid_package_name (spec, arch_no_archive, arch_req_version, 0))
                {
                  t_uchar * version = 0;
                  t_uchar * fqversion = 0;

                  version = arch_parse_package_name (arch_ret_package_version, 0, spec);
                  fqversion = arch_fully_qualify (arch->official_name, version);

                  if (!assoc_ref (fqbranches_checked, fqbranch))
                    {
                      rel_table versions = 0;
                      int v;

                      versions = arch_archive_versions (arch, branch);
                      for (v = 0; v < rel_n_records (versions); ++v)
                        {
                          t_uchar * vers = 0;
                          vers = arch_fully_qualify (arch->official_name, versions[v][0]);
                          assoc_set (&fqversion_exists, vers, "yes");
                          lim_free (0, vers);
                        }

                      rel_free_table (versions);
                    }

                  if (!assoc_ref (fqversion_exists, fqversion))
                    {
                      arch_chatter (chatter_fd, "* creating version %s/%s\n", arch->official_name, version);
                      if (arch_make_version (&errstr, arch, version))
                        {
                          safe_printfmt (2, "archive-setup: error making version %s/%s (%s)\n", arch->official_name, version, errstr);
                          exit (1);
                        }
                      assoc_set (&fqversion_exists, fqversion, "yes");
                    }

                  if (tag_op != arch_archive_setup_no_tags)
                    {
                      rel_table has_revisions = 0;

                      t_uchar * tag_from_archive;
                      t_uchar * tag_from_rev_spec;

                      struct arch_archive * from_arch = 0;
                      t_uchar * tag_from_version = 0;
                      rel_table from_has_revisions = 0;

                      arch_chatter (chatter_fd, "* creating tag in %s/%s\n", arch->official_name, version);
                      has_revisions = arch_archive_revisions (arch, version, 0);

                      tag_from_archive = wants[x][2];
                      tag_from_rev_spec = wants[x][3];

                      from_arch = find_archive (archs, tag_from_archive);
                      if (!from_arch)
                        {
                          /* FIXME-REMOVENAME use the namespace out facility */
                          from_arch = arch_archive_connect_branch (tag_from_archive, NULL);
                          if (!arch)
                            {
                              safe_printfmt (2, "Could not connect to archive %s ", archive);
                              exit (2);
                            }
                          ar_push_arch_archive (&archs, from_arch);
                        }

                      tag_from_version = arch_parse_package_name (arch_ret_package_version, 0, tag_from_rev_spec);
                      from_has_revisions = arch_archive_revisions (from_arch, tag_from_version, 0);

                      switch (tag_op)
                        {
                        default:
                          {
                            panic ("archive-setup.c internal error");
                            break;
                          }
                        case arch_archive_setup_make_base0_tag:
                          {
                            if (has_revisions)
                              arch_chatter (chatter_fd, " ...skipping, base-0 already exists");
                            else
                              {
                                t_uchar * tag_revision = 0;
                                t_uchar * tag_from_revision = 0;

                                tag_revision = str_alloc_cat (0, version, "--base-0");

                                if (arch_valid_package_name (tag_from_rev_spec, 0, arch_req_patch_level, 0))
                                  tag_from_revision = arch_parse_package_name (arch_ret_non_archive, 0, tag_from_rev_spec);
                                else if (from_has_revisions)
                                  tag_from_revision = str_alloc_cat_many (0, tag_from_version, "--", from_has_revisions[rel_n_records (from_has_revisions) - 1][0], str_end);

                                if (tag_from_revision)
                                  {
                                    tag_method_t * tag = arch_tag (talloc_context, chatter_fd, arch, tag_revision, from_arch, tag_from_revision, 0);
                                    if (archive_cache)
                                      arch_tag_cacherev (tag);
                                    talloc_free (tag);
                                  }

                                lim_free (0, tag_from_revision);
                                lim_free (0, tag_revision);
                              }

                            break;
                          }
                        }

                      rel_free_table (has_revisions);
                      lim_free (0, tag_from_version);
                      rel_free_table (from_has_revisions);
                    }

                  lim_free (0, version);
                  lim_free (0, fqversion);
                }

              lim_free (0, branch);
              lim_free (0, fqbranch);
            }
        }
      lim_free (0, category);
      lim_free (0, fqcategory);
    }

  for (x = 0; x < ar_size_arch_archive (archs); ++x)
    if (archs[x] != initial_arch)
	arch_archive_close (archs[x]);

  ar_free_arch_archive (&archs);
  free_assoc_table (fqcategories_checked);
  free_assoc_table (fqbranches_checked);
  free_assoc_table (fqcategory_exists);
  free_assoc_table (fqbranch_exists);
  free_assoc_table (fqversion_exists);
}


/**
 * \brief find an archive in the local cache.
 * 
 * TODO, FIXME-REMOVENAME - replace registered_name with location here,
 * and in all callers.
 */
static struct arch_archive *
find_archive (struct arch_archive ** archs, t_uchar * name)
{
  int x;

  for (x = 0; x < ar_size_arch_archive (archs); ++x)
    if (!str_cmp (name, archs[x]->registered_name))
      return archs[x];

  return 0;
}



/* tag: Tom Lord Wed Jun 11 11:58:43 2003 (archive-setup.c)
 */


syntax highlighted by Code2HTML, v. 0.9.1