/*
* Copyright 2013 State University of New York at Oswego
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.oswego.csc480_hci521_2013.client.activity;
import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.MenuItem;
import edu.oswego.csc480_hci521_2013.client.AppPlaceHistoryMapper;
import edu.oswego.csc480_hci521_2013.client.Entry;
import edu.oswego.csc480_hci521_2013.client.events.RFGenerateEvent;
import edu.oswego.csc480_hci521_2013.client.events.RFGenerateEventHandler;
import edu.oswego.csc480_hci521_2013.client.events.TreeVisEvent;
import edu.oswego.csc480_hci521_2013.client.events.TreeVisEventHandler;
import edu.oswego.csc480_hci521_2013.client.place.ConfusionMatrixPlace;
import edu.oswego.csc480_hci521_2013.client.place.DoublePanelPlace;
import edu.oswego.csc480_hci521_2013.client.place.DataTablePlace;
import edu.oswego.csc480_hci521_2013.client.place.TreeVisPlace;
import edu.oswego.csc480_hci521_2013.client.presenters.ConfusionMatrixPresenterImpl;
import edu.oswego.csc480_hci521_2013.client.presenters.DataPanelPresenterImpl;
import edu.oswego.csc480_hci521_2013.client.presenters.DoublePanelPresenter;
import edu.oswego.csc480_hci521_2013.client.presenters.TabPanelPresenter;
import edu.oswego.csc480_hci521_2013.client.presenters.TreePanelPresenterImpl;
import edu.oswego.csc480_hci521_2013.client.services.H2OServiceAsync;
import edu.oswego.csc480_hci521_2013.client.ui.ConfusionMatrixViewImpl;
import edu.oswego.csc480_hci521_2013.client.ui.DataPanelViewImpl;
import edu.oswego.csc480_hci521_2013.client.ui.DoublePanelView;
import edu.oswego.csc480_hci521_2013.client.ui.TabLabelView;
import edu.oswego.csc480_hci521_2013.client.ui.TabLabelViewImpl;
import edu.oswego.csc480_hci521_2013.shared.h2o.json.Inspect;
import edu.oswego.csc480_hci521_2013.client.ui.TreePanelViewImpl;
import edu.oswego.csc480_hci521_2013.shared.h2o.json.RF;
import edu.oswego.csc480_hci521_2013.shared.h2o.json.RFTreeView;
import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.InspectBuilder;
import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.RFTreeViewBuilder;
import edu.oswego.csc480_hci521_2013.shared.h2o.json.RFView;
import edu.oswego.csc480_hci521_2013.shared.h2o.json.StoreView;
import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.StoreViewBuilder;
import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.RFBuilder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.gwt.regexp.shared.*;
public class DoublePanelActivity extends AbstractActivity implements DoublePanelPresenter {
static final Logger logger = Logger.getLogger(DoublePanelActivity.class.getName());
private DoublePanelView view;
private PlaceController places;
private EventBus eventBus;
private H2OServiceAsync service;
private TabManager dataTabs = new TabManager();
private TabManager visTabs = new TabManager();
public DoublePanelActivity(DoublePanelView view, PlaceController places, EventBus eventBus, H2OServiceAsync service) {
// FIXME: this constructor should go away...
this(null, view, places, service);
}
public DoublePanelActivity(DoublePanelPlace place, DoublePanelView view, PlaceController places, H2OServiceAsync service) {
// TODO: handle the place, it will carry args for what we should display.
this.view = view;
this.places = places;
this.service = service;
}
@Override
public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
this.eventBus = eventBus;
containerWidget.setWidget(view);
bind(eventBus);
loadParsedDataMenu();
logger.log(Level.INFO, "DoublePanelActivity started");
}
private void bind(EventBus eventBus) {
eventBus.addHandler(TreeVisEvent.TYPE, new TreeVisEventHandler() {
@Override
public void onViewData(TreeVisEvent e) {
addVisTab(e.getData().getDataKey(), e.getData().getModelKey(), e.getIndex());
}
});
eventBus.addHandler(RFGenerateEvent.TYPE, new RFGenerateEventHandler() {
@Override
public void onStart(RFGenerateEvent e) {
logger.log(Level.INFO, "Adding confusion matrix...");
addConfusionMatrixTab(e.getData(),e.getBuilder());
}
});
}
private void loadParsedDataMenu() {
service.getDataStores(new StoreViewBuilder()
.setFilter(".hex").setView(1024),
new AsyncCallback<StoreView>() {
@Override
public void onFailure(Throwable caught) {
// FIXME: we need some sort of general error handler
logger.log(Level.SEVERE, caught.toString());
}
@Override
public void onSuccess(StoreView result) {
for (StoreView.Row row : result.getKeys()) {
// NOTE: there is no way to know from this if it is parsed or not,
// but the naming convention is that parsed data ends in .hex
// we could possibly do an inspect call on each piece to
// check if it is parsed or not...
// TODO: we should check if there are more items still available.
if (row.getKey().endsWith(".hex")) {
String key = row.getKey();
view.addMenuItem(new MenuItem(key, false,
getMenuCommand(key)));
}
}
}
});
}
@Override
public void goTo(Place place) {
this.places.goTo(place);
}
@Override
public void addDataTab(final String datakey) {
logger.log(Level.INFO, "Creating new data tab: " + datakey);
service.getData(new InspectBuilder(datakey),
new AsyncCallback<Inspect>() {
@Override
public void onFailure(Throwable caught) {
logger.log(Level.INFO, "Failure adding data tab.");
logger.log(Level.SEVERE, caught.toString());
// FIXME: do a message box or something...
}
@Override
public void onSuccess(Inspect result)
{
logger.log(Level.INFO, "Building data tab: " + datakey);
DataPanelPresenterImpl presenter = new DataPanelPresenterImpl(
service, new DataPanelViewImpl(), eventBus, datakey,
result);
TabLabelView label = new TabLabelViewImpl();
label.setLabel(datakey);
label.setPresenter(DoublePanelActivity.this);
view.addDataTab(presenter.getView(), label);
dataTabs.addTab(label, presenter);
}
});
}
@Override
public void addVisTab(final String datakey, final String modelkey, final int tree) {
service.getTreeView(
new RFTreeViewBuilder(datakey, modelkey).setTreeNumber(tree),
new AsyncCallback<RFTreeView>() {
@Override
public void onFailure(Throwable thrwbl) {
logger.log(Level.SEVERE, thrwbl.toString());
// FIXME: do a message box or something...
}
@Override
public void onSuccess(RFTreeView treeview) {
TreePanelPresenterImpl presenter = new TreePanelPresenterImpl(
new TreePanelViewImpl(treeview, datakey, modelkey, tree),
treeview, datakey, modelkey, tree);
logger.log(Level.INFO, treeview.toString());
TabLabelView label = new TabLabelViewImpl();
//label.setLabel(datakey + "<br>" + modelkey + "<br>tree " + (tree + 1));
label.setLabel("Tree " + (tree + 1) +"<br>"+parseDatakey(datakey));
label.setPresenter(DoublePanelActivity.this);
view.addVisTab(presenter.getView(), label);
visTabs.addTab(label, presenter);
}
});
}
private String parseDatakey(String dataKey) {
String result = dataKey;
RegExp regex = RegExp.compile("([^\\\\/:*?\"<>|\r\n]+$)");
MatchResult matcher = regex.exec(dataKey);
if (regex.test(dataKey)) {
result = matcher.getGroup(1);
}
return result;
}
@Override
public void addConfusionMatrixTab(RF rf, RFBuilder b) {
ConfusionMatrixViewImpl matrixView = new ConfusionMatrixViewImpl();
matrixView.setResponseVariable(b.getResponseVariable());
ConfusionMatrixPresenterImpl presenter = new ConfusionMatrixPresenterImpl(matrixView, eventBus, rf,b);
//String title = "Confusion Matrix<br>" + rf.getDataKey() + "<br>" + rf.getModelKey();
String title = "Confusion Matrix<br>" + parseDatakey(rf.getDataKey());
TabLabelView label = new TabLabelViewImpl();
label.setLabel(title);
label.setPresenter(this);
view.addVisTab(presenter.getView(), label);
visTabs.addTab(label, presenter);
}
public void addConfusionMatrixTab(RF rf, RFView rfview, RFBuilder b) {
ConfusionMatrixPresenterImpl presenter
= new ConfusionMatrixPresenterImpl(
new ConfusionMatrixViewImpl(), eventBus, rf, b);
presenter.setData(rfview);
presenter.getView().forestFinish(rfview.getNtree());
//String title = "Confusion Matrix<br>" + rf.getDataKey() + "<br>" + rf.getModelKey();
String title = "Confusion Matrix<br>" + parseDatakey(rf.getDataKey());
TabLabelView label = new TabLabelViewImpl();
label.setLabel(title);
label.setPresenter(this);
view.addVisTab(presenter.getView(), label);
visTabs.addTab(label, presenter);
}
private Command getMenuCommand(final String value) {
return new Command() {
@Override
public void execute() {
logger.log(Level.INFO, "Adding dataset: " + value);
addDataTab(value);
}
};
}
private void popoutConfusionMatrixTab(ConfusionMatrixPlace place, int id) {
// FIXME: this needs to be injected...
AppPlaceHistoryMapper historyMapper = Entry.getPlaceHistoryMapper();
String token = historyMapper.getToken(place);
String url = Window.Location.createUrlBuilder().setHash(token).buildString();
int width = Window.getClientWidth() / 2;
int height = Window.getClientHeight() / 2;
String features = "width=" + width + ",height=" + height + ",menubar=0,location=0,toolbar=0,status=0";
ConfusionMatrixActivity.openPanel(this, url, "_blank", features, Integer.toString(id));
}
private void popoutTreeVisTab(TreeVisPlace place, int id) {
// FIXME: this needs to be injected...
AppPlaceHistoryMapper historyMapper = Entry.getPlaceHistoryMapper();
String token = historyMapper.getToken(place);
String url = Window.Location.createUrlBuilder().setHash(token).buildString();
int width = Window.getClientWidth() / 2;
int height = Window.getClientHeight() / 2;
String features = "width=" + width + ",height=" + height + ",menubar=0,location=0,toolbar=0,status=0";
TreeVisActivity.openPanel(this, url, "_blank", features, Integer.toString(id));
}
private void popoutDataTab(DataTablePlace place, int id) {
logger.log(Level.INFO, "Popping data panel: " + place.getDataKey());
// FIXME: this needs to be injected...
AppPlaceHistoryMapper historyMapper = Entry.getPlaceHistoryMapper();
String token = historyMapper.getToken(place);
String url = Window.Location.createUrlBuilder().setHash(token).buildString();
int width = Window.getClientWidth() / 2;
int height = Window.getClientHeight() / 2;
String features = "width=" + width + ",height=" + height + ",menubar=0,location=0,toolbar=0,status=0";
DataPanelActivity.openPanel(this, url, "_blank", features, Integer.toString(id));
}
public void popinDataPanel(String id) {
logger.log(Level.INFO, "Adding data panel back in!");
TabLabelView tab = dataTabs.unpopTab(Integer.parseInt(id));
TabPanelPresenter p = dataTabs.getPresenter(tab);
// FIXME: reusing presenters/view does not work yet...
//p.added();
dataTabs.deleteTab(tab);
addDataTab(((DataPanelPresenterImpl) p).getDataKey());
}
public void popinVisPanel(String id) {
logger.log(Level.INFO, "Adding vis panel back in!");
TabLabelView tab = visTabs.unpopTab(Integer.parseInt(id));
TabPanelPresenter p = visTabs.getPresenter(tab);
// FIXME: reusing presenters/view does not work yet...
//p.added();
visTabs.deleteTab(tab);
if (p instanceof ConfusionMatrixPresenterImpl) {
ConfusionMatrixPresenterImpl cp = (ConfusionMatrixPresenterImpl) p;
addConfusionMatrixTab(cp.getRandomForest(), cp.getData(), cp.getBuilder());
} else {
TreePanelPresenterImpl tp = (TreePanelPresenterImpl) p;
addVisTab(tp.getDatakey(), tp.getModelkey(), tp.getTreeIndex());
}
}
@Override
public void popout(TabLabelView tab) {
if (dataTabs.hasTab(tab)) {
int index = dataTabs.popTab(tab);
view.removeDataTab(index);
TabPanelPresenter p = dataTabs.getPresenter(tab);
p.removed();
String datakey = ((DataPanelPresenterImpl) p).getDataKey();
DataTablePlace place = new DataTablePlace();
place.setDataKey(datakey);
popoutDataTab(place, tab.hashCode());
} else if (visTabs.hasTab(tab)) {
int index = visTabs.popTab(tab);
view.removeVisTab(index);
TabPanelPresenter p = visTabs.getPresenter(tab);
p.removed();
if (p instanceof ConfusionMatrixPresenterImpl) {
ConfusionMatrixPresenterImpl cp = (ConfusionMatrixPresenterImpl) p;
ConfusionMatrixPlace place = new ConfusionMatrixPlace();
place.setRandomForest(cp.getRandomForest());
popoutConfusionMatrixTab(place, tab.hashCode());
} else {
TreePanelPresenterImpl tp = (TreePanelPresenterImpl) p;
TreeVisPlace place = new TreeVisPlace();
place.setDataKey(tp.getDatakey());
place.setModelKey(tp.getModelkey());
place.setTree(tp.getTreeIndex());
popoutTreeVisTab(place, tab.hashCode());
}
} else {
logger.log(Level.SEVERE, "Unknown tab!");
}
}
@Override
public void close(TabLabelView tab) {
if (dataTabs.hasTab(tab)) {
int index = dataTabs.deleteTab(tab);
view.removeDataTab(index);
TabPanelPresenter p = dataTabs.getPresenter(tab);
p.removed();
} else if (visTabs.hasTab(tab)) {
int index = visTabs.deleteTab(tab);
view.removeVisTab(index);
TabPanelPresenter p = visTabs.getPresenter(tab);
p.removed();
} else {
logger.log(Level.SEVERE, "Unknown tab!");
}
}
private static class TabManager {
List<TabLabelView> tabList = new ArrayList<TabLabelView>();
Map<TabLabelView, TabPanelPresenter> panels = new HashMap<TabLabelView, TabPanelPresenter>();
Map<Integer, TabLabelView> popped = new HashMap<Integer, TabLabelView>();
boolean hasTab(TabLabelView tab) {
return panels.containsKey(tab);
}
TabPanelPresenter getPresenter(TabLabelView tab) {
return panels.get(tab);
}
void addTab(TabLabelView tab, TabPanelPresenter presenter) {
panels.put(tab, presenter);
tabList.add(tab);
}
int popTab(TabLabelView tab) {
int index = tabList.indexOf(tab);
tabList.remove(tab);
popped.put(tab.hashCode(), tab);
return index;
}
TabLabelView unpopTab(Integer id) {
TabLabelView t = popped.remove(id);
tabList.add(t);
return t;
}
int deleteTab(TabLabelView tab) {
int index = tabList.indexOf(tab);
tabList.remove(tab);
panels.remove(tab);
return index;
}
}
}