/* inventory-file.c:
 *
 * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
 ****************************************************************
 * Copyright (C) 2005 Canonical Limited
 *    Authors: Robert Collins <robert.collins@canonical.com>
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/bugs/panic.h"
#include "hackerlab/vu/safe.h"
#include "hackerlab/fs/cwd.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/char/str.h"
#include "po/gettext.h"
#include "libfsutils/file-contents.h"
#include "libawk/trim.h"
#include "libarch/ancestry.h"
#include "libarch/namespace.h"
#include "libarch/patch-id.h"
#include "libarch/patch-logs.h"
#include "libarch/changelogs.h"
#include "libarch/inv-ids.h"
#include "libarch/invent.h"
#include "libarch/project-tree.h"
#include "libarch/debug.h"
#include "libarch/inventory-entry.h"

inventory_entry_vtable_t inventory_file_vtable = 
{
  NULL,
  NULL,
  arch_project_tree_vtable_end
};

static inventory_entry_t * inventory_dir_add_child (inventory_entry_t * entry, inventory_entry_t * child);
static inventory_entry_t * inventory_dir_get_child (inventory_entry_t * entry, t_uchar const * const name);

inventory_entry_vtable_t inventory_dir_vtable = 
{
  inventory_dir_add_child,
  inventory_dir_get_child,
  arch_project_tree_vtable_end
};

inventory_file_t *
inventory_file_new (inventory_file_t * parent, t_uchar const * const name, t_uchar const * const id)
{
    inventory_file_t *result = talloc (NULL, inventory_file_t);
    inventory_file_init (result, parent, name, id);
    result->vtable = &inventory_file_vtable;
    return result;
}

void
inventory_file_init (inventory_file_t * file, inventory_file_t * parent, t_uchar const * const name, t_uchar const * const id)
{
    file->vtable = &inventory_file_vtable;
    file->name = talloc_strdup (file, name);
    file->id = talloc_strdup (file, id);
    if (parent)
        file->parent = inventory_entry_add_child (parent, file) ? parent : NULL;
    else
        file->parent = NULL;
}

int
inventory_file_finalise (void *data)
{ 
    /* all resources auto freed */
    return 0;
}

inventory_entry_t *
inventory_dir_new (inventory_file_t * parent, t_uchar const * const name, t_uchar const * const id)
{
    inventory_dir_t *result = talloc (NULL, inventory_dir_t);
    talloc_set_destructor (result, inventory_dir_finalise);
    inventory_file_init (&result->entry, parent, name, id);
    result->children = NULL;
    result->entry.vtable = &inventory_dir_vtable;
    return &result->entry;
}

int
inventory_dir_finalise (void *data)
{
    inventory_dir_t *dir = (inventory_dir_t *)data;
    /* children are auto freed, but the array isn't */
    ar_free_inventory_entry (&dir->children);
    inventory_file_finalise (&dir->entry);
    return 0;
}

/**
 * \brief get the child of an inventory item. for files this always returns NULL
 */
inventory_entry_t * 
inventory_entry_get_child (inventory_entry_t * entry, t_uchar const * const name)
{
  invariant (!!entry->vtable);
  if (!entry->vtable->get_child)
      return NULL;
  return entry->vtable->get_child (entry, name);
}

/**
 * \brief get the child of an inventory item. for files this always returns NULL
 * \return the added child - if this is not returned, the add failed
 */
inventory_entry_t *
inventory_entry_add_child (inventory_entry_t * entry, inventory_entry_t *child)
{
  invariant (!!entry->vtable);
  if (!entry->vtable->add_child)
      return NULL;
  return entry->vtable->add_child (entry, child);
}

inventory_file_t * 
inventory_dir_get_child (inventory_file_t * file, t_uchar const * const name)
{
  inventory_dir_t *dir = talloc_get_type (file, inventory_dir_t);
  int index;
  invariant (!!dir);
  debug (dbg_invent, 9, _("Looking for child '%s' under id '%s' (%d) elements\n"), name, file->id, ar_size_inventory_entry (dir->children));
  ar_for_each (dir->children, index)
    if (!str_cmp (name, dir->children[index]->name))
        return dir->children[index];
  return NULL;
}

inventory_file_t *
inventory_dir_add_child (inventory_file_t * file, inventory_file_t * child)
{
  inventory_dir_t *dir = talloc_get_type (file, inventory_dir_t);
  invariant (!!dir);
  debug (dbg_invent, 9, _("Adding child '%s' under id '%s' (%d) elements\n"), child->name, file->id, ar_size_inventory_entry (dir->children));
  if (inventory_dir_get_child (file, child->name))
      /* already present */
      return NULL;
  ar_push_inventory_entry (&dir->children, child);
  return child;
}

inventory_entry_t *
inventory_link_new (inventory_file_t * parent, t_uchar const * const name, t_uchar const * const id)
{
    inventory_link_t *result = talloc (NULL, inventory_link_t);
    talloc_set_destructor (result, inventory_link_finalise);
    inventory_file_init (&result->entry, parent, name, id);
    result->entry.vtable = &inventory_file_vtable;
    return &result->entry;
}

int
inventory_link_finalise (void *data)
{
    /* all resources auto freed */
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1