1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*
4*******************************************************************************
5*
6*   Copyright (C) 2004-2010, International Business Machines
7*   Corporation and others.  All Rights Reserved.
8*
9*******************************************************************************
10*   file name:  ReplaceableContextIterator.java
11*   encoding:   US-ASCII
12*   tab size:   8 (not used)
13*   indentation:4
14*
15*   created on: 2005feb04
16*   created by: Markus W. Scherer
17*
18*   Implementation of UCaseProps.ContextIterator, iterates over a Replaceable.
19*   Java port of casetrn.cpp/utrans_rep_caseContextIterator().
20*/
21
22package com.ibm.icu.text;
23
24import com.ibm.icu.impl.UCaseProps;
25
26/**
27 * Implementation of UCaseProps.ContextIterator, iterates over a Replaceable.
28 * See casetrn.cpp/utrans_rep_caseContextIterator().
29 * See also UCharacter.StringContextIterator.
30 */
31class ReplaceableContextIterator implements UCaseProps.ContextIterator {
32    /**
33     * Constructor.
34     * @param rep Replaceable to iterate over.
35     */
36    ReplaceableContextIterator() {
37        this.rep=null;
38        limit=cpStart=cpLimit=index=contextStart=contextLimit=0;
39        dir=0;
40        reachedLimit=false;
41    }
42
43    /**
44     * Set the text for iteration.
45     * @param rep Iteration text.
46     */
47    public void setText(Replaceable rep) {
48        this.rep=rep;
49        limit=contextLimit=rep.length();
50        cpStart=cpLimit=index=contextStart=0;
51        dir=0;
52        reachedLimit=false;
53    }
54
55    /**
56     * Set the index where nextCaseMapCP() is to start iterating.
57     * @param index Iteration start index for nextCaseMapCP().
58     */
59    public void setIndex(int index) {
60        cpStart=cpLimit=index;
61        this.index=0;
62        dir=0;
63        reachedLimit=false;
64    }
65
66    /**
67     * Get the index of where the code point currently being case-mapped starts.
68     * @return The start index of the current code point.
69     */
70    public int getCaseMapCPStart() {
71        return cpStart;
72    }
73
74    /**
75     * Set the iteration limit for nextCaseMapCP() to an index within the string.
76     * If the limit parameter is negative or past the string, then the
77     * string length is restored as the iteration limit.
78     *
79     * @param lim The iteration limit.
80     */
81    public void setLimit(int lim) {
82        if(0<=lim && lim<=rep.length()) {
83            limit=lim;
84        } else {
85            limit=rep.length();
86        }
87        reachedLimit=false;
88    }
89
90    /**
91     * Set the start and limit indexes for context iteration with next().
92     * @param contextStart Start of context for next().
93     * @param contextLimit Limit of context for next().
94     */
95    public void setContextLimits(int contextStart, int contextLimit) {
96        if(contextStart<0) {
97            this.contextStart=0;
98        } else if(contextStart<=rep.length()) {
99            this.contextStart=contextStart;
100        } else {
101            this.contextStart=rep.length();
102        }
103        if(contextLimit<this.contextStart) {
104            this.contextLimit=this.contextStart;
105        } else if(contextLimit<=rep.length()) {
106            this.contextLimit=contextLimit;
107        } else {
108            this.contextLimit=rep.length();
109        }
110        reachedLimit=false;
111    }
112
113    /**
114     * Iterate forward through the string to fetch the next code point
115     * to be case-mapped, and set the context indexes for it.
116     *
117     * @return The next code point to be case-mapped, or <0 when the iteration is done.
118     */
119    public int nextCaseMapCP() {
120        int c;
121        if(cpLimit<limit) {
122            cpStart=cpLimit;
123            c=rep.char32At(cpLimit);
124            cpLimit+=UTF16.getCharCount(c);
125            return c;
126        } else {
127            return -1;
128        }
129    }
130
131    /**
132     * Replace the current code point by its case mapping,
133     * and update the indexes.
134     *
135     * @param text Replacement text.
136     * @return The delta for the change of the text length.
137     */
138    public int replace(String text) {
139        int delta=text.length()-(cpLimit-cpStart);
140        rep.replace(cpStart, cpLimit, text);
141        cpLimit+=delta;
142        limit+=delta;
143        contextLimit+=delta;
144        return delta;
145    }
146
147    /**
148     * Did forward context iteration with next() reach the iteration limit?
149     * @return Boolean value.
150     */
151    public boolean didReachLimit() {
152        return reachedLimit;
153    }
154
155    // implement UCaseProps.ContextIterator
156    public void reset(int direction) {
157        if(direction>0) {
158            /* reset for forward iteration */
159            this.dir=1;
160            index=cpLimit;
161        } else if(direction<0) {
162            /* reset for backward iteration */
163            this.dir=-1;
164            index=cpStart;
165        } else {
166            // not a valid direction
167            this.dir=0;
168            index=0;
169        }
170        reachedLimit=false;
171    }
172
173    public int next() {
174        int c;
175
176        if(dir>0) {
177            if(index<contextLimit) {
178                c=rep.char32At(index);
179                index+=UTF16.getCharCount(c);
180                return c;
181            } else {
182                // forward context iteration reached the limit
183                reachedLimit=true;
184            }
185        } else if(dir<0 && index>contextStart) {
186            c=rep.char32At(index-1);
187            index-=UTF16.getCharCount(c);
188            return c;
189        }
190        return -1;
191    }
192
193    // variables
194    protected Replaceable rep;
195    protected int index, limit, cpStart, cpLimit, contextStart, contextLimit;
196    protected int dir; // 0=initial state  >0=forward  <0=backward
197    protected boolean reachedLimit;
198}
199