1/*
2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.im.app;
19
20import com.android.im.plugin.BrandingResourceIDs;
21
22import android.graphics.drawable.Drawable;
23import android.text.Spannable;
24import android.text.SpannableString;
25import android.text.style.ImageSpan;
26import android.text.util.Linkify;
27
28public class Markup {
29    private BrandingResources mRes;
30    private IntTrie mSmileys;
31
32    public Markup(BrandingResources res) {
33        mRes = res;
34        mSmileys = new IntTrie(
35                res.getStringArray(BrandingResourceIDs.STRING_ARRAY_SMILEY_TEXTS), res.getSmileyIcons());
36    }
37
38    public final CharSequence markup(CharSequence text) {
39        SpannableString result;
40
41        if (text instanceof SpannableString) {
42            result = (SpannableString) text;
43        } else {
44            result = new SpannableString(text);
45        }
46
47        Linkify.addLinks(result, Linkify.ALL);
48        applyEmoticons(result);
49
50        return result;
51    }
52
53    public final CharSequence applyEmoticons(CharSequence text) {
54        int offset = 0;
55        final int len = text.length();
56        SpannableString result = null;
57
58        while (offset < len) {
59            int index = offset;
60            IntTrie.Node n = mSmileys.getNode(text.charAt(index++));
61            int candidate = 0;
62            int lastMatchEnd = -1;
63
64            //  Search the trie until we stop matching
65            while (n != null) {
66                //  Record the value and position of the longest match
67                if (n.mValue != 0) {
68                    candidate = n.mValue;
69                    lastMatchEnd = index;
70                }
71
72                //  Let's not run off the end of the input
73                if (index >= len) {
74                    break;
75                }
76
77                n = n.getNode(text.charAt(index++));
78            }
79
80            //  If we matched a smiley, apply its image over the text
81            if (candidate != 0) {
82                //  Lazy-convert the result text to a SpannableString if we have to
83                if (result == null) {
84                    if (text instanceof SpannableString) {
85                        result = (SpannableString) text;
86                    } else {
87                        result = new SpannableString(text);
88                        text = result;
89                    }
90                }
91                Drawable smiley = mRes.getSmileyIcon(candidate);
92                smiley.setBounds(0, 0, smiley.getIntrinsicWidth(), smiley.getIntrinsicHeight());
93                result.setSpan(new ImageSpan(smiley, ImageSpan.ALIGN_BASELINE),
94                    offset, lastMatchEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
95
96                candidate = 0;
97            }
98
99            //  if there was a match, start searching for the next one after it
100            //  if no match, start at the next character
101            if (lastMatchEnd != -1) {
102                offset = lastMatchEnd;
103                lastMatchEnd = -1;
104            } else {
105                offset++;
106            }
107        }
108
109        //  If there were no modifications, return the original string
110        if (result == null) {
111            return text;
112        }
113
114        return result;
115    }
116}
117