/*
*******************************************************************************
* Copyright (C) 2010-2014, International Business Machines
* Corporation and others.  All Rights Reserved.
*******************************************************************************
* UTF16CollationIterator.java, ported from utf16collationiterator.h/.cpp
*
* C++ version created on: 2010oct27
* created by: Markus W. Scherer
*/

package com.ibm.icu.impl.coll;

/**
 * UTF-16 collation element and character iterator.
 * Handles normalized UTF-16 text, with length or NUL-terminated.
 * Unnormalized text is handled by a subclass.
 */
public class UTF16CollationIterator extends CollationIterator {
    /**
     * Partial constructor, see {@link CollationIterator#CollationIterator(CollationData)}.
     */
    public UTF16CollationIterator(CollationData d) {
        super(d);
    }

    public UTF16CollationIterator(CollationData d, boolean numeric, CharSequence s, int p) {
        super(d, numeric);
        seq = s;
        start = 0;
        pos = p;
        limit = s.length();
    }

    @Override
    public boolean equals(Object other) {
        if(!super.equals(other)) { return false; }
        UTF16CollationIterator o = (UTF16CollationIterator)other;
        // Compare the iterator state but not the text: Assume that the caller does that.
        return (pos - start) == (o.pos - o.start);
    }

    @Override
    public int hashCode() {
        assert false : "hashCode not designed";
        return 42; // any arbitrary constant will do
    }

    @Override
    public void resetToOffset(int newOffset) {
        reset();
        pos = start + newOffset;
    }

    @Override
    public int getOffset() {
        return pos - start;
    }

    public void setText(boolean numeric, CharSequence s, int p) {
        reset(numeric);
        seq = s;
        start = 0;
        pos = p;
        limit = s.length();
    }

    @Override
    public int nextCodePoint() {
        if(pos == limit) {
            return Collation.SENTINEL_CP;
        }
        char c = seq.charAt(pos++);
        char trail;
        if(Character.isHighSurrogate(c) && pos != limit &&
                Character.isLowSurrogate(trail = seq.charAt(pos))) {
            ++pos;
            return Character.toCodePoint(c, trail);
        } else {
            return c;
        }
    }

    @Override
    public int previousCodePoint() {
        if(pos == start) {
            return Collation.SENTINEL_CP;
        }
        char c = seq.charAt(--pos);
        char lead;
        if(Character.isLowSurrogate(c) && pos != start &&
                Character.isHighSurrogate(lead = seq.charAt(pos - 1))) {
            --pos;
            return Character.toCodePoint(lead, c);
        } else {
            return c;
        }
    }

    @Override
    protected long handleNextCE32() {
        if(pos == limit) {
            return NO_CP_AND_CE32;
        }
        char c = seq.charAt(pos++);
        return makeCodePointAndCE32Pair(c, trie.getFromU16SingleLead(c));
    }

    @Override
    protected char handleGetTrailSurrogate() {
        if(pos == limit) { return 0; }
        char trail;
        if(Character.isLowSurrogate(trail = seq.charAt(pos))) { ++pos; }
        return trail;
    }

    /* boolean foundNULTerminator(); */

    @Override
    protected void forwardNumCodePoints(int num) {
        while(num > 0 && pos != limit) {
            char c = seq.charAt(pos++);
            --num;
            if(Character.isHighSurrogate(c) && pos != limit &&
                    Character.isLowSurrogate(seq.charAt(pos))) {
                ++pos;
            }
        }
    }

    @Override
    protected void backwardNumCodePoints(int num) {
        while(num > 0 && pos != start) {
            char c = seq.charAt(--pos);
            --num;
            if(Character.isLowSurrogate(c) && pos != start &&
                    Character.isHighSurrogate(seq.charAt(pos-1))) {
                --pos;
            }
        }
    }

    protected CharSequence seq;
    protected int start;
    protected int pos;
    protected int limit;
}
