package jacorb.collection;

/*
 *        JacORB collection service
 *
 *   Copyright (C) 1999-2000  LogicLand group, Viacheslav Tararin.
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library 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
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

import org.omg.CosCollection.*;
import org.omg.PortableServer.Servant;
import org.omg.CORBA.Any;
import org.omg.CORBA.AnyHolder;
import jacorb.collection.util.*;
import java.util.*;

class PositionalIteratorImpl 
    implements org.omg.CosCollection.IteratorOperations 
{
    private Servant srvnt = null;
    protected int pos = -1;
    protected boolean in_between = false;
    protected boolean read_only = true;
    protected CollectionImpl collection;
/* ========================================================================= */
    PositionalIteratorImpl( CollectionImpl collection ){
        this.collection = collection;
    };
/* ------------------------------------------------------------------------- */
    PositionalIteratorImpl( CollectionImpl collection, boolean read_only ){
        this.collection = collection;
        this.read_only = read_only;
    };
/* ========================================================================= */
    public boolean set_to_first_element() {
        synchronized( collection ){
            check_servant();
            if( collection.is_empty() ) {
                invalidate();
            } else {
                set_pos( 0 );
            };
        };
        return get_pos() == 0;
    };
/* ------------------------------------------------------------------------- */
    public boolean set_to_next_element() throws IteratorInvalid {
        return set_to_next_nth_element( 1 );
    };
/* ------------------------------------------------------------------------- */
    public boolean set_to_next_nth_element(int n) throws IteratorInvalid {
        synchronized( collection ) {
            check_invalid();
            int new_pos = get_pos()+n;
            if( is_in_between() ){
                new_pos = get_pos()+n-1;
            }
            if( collection.number_of_elements() > new_pos && new_pos >= 0 ){
                set_pos( new_pos );
            } else {
                invalidate();
            }
            in_between = false;
            return exist_next();
        } 
    };
/* ------------------------------------------------------------------------- */
    public boolean retrieve_element(AnyHolder element) throws IteratorInvalid,IteratorInBetween{
        synchronized( collection ){
            check_iterator();
            try {
                element.value = collection.element_retrieve( get_pos() );
                return true;
            } catch ( PositionInvalid e ){
                set_pos( -1 );
                throw new IteratorInvalid( IteratorInvalidReason.is_invalid );
            }
        }
    };
/* ------------------------------------------------------------------------- */
    public boolean retrieve_element_set_to_next(AnyHolder element, org.omg.CORBA.BooleanHolder more) throws IteratorInvalid,IteratorInBetween{
        synchronized( collection ){
            boolean rc = retrieve_element( element );
            set_to_next_element();
            more.value = exist_next();
            return rc;
        }
    };
/* ------------------------------------------------------------------------- */
    public boolean retrieve_next_n_elements(int n, AnySequenceHolder result, org.omg.CORBA.BooleanHolder more) throws IteratorInvalid,IteratorInBetween{
        Vector v = new Vector( n );
        int i = 0;
        synchronized( collection ){
             check_iterator();
             boolean b = true;
             AnyHolder a = new AnyHolder();
             more.value = true;
             for ( i=0; (i<n || n==0) && get_pos() != -1; i++ ){
                 try {
                     retrieve_element_set_to_next( a, more );
                     v.addElement(a.value);
                 } catch ( IteratorInvalid e ){
                     more.value = false;
                     break;
                 }
             }
        }
        Any [] anies = new Any[v.size()];
        v.copyInto( (java.lang.Object [])anies );
        result.value = anies;
        return i>0;
    };
/* ------------------------------------------------------------------------- */
    public boolean not_equal_retrieve_element_set_to_next(org.omg.CosCollection.Iterator test, AnyHolder element) throws IteratorInvalid,IteratorInBetween{
        synchronized( collection ){
            check_iterator();
            if( is_equal( test ) ){
                retrieve_element( element );
                return false;
            } else {
                retrieve_element( element );
                set_to_next_element();
                return true;
            }
        };
    };
