17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 1996-2014, International Business Machines Corporation and
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved.
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.text;
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.CharacterIterator;
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.lang.UCharacter;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ICUCloneNotSupportedException;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale;
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Inserts the specified characters at word breaks. To restrict it to particular characters, use a filter.
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * TODO: this is an internal class, and only temporary. Remove it once we have \b notation in Transliterator.
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertfinal class BreakTransliterator extends Transliterator {
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private BreakIterator bi;
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private String insertion;
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int[] boundaries = new int[50];
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int boundaryCount = 0;
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public BreakTransliterator(String ID, UnicodeFilter filter, BreakIterator bi, String insertion) {
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(ID, filter);
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.bi = bi;
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.insertion = insertion;
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public BreakTransliterator(String ID, UnicodeFilter filter) {
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(ID, filter, null, " ");
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:OFF
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // The following method is not called by anything and can't be reached
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String getInsertion() {
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return insertion;
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:ON
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:OFF
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // The following method is not called by anything and can't be reached
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setInsertion(String insertion) {
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.insertion = insertion;
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:ON
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public BreakIterator getBreakIterator() {
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Defer initialization of BreakIterator because it is slow,
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // typically over 2000 ms.
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (bi == null) bi = BreakIterator.getWordInstance(new ULocale("th_TH"));
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return bi;
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:OFF
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // The following method is not called by anything and can't be reached
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setBreakIterator(BreakIterator bi) {
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.bi = bi;
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:ON
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int LETTER_OR_MARK_MASK =
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          (1<<Character.UPPERCASE_LETTER)
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        | (1<<Character.LOWERCASE_LETTER)
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        | (1<<Character.TITLECASE_LETTER)
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        | (1<<Character.MODIFIER_LETTER)
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        | (1<<Character.OTHER_LETTER)
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        | (1<<Character.COMBINING_SPACING_MARK)
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        | (1<<Character.NON_SPACING_MARK)
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        | (1<<Character.ENCLOSING_MARK)
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ;
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected synchronized void handleTransliterate(Replaceable text, Position pos, boolean incremental) {
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boundaryCount = 0;
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int boundary = 0;
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        getBreakIterator(); // Lazy-create it if necessary
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        bi.setText(new ReplaceableCharacterIterator(text, pos.start, pos.limit, pos.start));
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // TODO: fix clumsy workaround used below.
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        char[] tempBuffer = new char[text.length()];
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        text.getChars(0, text.length(), tempBuffer, 0);
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        bi.setText(new StringCharacterIterator(new String(tempBuffer), pos.start, pos.limit, pos.start));
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // end debugging
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // To make things much easier, we will stack the boundaries, and then insert at the end.
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // generally, we won't need too many, since we will be filtered.
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for(boundary = bi.first(); boundary != BreakIterator.DONE && boundary < pos.limit; boundary = bi.next()) {
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (boundary == 0) continue;
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // HACK: Check to see that preceeding item was a letter
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int cp = UTF16.charAt(text, boundary-1);
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int type = UCharacter.getType(cp);
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            //System.out.println(Integer.toString(cp,16) + " (before): " + type);
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (((1<<type) & LETTER_OR_MARK_MASK) == 0) continue;
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            cp = UTF16.charAt(text, boundary);
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            type = UCharacter.getType(cp);
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            //System.out.println(Integer.toString(cp,16) + " (after): " + type);
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (((1<<type) & LETTER_OR_MARK_MASK) == 0) continue;
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (boundaryCount >= boundaries.length) {       // realloc if necessary
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                int[] temp = new int[boundaries.length * 2];
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                System.arraycopy(boundaries, 0, temp, 0, boundaries.length);
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                boundaries = temp;
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            boundaries[boundaryCount++] = boundary;
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            //System.out.println(boundary);
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int delta = 0;
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int lastBoundary = 0;
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (boundaryCount != 0) { // if we found something, adjust
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            delta = boundaryCount * insertion.length();
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            lastBoundary = boundaries[boundaryCount-1];
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // we do this from the end backwards, so that we don't have to keep updating.
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            while (boundaryCount > 0) {
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                boundary = boundaries[--boundaryCount];
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                text.replace(boundary, boundary, insertion);
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Now fix up the return values
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.contextLimit += delta;
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.limit += delta;
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.start = incremental ? lastBoundary + delta : pos.limit;
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Registers standard variants with the system.  Called by
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Transliterator during initialization.
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static void register() {
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // false means that it is invisible
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Transliterator trans = new BreakTransliterator("Any-BreakInternal", null);
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Transliterator.registerInstance(trans, false);
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Transliterator.registerFactory("Any-Break", new Transliterator.Factory() {
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            public Transliterator getInstance(String ID) {
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return new BreakTransliterator("Any-Break", null);
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        });
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Hack, just to get a real character iterator.
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final class ReplaceableCharacterIterator implements CharacterIterator
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private Replaceable text;
1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private int begin;
1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private int end;
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // invariant: begin <= pos <= end
1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        private int pos;
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Constructs an iterator with an initial index of 0.
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*public ReplaceableCharacterIterator(Replaceable text)
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this(text, 0);
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }*/
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Constructs an iterator with the specified initial index.
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        *
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param  text   The String to be iterated over
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param  pos    Initial iterator position
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*public ReplaceableCharacterIterator(Replaceable text, int pos)
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this(text, 0, text.length(), pos);
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }*/
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Constructs an iterator over the given range of the given string, with the
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * index set at the specified position.
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        *
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param  text   The String to be iterated over
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param  begin  Index of the first character
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param  end    Index of the character following the last character
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param  pos    Initial iterator position
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public ReplaceableCharacterIterator(Replaceable text, int begin, int end, int pos) {
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (text == null) {
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new NullPointerException();
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.text = text;
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (begin < 0 || begin > end || end > text.length()) {
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Invalid substring range");
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (pos < begin || pos > end) {
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Invalid position");
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.begin = begin;
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.end = end;
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.pos = pos;
2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Reset this iterator to point to a new string.  This package-visible
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * method is used by other java.text classes that want to avoid allocating
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * new ReplaceableCharacterIterator objects every time their setText method
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * is called.
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        *
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param  text   The String to be iterated over
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public void setText(Replaceable text) {
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (text == null) {
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new NullPointerException();
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.text = text;
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.begin = 0;
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.end = text.length();
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.pos = 0;
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.first() for String.
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#first
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public char first()
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            pos = begin;
2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return current();
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.last() for String.
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#last
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public char last()
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (end != begin) {
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos = end - 1;
2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos = end;
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return current();
2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.setIndex() for String.
2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#setIndex
2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public char setIndex(int p)
2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (p < begin || p > end) {
2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Invalid index");
2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            pos = p;
2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return current();
2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.current() for String.
2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#current
2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public char current()
2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (pos >= begin && pos < end) {
2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return text.charAt(pos);
2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            else {
2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return DONE;
2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.next() for String.
2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#next
2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public char next()
2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (pos < end - 1) {
2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos++;
2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return text.charAt(pos);
2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            else {
2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos = end;
2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return DONE;
2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.previous() for String.
2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#previous
2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public char previous()
2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (pos > begin) {
3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos--;
3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return text.charAt(pos);
3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            else {
3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return DONE;
3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.getBeginIndex() for String.
3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#getBeginIndex
3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public int getBeginIndex()
3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return begin;
3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.getEndIndex() for String.
3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#getEndIndex
3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public int getEndIndex()
3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return end;
3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Implements CharacterIterator.getIndex() for String.
3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @see CharacterIterator#getIndex
3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public int getIndex()
3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return pos;
3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Compares the equality of two ReplaceableCharacterIterator objects.
3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @param obj the ReplaceableCharacterIterator object to be compared with.
3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @return true if the given obj is the same as this
3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * ReplaceableCharacterIterator object; false otherwise.
3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public boolean equals(Object obj)
3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (this == obj) {
3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return true;
3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (!(obj instanceof ReplaceableCharacterIterator)) {
3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return false;
3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ReplaceableCharacterIterator that = (ReplaceableCharacterIterator) obj;
3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (hashCode() != that.hashCode()) {
3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return false;
3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (!text.equals(that.text)) {
3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return false;
3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (pos != that.pos || begin != that.begin || end != that.end) {
3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return false;
3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return true;
3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Computes a hashcode for this iterator.
3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @return A hash code
3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public int hashCode()
3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return text.hashCode() ^ pos ^ begin ^ end;
3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * Creates a copy of this iterator.
3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        * @return A copy of this
3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public Object clone()
3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            try {
3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ReplaceableCharacterIterator other
3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                = (ReplaceableCharacterIterator) super.clone();
3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return other;
3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            catch (CloneNotSupportedException e) {
3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new ICUCloneNotSupportedException();
3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /* (non-Javadoc)
3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see com.ibm.icu.text.Transliterator#addSourceTargetSet(com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet)
3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet) {
3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        UnicodeSet myFilter = getFilterAsUnicodeSet(inputFilter);
3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Doesn't actually modify the source characters, so leave them alone.
3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // add the characters inserted
3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (myFilter.size() != 0) {
4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            targetSet.addAll(insertion);
4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
405