
/** @file  psArray.c
 *
 *  @brief Contains support for basic vector types
 *
 *  This file defines the basic type for a vector struct and functions useful
 *  in manupulating vectors.
 *
 *  @author Ross Harman, MHPCC
 *
 *  @version $Revision: 1.16 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2004-09-28 23:26:48 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */

/******************************************************************************/

/*  INCLUDE FILES                                                             */

/******************************************************************************/
#include<stdlib.h>                         // for qsort, etc.
#include<string.h>

#include "psMemory.h"
#include "psError.h"
#include "psArray.h"
#include "psLogMsg.h"

#include "psCollectionsErrors.h"

/*****************************************************************************/

/*  FUNCTION IMPLEMENTATION - LOCAL                                          */

/*****************************************************************************/
static void arrayFree(psArray* restrict psArr);

/*****************************************************************************/

/* FUNCTION IMPLEMENTATION - PUBLIC                                          */

/*****************************************************************************/
psArray* psArrayAlloc(unsigned int nalloc)
{
    psArray* psArr = NULL;

    // Create vector struct
    psArr = (psArray* ) psAlloc(sizeof(psArray));
    p_psMemSetDeallocator(psArr, (psFreeFcn) arrayFree);

    psArr->nalloc = nalloc;
    psArr->n = nalloc;

    // Create vector data array
    psArr->data = psAlloc(nalloc * sizeof(psPTR));

    return psArr;
}

psArray* psArrayRealloc(psArray* restrict in, unsigned int nalloc)
{
    if (in == NULL) {
        return psArrayAlloc(nalloc);
    } else if (in->nalloc != nalloc) {     // No need to realloc to same size
        if (nalloc < in->n) {
            for (int i = nalloc; i < in->n; i++) {      // For reduction in vector size
                psFree(in->data[i]);
            }
            in->n = nalloc;
        }
        // Realloc after decrementation to avoid accessing freed array elements
        in->data = psRealloc(in->data, nalloc * sizeof(psPTR));
        in->nalloc = nalloc;
    }

    return in;
}

static void arrayFree(psArray* restrict psArr)
{
    if (psArr == NULL) {
        return;
    }

    psArrayElementFree(psArr);

    psFree(psArr->data);
}

bool psArrayRemove(psArray* psArr,
                   psPTR data)
{
    bool success = false;

    if (psArr == NULL) {
        return success;
    }

    int n = psArr->n;
    psPTR* psArrData = psArr->data;
    for (int i = n-1; i<0; i--) {
        if (psArrData[i] == data) {
            memmove(psArrData[i],psArrData[i+1],(n-i-1)*sizeof(psPTR));
            n--;
            success = true;
        }
    }
    psArr->n = n; // reset the array size to indicate the removed item(s)

    return success;
}

void psArrayElementFree(psArray* restrict psArr)
{

    if (psArr == NULL) {
        return;
    }

    for (int i = 0; i < psArr->n; i++) {
        psFree(psArr->data[i]);
        psArr->data[i] = NULL;
    }
}

psArray* psArraySort(psArray* in, psComparePtrFcn compare)
{
    if (in == NULL) {
        return NULL;
    }

    qsort(in->data, in->n, sizeof(psPTR), (int (*)(const void *, const void *))compare);

    return in;
}
