/*
 * This file is part of the Poliqarp suite.
 * 
 * Copyright (C) 2004-2009 by Instytut Podstaw Informatyki Polskiej
 * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 * Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file gpl.txt included in the packaging
 * of this file.  (See http://www.gnu.org/licenses/translations.html for
 * unofficial translations.)
 * 
 * A commercial license is available from IPI PAN (contact
 * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more
 * information).  Licensees holding a valid commercial license from IPI
 * PAN may use this file in accordance with that license.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

#include <bp/common.h>
#include "heap.h"

bool heap_empty(const struct heap *heap)
{
   return (heap->size == 0);
}

static inline int heap_compare(struct heap *heap, size_t i, size_t j)
{
   return occurrences_compare(runs_get_current(heap->runs, i),
                              runs_get_current(heap->runs, j));
}

static void heap_down(struct heap *heap, size_t i)
{
   int v = heap->data[i];
   while (i <= heap->size / 2) {
      size_t j = 2 * i;
      if (j < heap->size &&
          heap_compare(heap, heap->data[j], heap->data[j + 1]) > 0)
      {
         j++;
      }
      if (heap_compare(heap, v, heap->data[j]) <= 0)
         break;
      heap->data[i] = heap->data[j];
      i = j;
   }
   heap->data[i] = v;
}

void heap_create(struct heap *heap, struct runs *runs)
{
   size_t i;
   heap->runs = runs;
   heap->size = runs->size;
   heap->data = bp_malloc((heap->size + 1) * sizeof *heap->data);
   for (i = 0; i < heap->size; i++)
      heap->data[i + 1] = i;
   for (i = heap->size / 2; i; i--)
      heap_down(heap, i);
}

void heap_destroy(struct heap *heap)
{
   free(heap->data);
}

int heap_extract_min(struct heap *heap)
{
   int res = heap->data[1];
   heap->data[1] = heap->data[heap->size--];
   heap_down(heap, 1);
   return res;
}

void heap_insert(struct heap *heap, int i)
{
   int k, l;
   heap->data[++heap->size] = i;
   k = heap->size;
   l = k / 2;
   while (l && heap_compare(heap, i, heap->data[l]) < 0) {
      heap->data[k] = heap->data[l];
      k = l;
      l /= 2;
   }
   heap->data[k] = i;
}

