/*===========================================================================
  Copyright (C) 2001 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
    Internet e-mail: midas@eso.org
    Postal address: European Southern Observatory
            Data Management Division 
            Karl-Schwarzschild-Strasse 2
            D 85748 Garching bei Muenchen 
            GERMANY
===========================================================================*/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <uves_deque.h>

#include <cpl.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <uves_msg.h>
struct _uves_deque_
{
    void **members;
    unsigned long front;
    unsigned long size;
    unsigned long back;

};


uves_deque *
uves_deque_new(void)
{

    uves_deque *d = cpl_calloc(1, sizeof(*d));
 

    if (d == NULL)
        {
            return NULL;
        }
 

    d->members = NULL;
 

    d->front = 0;
    d->size = 0;
    d->back = 0;


    return d;
}

void
uves_deque_push_back(uves_deque *d, cxptr what)
{
    assert( d != NULL );

    if (d->back == 0)
        {
//      fprintf(stderr, "old : %ld - %ld - %ld\n", d->front, d->size, d->back);
            void **new_members;
            unsigned long i;
            d->back = d->size + 1;
            new_members = cpl_calloc(d->front + d->size + d->back, sizeof(void *));
  
            for (i = 0; i < d->size; i++)
                {
                    new_members[d->front + i] = d->members[d->front + i];
                }

            cpl_free(d->members);
            d->members = new_members;

//      fprintf(stderr, "new : %ld - %ld - %ld\n", d->front, d->size, d->back);
        }

    d->members[d->front + d->size] = (cxptr)what;
    d->size++;
    d->back--;

    return;
}

void
uves_deque_push_front(uves_deque *d, cxptr what)
{
    assert( d != NULL );

    if (d->front == 0)
        {
//      fprintf(stderr, "old : %ld - %ld - %ld\n", d->front, d->size, d->back);
            void **new_members;
            unsigned long i;

            d->front = d->size + 1;
            new_members = cpl_calloc(d->front + d->size + d->back, sizeof(void *));

            for (i = 0; i < d->size; i++)
                {
                    new_members[d->front + i] = d->members[0 + i];
                }

            cpl_free(d->members);
            d->members = new_members;

//      fprintf(stderr, "new : %ld - %ld - %ld\n", d->front, d->size, d->back);
        }

    d->front--;
    d->size++;
    d->members[d->front] = what;

    return;
}

cxptr
uves_deque_get(const uves_deque *d, uves_deque_const_iterator indx)
{
    assert( d != NULL );
    assert( indx < d->size );

    return d->members[d->front + indx];  
}

uves_deque_iterator
uves_deque_erase(uves_deque *d, uves_deque_iterator indx, cx_free_func deallocate)
{
    unsigned long i;

    //printf("indx = %d size = %d\n", indx, d->size);
    assert( d != NULL );
    assert( indx < d->size );

    deallocate(d->members[d->front + indx]);

    for (i = indx; i < d->size - 1; i++)
        {
            d->members[d->front + i] = d->members[d->front + i + 1];
        }

    d->size--;
    d->back++;

    return indx;
}

void
uves_deque_insert(uves_deque *d, uves_deque_iterator indx, cxptr what)
{
    //printf("indx = %d size = %d\n", indx, d->size);
    assert( d != NULL );
    assert( indx <= d->size );

    if ( indx == d->size )
        {
            uves_deque_push_back(d, what);
        }
    else
        {
            unsigned long i;

            assert( indx < d->size );
            assert( d->size > 1 );
      
            uves_deque_push_back(d, d->members[d->front + d->size - 1]);
      
            for (i = d->size-1; i > indx; i--)
                {
                    d->members[d->front + i] = d->members[d->front + i - 1];
                }
      
            d->members[d->front + indx] = what;
        }

    return;
}

cxsize
uves_deque_size(const uves_deque *d)
{
    assert( d != NULL );
  
    return d->size;
}


void
uves_deque_destroy(uves_deque *d, cx_free_func deallocate)
{
    if (d != NULL)
        {
            if (deallocate != NULL)
                {
                    unsigned long i;
          
                    for (i = 0; i < d->size; i++)
                        {
                            deallocate(d->members[d->front + i]);
                        }
                }
            cpl_free(d->members);
            cpl_free(d);
        }
}

cxbool 
uves_deque_empty(const uves_deque *d)
{
    assert(d != NULL);

    return (d->size == 0);
}

uves_deque_iterator 
uves_deque_begin(const uves_deque *d)
{
    assert(d != NULL);
    return 0;
}

uves_deque_iterator
uves_deque_end(const uves_deque *d)
{
    assert(d != NULL);
    return d->size;
}

uves_deque_iterator
uves_deque_next(const uves_deque *d, uves_deque_const_iterator i)
{
    assert(d != NULL);

    return i+1;
}

