package com.smartandroid.sa.floatextview;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.TextPaint;
import android.text.style.StyleSpan;
import android.text.style.URLSpan;
/**
* Created by Dean on 24/06/2014.
*/
public class SpanParser {
public SpanParser(FlowTextView flowTextView, PaintHelper paintHelper) {
this.mFlowTextView = flowTextView;
this.mPaintHelper = paintHelper;
}
private final PaintHelper mPaintHelper;
private final FlowTextView mFlowTextView;
private final ArrayList<HtmlLink> mLinks = new ArrayList<HtmlLink>();
private int mTextLength = 0;
private Spannable mSpannable;
private final HashMap<Integer, HtmlObject> sorterMap = new HashMap<Integer, HtmlObject>();
public float parseSpans(ArrayList<HtmlObject> objects, Object[] spans,
int lineStart, int lineEnd, float baseXOffset) {
sorterMap.clear();
int charFlagSize = lineEnd - lineStart;
boolean[] charFlags = new boolean[charFlagSize];
String tempString;
int spanStart;
int spanEnd;
int charCounter;
for (Object span : spans) {
spanStart = mSpannable.getSpanStart(span);
spanEnd = mSpannable.getSpanEnd(span);
if (spanStart < lineStart)
spanStart = lineStart;
if (spanEnd > lineEnd)
spanEnd = lineEnd;
for (charCounter = spanStart; charCounter < spanEnd; charCounter++) { // mark
// these
// characters
// as
// rendered
int charFlagIndex = charCounter - lineStart;
charFlags[charFlagIndex] = true;
}
tempString = extractText(spanStart, spanEnd);
sorterMap.put(spanStart,
parseSpan(span, tempString, spanStart, spanEnd));
}
charCounter = 0;
while (!isArrayFull(charFlags)) {
while (true) {
if (charCounter >= charFlagSize)
break;
if (charFlags[charCounter] == true) {
charCounter++;
continue;
}
int temp1 = charCounter;
while (true) {
if (charCounter > charFlagSize)
break;
if (charCounter < charFlagSize) {
if (charFlags[charCounter] == false) {
charFlags[charCounter] = true;// mark as filled
charCounter++;
continue;
}
}
int temp2 = charCounter;
spanStart = lineStart + temp1;
spanEnd = lineStart + temp2;
tempString = extractText(spanStart, spanEnd);
sorterMap.put(spanStart,
parseSpan(null, tempString, spanStart, spanEnd));
break;
}
}
}
Object[] sorterKeys = sorterMap.keySet().toArray();
Arrays.sort(sorterKeys);
float thisXoffset = baseXOffset;
for (charCounter = 0; charCounter < sorterKeys.length; charCounter++) {
HtmlObject thisObj = sorterMap.get(sorterKeys[charCounter]);
thisObj.xOffset = thisXoffset;
thisXoffset += thisObj.paint.measureText(thisObj.content);
objects.add(thisObj);
}
return (thisXoffset - baseXOffset);
}
private HtmlObject parseSpan(Object span, String content, int start, int end) {
if (span instanceof URLSpan) {
return getHtmlLink((URLSpan) span, content, start, end, 0);
} else if (span instanceof StyleSpan) {
return getStyledObject((StyleSpan) span, content, start, end, 0);
} else {
return getHtmlObject(content, start, end, 0);
}
}
private HtmlObject getStyledObject(StyleSpan span, String content,
int start, int end, float thisXOffset) {
TextPaint paint = mPaintHelper.getPaintFromHeap();
paint.setTypeface(Typeface.defaultFromStyle(span.getStyle()));
paint.setTextSize(mFlowTextView.getTextsize());
paint.setColor(mFlowTextView.getColor());
span.updateDrawState(paint);
span.updateMeasureState(paint);
HtmlObject obj = new HtmlObject(content, start, end, thisXOffset, paint);
obj.recycle = true;
return obj;
}
private HtmlObject getHtmlObject(String content, int start, int end,
float thisXOffset) {
return new HtmlObject(content, start, end, thisXOffset,
mFlowTextView.getTextPaint());
}
public void reset() {
mLinks.clear();
}
private HtmlLink getHtmlLink(URLSpan span, String content, int start,
int end, float thisXOffset) {
HtmlLink obj = new HtmlLink(content, start, end, thisXOffset,
mFlowTextView.getLinkPaint(), span.getURL());
mLinks.add(obj);
return obj;
}
public void addLink(HtmlLink thisLink, float yOffset, float width,
float height) {
thisLink.yOffset = yOffset - 20;
thisLink.width = width;
thisLink.height = height + 20;
mLinks.add(thisLink);
}
private String extractText(int start, int end) {
if (start < 0)
start = 0;
if (end > mTextLength - 1)
end = mTextLength - 1;
return mSpannable.subSequence(start, end).toString();
}
private static boolean isArrayFull(boolean[] array) {
for (int arrayIndex = 0; arrayIndex < array.length; arrayIndex++) {
if (array[arrayIndex] == false)
return false;
}
return true;
}
// GETTERS AND SETTERS
public ArrayList<HtmlLink> getLinks() {
return mLinks;
}
public Spannable getSpannable() {
return mSpannable;
}
public void setSpannable(Spannable mSpannable) {
this.mSpannable = mSpannable;
mTextLength = mSpannable.length();
}
}