/* ------------------------------------------------------------------------- */
    public void remove_element() throws IteratorInvalid,IteratorInBetween{
        synchronized( collection ){
            check_iterator();
            check_read_only();
            try {
                collection.element_remove( get_pos() );
            } catch ( PositionInvalid e ){
                invalidate();
                throw new IteratorInvalid( IteratorInvalidReason.is_invalid );
            } catch ( EmptyCollection e ){
                invalidate();
                throw new IteratorInvalid( IteratorInvalidReason.is_invalid );
           };
        };
    };
/* ------------------------------------------------------------------------- */
    public boolean remove_element_set_to_next() throws IteratorInvalid,IteratorInBetween{
        synchronized( collection ) {
            remove_element();
            return set_to_next_element();
        }
    };
/* ------------------------------------------------------------------------- */
    public boolean remove_next_n_elements(int n, org.omg.CORBA.IntHolder actual_number) throws IteratorInvalid,IteratorInBetween{
        synchronized( collection ){
            int count = 0;
            for( int i=0; ( i<n || n==0 ) && get_pos() != -1; i++, count++ ){
                remove_element_set_to_next();
            }
            actual_number.value = count;
            return exist_next();
        };
    };
/* ------------------------------------------------------------------------- */
    public boolean not_equal_remove_element_set_to_next(org.omg.CosCollection.Iterator test) 
	throws IteratorInvalid,IteratorInBetween{
        synchronized( collection ){
            check_iterator();
            if( is_equal( test ) ){
                remove_element();
                return false;
            } else {
                remove_element_set_to_next();
                return true;
            }
        }
    };
/* ------------------------------------------------------------------------- */
    public void replace_element(Any element) throws IteratorInvalid,IteratorInBetween,ElementInvalid{
        synchronized( collection ){
            check_iterator();
            check_read_only();
            try {
                collection.element_replace( get_pos(), element );
            } catch ( PositionInvalid e ){
                invalidate();
                throw new IteratorInvalid( IteratorInvalidReason.is_invalid );
            }
        }
    };
/* ------------------------------------------------------------------------- */
    public boolean replace_element_set_to_next(Any element) throws IteratorInvalid,IteratorInBetween,ElementInvalid{
        synchronized( collection ){
            replace_element( element );
            return set_to_next_element();
        }
    };
/* ------------------------------------------------------------------------- */
    public boolean replace_next_n_elements(Any[] elements, org.omg.CORBA.IntHolder actual_number) throws IteratorInvalid,IteratorInBetween,ElementInvalid{
        synchronized( collection ){
            actual_number.value = 0;
            for( int i=0; i<elements.length && is_valid() ; i++, actual_number.value++){
                replace_element_set_to_next( elements[i] );
            }
            return exist_next();
        } 
    };
/* ------------------------------------------------------------------------- */
    public boolean not_equal_replace_element_set_to_next(org.omg.CosCollection.Iterator test, Any element) throws IteratorInvalid,IteratorInBetween,ElementInvalid{
        synchronized( collection ){
            check_iterator();
            if( is_equal( test ) ){
                replace_element( element );
                return false;
            } else {
                replace_element_set_to_next( element );
                return true;
            }
        };
    };
/* ------------------------------------------------------------------------- */
    public boolean add_element_set_iterator(Any element) throws ElementInvalid{
        synchronized( collection ){
            pos = collection.element_add( element );
            set_pos( pos );
            in_between = false;
            return true;
        } 
    };
/* ------------------------------------------------------------------------- */
    public boolean add_n_elements_set_iterator(Any[] elements, org.omg.CORBA.IntHolder actual_number) throws ElementInvalid{
        synchronized( collection ){
            actual_number.value = 0;
            int pos[] = new int[ elements.length ];
            for( int i=0; i<elements.length; i++ ){
                collection.check_element( elements[i] );
            }
            for( int i=0; i<elements.length; i++, actual_number.value++ ){
                add_element_set_iterator( elements[i] );
            }
            return true;
        } 
    };
/* ------------------------------------------------------------------------- */
    public synchronized void invalidate(){
        pos = -1;
    };
