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

#include "hackerlab/bugs/panic.h"
#include "hackerlab/char/str.h"
#include "tla/libarch/namespace.h"
#include "tla/libarch/patch-logs.h"
#include "tla/libarch/missing.h"


/* __STDC__ prototypes for static functions */
static int is_a_patch_present (rel_table has, t_uchar *log);
static rel_table get_all_arch_logs (t_uchar *tree_root, struct arch_archive * arch);





rel_table
arch_missing (t_uchar * tree_root, struct arch_archive * arch, t_uchar * version, int skip_present)
{
  rel_table has = rel_table_nil;
  rel_table needs = rel_table_nil;
  rel_table answer = rel_table_nil;

  invariant (arch_valid_package_name (version, arch_no_archive, arch_req_version, 0));

  has = arch_logs (tree_root, arch->name, version, 0);
  needs = arch_archive_revisions (arch, version, 0);

  rel_sort_table_by_field (0, has, 0);
  rel_sort_table_by_field (0, needs, 0);

  answer = rel_join (2, rel_join_output (2,0, -1), 0, 0, has, needs);

  arch_sort_table_by_patch_level_field (0, answer, 0);

  if (skip_present)
    answer = arch_filter_present_logs (tree_root, arch, version, answer);

  rel_free_table (has);
  rel_free_table (needs);
  return answer;
}

int
arch_revision_has_present_patch (t_uchar * tree_root, struct arch_archive * arch, t_uchar * revision)
{
  int answer = 0;
  rel_table has = rel_table_nil;
  t_uchar * log = 0;

  has = get_all_arch_logs (tree_root, arch);
  log = arch_archive_log (arch, revision);

  answer = is_a_patch_present (has, log);

  rel_free_table (has);
  return answer;
}



static int
is_a_patch_present (rel_table has, t_uchar *log)
{
  assoc_table headers = 0;
  const t_uchar * new_patches_header;
  rel_table new_patches = rel_table_nil;
  rel_table result = rel_table_nil;
  int found = 0;

  arch_parse_log (0, &headers, 0, log);
  new_patches_header = assoc_get_str_taking (headers, rel_make_field_str ("new-patches"));

  new_patches = rel_ws_split (new_patches_header);
  rel_sort_table_by_field (0, new_patches, 0);
  rel_uniq_by_field (&new_patches, 0);

  result = rel_join (-1, rel_join_output(1,0,2,0,-1), 0, 0, has, new_patches);
  if (rel_n_records (result) > 0)
    found = 1;

  free_assoc_table (headers);
  rel_free_table (new_patches);
  rel_free_table (result);
  return found;
}

static rel_table
get_all_arch_logs (t_uchar *tree_root, struct arch_archive * arch)
{
    rel_table versions = rel_table_nil;
    rel_table result = rel_table_nil;
    int x;
    versions = arch_log_versions (tree_root,0,0,0,0);
    for (x = 0; x < rel_n_records (versions); ++x)
      {
        rel_table version_logs = rel_table_nil;
        t_uchar * archive;
        t_uchar * revision;
        archive = arch_parse_package_name (arch_ret_archive, 0 , rel_peek_str (versions, x, 0));
        revision = arch_parse_package_name (arch_ret_non_archive, 0, rel_peek_str (versions, x, 0));
        version_logs = arch_logs (tree_root, archive, revision, 1);
        rel_append_x (&result, version_logs);
        lim_free (0, revision);
        lim_free (0, archive);
        rel_free_table (version_logs);
      }

    rel_free_table (versions);
    rel_sort_table_by_field (0, result, 0);
    return result;
}

rel_table
arch_filter_present_logs (t_uchar * tree_root, struct arch_archive * arch, t_uchar * version, rel_table unfiltered)
{
    rel_table has = rel_table_nil;
    rel_table to_skip = rel_table_nil;
    rel_table answer = rel_table_nil;
    int x;
    if (rel_n_records (unfiltered) < 1)
        return unfiltered;

    has = get_all_arch_logs (tree_root,arch);

    for (x = 0; x < rel_n_records (unfiltered); ++x)
      {
        t_uchar * revision = str_alloc_cat_many (0, version, "--", rel_peek_str (unfiltered, x, 0), str_end);
        t_uchar * log = 0;

        log = arch_archive_log (arch, revision);

        if (is_a_patch_present(has, log))
            rel_add_records (&to_skip, rel_copy_record (rel_peek_record (unfiltered, x)), rel_record_null);
        lim_free (0, revision);
      }
    rel_free_table (has);
    rel_sort_table_by_field (0, to_skip, 0);
    rel_sort_table_by_field (0, unfiltered, 0);
    answer = rel_join (1, rel_join_output (1,0, -1), 0, 0, unfiltered, to_skip);
    arch_sort_table_by_patch_level_field (0, answer, 0);
    rel_free_table (unfiltered);
    rel_free_table (to_skip);
    return answer;
}




/* tag: Tom Lord Sat May 24 23:01:13 2003 (whats-missing.c)
 */
