package freenet.clients.http.updateableelements;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import freenet.client.FetchException;
import freenet.client.filter.HTMLFilter.ParsedTag;
import freenet.clients.http.FProxyFetchInProgress;
import freenet.clients.http.FProxyFetchInProgress.REFILTER_POLICY;
import freenet.clients.http.FProxyFetchResult;
import freenet.clients.http.FProxyFetchTracker;
import freenet.clients.http.FProxyFetchWaiter;
import freenet.clients.http.FProxyToadlet;
import freenet.clients.http.SimpleToadletServer;
import freenet.clients.http.ToadletContext;
import freenet.keys.FreenetURI;
import freenet.support.Base64;
import freenet.support.HTMLNode;
import freenet.support.Logger;
/** A pushed image, the progress is shown with the ImageCreatorToadlet */
public class ImageElement extends BaseUpdateableElement {
private static volatile boolean logMINOR;
static {
Logger.registerClass(ImageElement.class);
}
/** The tracker that the Fetcher can be acquired */
public FProxyFetchTracker tracker;
/** The original URI */
public final FreenetURI origKey;
/** The URI of the download this progress bar shows */
public FreenetURI key;
/** The maxSize */
public long maxSize;
/** The FetchListener that gets notified when the download progresses */
private NotifierFetchListener fetchListener;
private ParsedTag originalImg;
// FIXME get this from global weakFastRandom ???
private final int randomNumber;
private boolean wasError = false;
public static ImageElement createImageElement(FProxyFetchTracker tracker,FreenetURI key,long maxSize,ToadletContext ctx, boolean pushed){
return createImageElement(tracker,key,maxSize,ctx,-1,-1, null, pushed);
}
public static ImageElement createImageElement(FProxyFetchTracker tracker,FreenetURI key,long maxSize,ToadletContext ctx,int width,int height, String name, boolean pushed){
Map<String,String> attributes=new HashMap<String, String>();
attributes.put("src", key.toString());
if(width!=-1){
attributes.put("width", String.valueOf(width));
}
if(height!=-1){
attributes.put("height", String.valueOf(height));
}
if(name != null) {
attributes.put("alt", name);
attributes.put("title", name);
}
return new ImageElement(tracker,key,maxSize,ctx,new ParsedTag("img", attributes), pushed);
}
public ImageElement(FProxyFetchTracker tracker, FreenetURI key, long maxSize, ToadletContext ctx, ParsedTag originalImg, boolean pushed) {
super("span", ctx);
randomNumber = tracker.makeRandomElementID();
long now = System.currentTimeMillis();
if (logMINOR) {
Logger.minor(this, "ImageElement creating for uri:" + key);
}
this.originalImg = originalImg;
this.tracker = tracker;
this.key = this.origKey = key;
this.maxSize = maxSize;
init(pushed);
if(!pushed) return;
// Creates and registers the FetchListener
fetchListener = new NotifierFetchListener(((SimpleToadletServer) ctx.getContainer()).pushDataManager, this);
((SimpleToadletServer) ctx.getContainer()).getTicker().queueTimedJob(new Runnable() {
@Override
public void run() {
try {
FProxyFetchWaiter waiter = ImageElement.this.tracker.makeFetcher(ImageElement.this.key, ImageElement.this.maxSize, null, REFILTER_POLICY.RE_FILTER);
ImageElement.this.tracker.getFetchInProgress(ImageElement.this.key, ImageElement.this.maxSize, null).addListener(fetchListener);
ImageElement.this.tracker.getFetchInProgress(ImageElement.this.key, ImageElement.this.maxSize, null).close(waiter);
} catch (FetchException fe) {
if (fe.newURI != null) {
try {
ImageElement.this.key = fe.newURI;
FProxyFetchWaiter waiter = ImageElement.this.tracker.makeFetcher(ImageElement.this.key, ImageElement.this.maxSize, null, REFILTER_POLICY.RE_FILTER);
ImageElement.this.tracker.getFetchInProgress(ImageElement.this.key, ImageElement.this.maxSize, null).addListener(fetchListener);
ImageElement.this.tracker.getFetchInProgress(ImageElement.this.key, ImageElement.this.maxSize, null).close(waiter);
} catch (FetchException fe2) {
wasError = true;
}
}
}
fetchListener.onEvent();
}
}, 0);
if (logMINOR) {
Logger.minor(this, "ImageElement creating finished in:" + (System.currentTimeMillis() - now) + " ms");
}
}
@Override
public void dispose() {
if (logMINOR) {
Logger.minor(this, "Disposing ImageElement");
}
FProxyFetchInProgress progress = tracker.getFetchInProgress(key, maxSize, null);
if (progress != null) {
progress.removeListener(fetchListener);
if (logMINOR) {
Logger.minor(this, "canCancel():" + progress.canCancel());
}
progress.requestImmediateCancel();
if (progress.canCancel()) {
tracker.run();
}
}
}
@Override
public String getUpdaterId(String requestId) {
return getId(origKey, randomNumber);
}
public static String getId(FreenetURI uri, int randomNumber) {
return Base64.encodeStandardUTF8(("image[URI:" + uri.toString() + ",random:" + randomNumber + "]"));
}
@Override
public String getUpdaterType() {
return UpdaterConstants.IMAGE_ELEMENT_UPDATER;
}
@Override
public void updateState(boolean initial) {
if (logMINOR) {
Logger.minor(this, "Updating ImageElement for url:" + key + (origKey == key ? (" originally " + origKey) : ""));
}
children.clear();
HTMLNode whenJsEnabled = new HTMLNode("span", "class", "jsonly ImageElement");
addChild(whenJsEnabled);
// When js disabled
addChild("noscript").addChild(makeHtmlNodeForParsedTag(originalImg));
if (initial) {
if (wasError) {
whenJsEnabled.addChild(makeHtmlNodeForParsedTag(originalImg));
} else {
Map<String, String> attr = originalImg.getAttributesAsMap();
String sizePart = "";
if (attr.containsKey("width") && attr.containsKey("height")) {
sizePart = "&width=" + attr.get("width") + "&height=" + attr.get("height");
}
attr.put("src", "/imagecreator/?text=+"+FProxyToadlet.l10n("imageinitializing")+"+" + sizePart);
whenJsEnabled.addChild(makeHtmlNodeForParsedTag(new ParsedTag(originalImg, attr)));
whenJsEnabled.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "fetchedBlocks", String.valueOf(0) });
whenJsEnabled.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "requiredBlocks", String.valueOf(1) });
}
} else {
FProxyFetchResult fr = null;
FProxyFetchWaiter waiter = null;
try {
try {
waiter = tracker.makeFetcher(key, maxSize, null, REFILTER_POLICY.RE_FILTER);
fr = waiter.getResultFast();
} catch (FetchException fe) {
whenJsEnabled.addChild("div", "error");
}
if (fr == null) {
whenJsEnabled.addChild("div", "No fetcher found");
} else {
if (fr.isFinished() && fr.hasData()) {
if (logMINOR) {
Logger.minor(this, "ImageElement is completed");
}
whenJsEnabled.addChild(makeHtmlNodeForParsedTag(originalImg));
} else if (fr.failed != null) {
if (logMINOR) {
Logger.minor(this, "ImageElement is errorous");
}
whenJsEnabled.addChild(makeHtmlNodeForParsedTag(originalImg));
} else {
if (logMINOR) {
Logger.minor(this, "ImageElement is still in progress");
}
int total = fr.requiredBlocks;
int fetchedPercent = (int) (fr.fetchedBlocks / (double) total * 100);
Map<String, String> attr = originalImg.getAttributesAsMap();
String sizePart = new String();
if (attr.containsKey("width") && attr.containsKey("height")) {
sizePart = "&width=" + attr.get("width") + "&height=" + attr.get("height");
}
attr.put("src", "/imagecreator/?text=" + fetchedPercent + "%25" + sizePart);
whenJsEnabled.addChild(makeHtmlNodeForParsedTag(new ParsedTag(originalImg, attr)));
whenJsEnabled.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "fetchedBlocks", String.valueOf(fr.fetchedBlocks) });
whenJsEnabled.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "requiredBlocks", String.valueOf(fr.requiredBlocks) });
}
}
} finally {
if (waiter != null) {
tracker.getFetchInProgress(key, maxSize, null).close(waiter);
}
if (fr != null) {
tracker.getFetchInProgress(key, maxSize, null).close(fr);
}
}
}
}
// FIXME move this to some global utilities class.
private HTMLNode makeHtmlNodeForParsedTag(ParsedTag pt) {
List<String> attributeNames = new ArrayList<String>();
List<String> attributeValues = new ArrayList<String>();
for (Entry<String, String> att : pt.getAttributesAsMap().entrySet()) {
attributeNames.add(att.getKey());
attributeValues.add(att.getValue());
}
return new HTMLNode(pt.element, attributeNames.toArray(new String[] {}), attributeValues.toArray(new String[] {}));
}
@Override
public String toString() {
return "ImageElement[key:" + key + ",maxSize:" + maxSize + ",originalImg:" + originalImg + ",updaterId:" + getUpdaterId(null) + "]";
}
}