/* ------------------------------------------------------------------------- */
    public synchronized boolean is_valid(){
        return pos != -1;
    };
/* ------------------------------------------------------------------------- */
    public synchronized boolean is_in_between(){
        return in_between;
    };
/* ------------------------------------------------------------------------- */
    public synchronized boolean is_for(org.omg.CosCollection.Collection collector){
        return collection.is_this_you( collector );
    };
/* ------------------------------------------------------------------------- */
    public synchronized boolean is_const(){
        return read_only;
    };
/* ------------------------------------------------------------------------- */
    public boolean is_equal(org.omg.CosCollection.Iterator test) throws IteratorInvalid{
        synchronized( collection ){
            PositionalIteratorImpl iter = collection.check_iterator( test );
            if( !is_valid() ){
                throw new IteratorInvalid( IteratorInvalidReason.is_invalid );
            }
            return get_pos() == iter.get_pos();
        };
    };
/* ------------------------------------------------------------------------- */
    public org.omg.CosCollection.Iterator _clone(){
        synchronized( collection ) {
            org.omg.CosCollection.Iterator iter = collection.create_iterator( read_only );
            try {
                PositionalIteratorImpl i = collection.check_iterator( iter );
                i.set_pos( get_pos() );
                return iter;
            } catch ( IteratorInvalid e ){
                e.printStackTrace( System.out );
                throw new org.omg.CORBA.INTERNAL();
            };
        };
    };
/* ------------------------------------------------------------------------- */
    public void assign(org.omg.CosCollection.Iterator from_where) throws IteratorInvalid{
        synchronized( collection ) {
            PositionalIteratorImpl i = collection.check_iterator( from_where );
            i.set_pos( get_pos() );
            i.set_in_between( is_in_between() );
        };
    };
/* ------------------------------------------------------------------------- */
    public synchronized void destroy(){
        synchronized( collection ) { 
            check_servant();
            collection.destroy_me( this );
        }
    };
/* ========================================================================= */
    public synchronized int get_pos(){
        check_servant();
        return pos;
    };
/* ------------------------------------------------------------------------- */
    public synchronized void set_pos( int pos ){
        check_servant();
        this.pos = pos;
    };
/* ------------------------------------------------------------------------- */
    public synchronized void set_in_between( boolean in_between ){
        check_servant();
        this.in_between = in_between;
    };
/* ------------------------------------------------------------------------- */
    public synchronized void set_servant( Servant srvnt ){
        if( srvnt != null ){
            System.out.println("Error: Servant setted before!");
            throw new org.omg.CORBA.INTERNAL();
        }
    };
/* ------------------------------------------------------------------------- */
    public synchronized Servant get_servant(){
        if( srvnt != null ){
            System.out.println("Error: Servant must be setted before!");
            throw new org.omg.CORBA.INTERNAL();
        }
        return srvnt;
    };
/* ========================================================================= */
    protected void check_servant() {
        if( srvnt == null ){
            System.out.println("Error: Servant must be setted before!");
            throw new org.omg.CORBA.INTERNAL();
        }
    }
/* -------------------------------------------------------------------------- */
    protected void check_invalid() throws IteratorInvalid {
        check_servant();
        if( pos == -1 ){
            throw new IteratorInvalid( IteratorInvalidReason.is_invalid );
        }
    }
/* -------------------------------------------------------------------------- */
    protected void check_in_between() throws IteratorInBetween {
        if( in_between ){
            throw new IteratorInBetween();
        }
    }
/* -------------------------------------------------------------------------- */
    protected void check_iterator() throws IteratorInBetween, IteratorInvalid {
        check_invalid();
        check_in_between();
    };
/* -------------------------------------------------------------------------- */
    protected void check_read_only() throws IteratorInvalid {
        if( read_only ){
            throw new IteratorInvalid( IteratorInvalidReason.is_const );
        }
    }
/* -------------------------------------------------------------------------- */
    protected synchronized boolean exist_next(){
        return is_valid() && collection.number_of_elements()-1 > get_pos();
    };
};
