package org.sagemath.droid.views;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.widget.LinearLayout;
import com.squareup.otto.Subscribe;
import org.sagemath.droid.events.InteractUpdateEvent;
import org.sagemath.droid.events.ReplyEvent;
import org.sagemath.droid.interacts.InteractView;
import org.sagemath.droid.models.database.Cell;
import org.sagemath.droid.models.gson.BaseReply;
import org.sagemath.droid.models.gson.InteractReply;
import org.sagemath.droid.states.InteractViewState;
import org.sagemath.droid.states.OutputBlockState;
import org.sagemath.droid.states.OutputViewState;
import org.sagemath.droid.utils.BusProvider;
/**
* The View hosting the interacts, if any.
*
* @author Rasmi Elsamar
* @author Nikhil Peter Raj
*/
public class OutputView
extends LinearLayout {
private final static String TAG = "SageDroid:OutputView";
private OutputWebView block;
private InteractView interactView;
private Context context;
private Cell cell;
public OutputView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
setOrientation(VERTICAL);
setFocusable(true);
setFocusableInTouchMode(true);
}
public void setCell(Cell cell) {
this.cell = cell;
}
public void register() {
BusProvider.getInstance().register(this);
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
OutputBlockState blockState = null;
InteractViewState viewState = null;
Log.i(TAG, "In onSaveInstanceState");
if (block != null) {
blockState = new OutputBlockState(superState, block.getHtmlData());
}
if (interactView != null) {
viewState = new InteractViewState(superState, interactView.getAddedViews());
}
if (blockState == null && viewState == null) {
//Contains neither html output nor interacts, just return normal
Log.i(TAG, "No output, default behaviour");
return superState;
}
if (viewState == null) {
//Only HTML output
Log.i(TAG, "Saving HTML Output");
return blockState;
} else {
// Has both Interact Controls and HTML
Log.i(TAG, "Saving Interact Output");
return new OutputViewState(superState, blockState, viewState);
}
}
public void unregisterComponentViews() {
if (block != null) {
block.unregister();
}
if (interactView != null) {
interactView.unregister();
}
BusProvider.getInstance().unregister(this);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof BaseSavedState)) {
//No state was saved, skip
super.onRestoreInstanceState(state);
return;
}
removeAllViews();
if (state instanceof OutputBlockState) {
//HTML was saved, restore it.
clear();
final OutputBlockState savedState = (OutputBlockState) state;
super.onRestoreInstanceState(savedState.getSuperState());
//Have to post it in a runnable or UI will not update
handler.post(new Runnable() {
@Override
public void run() {
String html = savedState.getSavedHtml();
block = getOutputBlock();
block.setHtmlFromSavedState(html);
}
});
} else if (state instanceof OutputViewState) {
//Restore an interact state, along with HTML
OutputViewState outputViewState = (OutputViewState) state;
super.onRestoreInstanceState(outputViewState.getSuperState());
final OutputBlockState blockState = outputViewState.getOutputBlockState();
final InteractViewState viewState = outputViewState.getInteractViewState();
handler.post(new Runnable() {
@Override
public void run() {
//Restore html
block = getOutputBlock();
block.setHtmlFromSavedState(blockState.getSavedHtml());
//Restore interacts
interactView = new InteractView(context);
interactView.addInteractsFromSavedState(viewState.getSavedControls());
addView(interactView, 0);
}
});
}
}
//Prevent Child Views from saving/restoring their state,
//since we will handle this explicitly
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
}
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
super.dispatchRestoreInstanceState(container);
}
@Subscribe
public void onReplyReceived(ReplyEvent replyEvent) {
Log.i(TAG, "Received Reply: " + replyEvent.getReply().getStringMessageType());
BaseReply reply = replyEvent.getReply();
if (reply instanceof InteractReply) {
UpdateResult task = new UpdateResult();
task.interact = (InteractReply) reply;
handler.post(task);
} else {
UpdateResult task = new UpdateResult();
task.output = reply;
handler.post(task);
}
}
@Subscribe
public void onInteractUpdated(InteractUpdateEvent event) {
block.clearBlocks();
}
private Handler handler = new Handler();
public OutputWebView getOutputBlock() {
if (block != null)
return block;
else return newOutputBlock();
}
private OutputWebView newOutputBlock() {
Log.i(TAG, "Creating newOutputBlock");
OutputWebView newBlock = new OutputWebView(context, cell);
Log.i(TAG, "Block data: " + newBlock.getHtmlData());
addView(newBlock);
block = newBlock;
return block;
}
private class UpdateResult implements Runnable {
private BaseReply output;
private InteractReply interact;
@Override
public void run() {
if (output != null) {
Log.d(TAG, "Setting: " + output.getStringMessageType());
OutputWebView block = getOutputBlock();
Log.i(TAG, "Setting block output: " + output.getStringMessageType());
block.set(output);
}
if (interact != null) {
interactView = new InteractView(context);
interactView.set(interact);
Log.i(TAG, "Adding Interact view with controls: "
+ interact.getContent().getData().getInteract().getControls());
addView(interactView, 0);
}
}
}
public void clear() {
removeAllViews();
block = null;
}
public void disableInteractViews() {
if (interactView != null) {
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
interactView.disableViews();
}
});
}
}
public void enableInteractViews() {
if (interactView != null) {
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
interactView.enableViews();
}
});
}
}
}