/* $Id$ 
 * 
 * Licensed to the Apache Software Foundation (ASF) under one or more 
 * contributor license agreements. See the NOTICE file distributed with  
 * this work for additional information regarding copyright ownership. 
 * The ASF licenses this file to you under the Apache License, Version  
 * 2.0 (the "License"); you may not use this file except in compliance  
 * with the License. You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 

/**
 * etch_collection.c -- collection support
 */

#include "etch_collection.h" 
#include "etch_global.h"
#include "etchobj.h"

int default_iterable_first   (etch_iterator*);
int default_iterable_next    (etch_iterator*);
int default_iterable_has_next(etch_iterator*);


/**
 * new_iterable()
 * constructor for an i_iterable interface
 */
i_iterable* new_iterable(i_iterable* thisp, i_iterable* parent, iterable_first func_first, 
    iterable_next func_next, iterable_has_next func_hasnext)
{
    i_iterable* vtab = NULL;

    if  (thisp) /* initializing existing object? */
         vtab = thisp;
    else vtab = new_vtable(parent, sizeof(i_iterable), CLASSID_ITERABLE_VTAB);

    if (NULL == vtab) return NULL;

    vtab->first    = func_first?   func_first:   default_iterable_first;
    vtab->next     = func_next?    func_next:    default_iterable_next;
    vtab->has_next = func_hasnext? func_hasnext: default_iterable_has_next;

    return vtab;
}


/**
 * destroy_iterator()
 * iterator destructor
 */
int destroy_iterator(etch_iterator* iterator)
{   
    if (iterator->refcount > 0)       /* if object is refcounted */                                     
        if (--iterator->refcount > 0) /* destroy only if last ref */
            return -1;    

    /* iterator owns itself, and possibly the collection. 
     * its vtable is owned by the collection. */
    if (!is_etchobj_static_shell(iterator))
    {
        if (iterator->is_own_collection)
           ((objmask*)iterator->collection)->destroy(iterator->collection);
            
        etch_free(iterator); 
    }

    return 0;
}


/**
 * clone_iterator()
 * iterator copy constructor
 */
etch_iterator* clone_iterator(etch_iterator* iterator)
{   
    etch_iterator* newobj = etch_malloc(sizeof(struct etch_iterator), ETCHTYPEB_ITERATOR); 
    memcpy(newobj, iterator, sizeof(struct etch_iterator));
    return newobj;
}


/**
 * new_iterator()
 * constructor for an etch_iterator object.
 */
etch_iterator* new_iterator(void* collection, i_iterable* iterable)
{
    etch_iterator* iterator = etch_malloc(sizeof(etch_iterator), ETCHTYPEB_ITERATOR);

    set_iterator(iterator, collection, iterable);

    return iterator;
}


/**
 * set_iterator()
 * constructor for an existing etch_iterator object.
 */
int set_iterator(etch_iterator* iterator, void* collection, i_iterable* iterable)
{
    memset(iterator, 0, sizeof(etch_iterator));

    iterator->obj_type = ETCHTYPEB_ITERATOR;
    iterator->class_id = CLASSID_ITERATOR; 

    iterator->vtab = iterable;
    iterator->collection = collection;

    iterator->destroy  = destroy_iterator;
    iterator->clone    = clone_iterator;

    iterator->first    = iterable->first;
    iterator->next     = iterable->next;
    iterator->has_next = iterable->has_next;

    iterator->first(iterator); /* establish initial position */
    return 0;
}


/**
 * new_empty_iterator()
 * constructor for an empty etch_iterator object, i.e. has_next() is false
 */
etch_iterator* new_empty_iterator()
{
    etch_iterator* iterator = etch_malloc(sizeof(etch_iterator), ETCHTYPEB_ITERATOR);

    iterator->obj_type = ETCHTYPEB_ITERATOR;
    iterator->class_id = CLASSID_ITERATOR; 
    iterator->destroy  = destroy_iterator;

    iterator->first    = default_iterable_first;
    iterator->next     = default_iterable_next;
    iterator->has_next = default_iterable_has_next;

    return iterator;
}


/**
 * default_iterable_first()
 * i_iterable first() default virtual method 
 */
int default_iterable_first(etch_iterator* i) 
{
    return -1;
}


/**
 * default_iterable_next()
 * i_iterable next() default virtual method 
 */
int default_iterable_next(etch_iterator* i) 
{
    return -1;
}


/**
 * default_iterable_has_next()
 * i_iterable has_next() default virtual method 
 */
int default_iterable_has_next (etch_iterator* i)
{
    return FALSE;
}


/**
 * etch_comparator_noteq(), etch_comparator_equal
 * comparators to use when a result not dependent on parameters is desired,
 * such as when using an add_from method to add to a collection when the
 * target collection is empty and thus no contains() comparison is needed. 
 */
int etch_comparator_noteq(void* a, void* b) { return -1;}
int etch_comparator_equal(void* a, void* b) { return 0; }