package org.geogebra.web.web.gui.view.data;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.euclidian.event.KeyEvent;
import org.geogebra.common.euclidian.event.KeyHandler;
import org.geogebra.common.gui.view.data.DataAnalysisModel;
import org.geogebra.common.gui.view.data.DataAnalysisModel.Regression;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.arithmetic.ExpressionNodeConstants.StringType;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.geos.GeoFunctionable;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.main.Localization;
import org.geogebra.common.main.error.ErrorHelper;
import org.geogebra.web.html5.gui.inputfield.AutoCompleteTextFieldW;
import org.geogebra.web.html5.gui.util.LayoutUtilW;
import org.geogebra.web.html5.main.AppW;
import org.geogebra.web.html5.main.DrawEquationW;
import org.geogebra.web.html5.main.LocalizationW;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.ScrollPanel;
/**
* Panel to select and display the DataAnalysisView regression model.
*
* @author G. Sturr, Laszlo Gal
*/
public class RegressionPanelW extends FlowPanel implements StatPanelInterfaceW {
private AppW app;
private final LocalizationW loc;
private DataAnalysisViewW statDialog;
// regression panel objects
private Label lblEqn;
private ListBox lbRegression, lbPolyOrder;
private Label lblEvaluate;
private AutoCompleteTextFieldW fldInputX;
private String[] regressionLabels;
private Label fldOutputY;
private boolean isIniting = true;
private FlowPanel predictionPanel;
private Canvas latexCanvas;
private GeoNumeric sample;
private DataAnalysisModel daModel;
/**
* Construct a regression panel
*
* @param app
* application
* @param statDialog
* invoking instance of DataAnalysisView
*/
public RegressionPanelW(AppW app, DataAnalysisViewW statDialog) {
this.app = app;
this.loc = (LocalizationW) app.getLocalization();
this.statDialog = statDialog;
this.daModel = statDialog.getModel();
setStyleName("daRegressionPanel");
sample = new GeoNumeric(app.getKernel().getConstruction());
sample.setObjColor(GColor.RED);
createRegressionPanel();
setLabels();
updateRegressionPanel();
updateGUI();
isIniting = false;
}
private FlowPanel regressionPanel;
private Label regressionTitle;
private void createRegressionPanel() {
// components
String[] orders = { "2", "3", "4", "5", "6", "7", "8", "9" };
lbPolyOrder = new ListBox();
for (String item: orders) {
lbPolyOrder.addItem(item);
}
lbPolyOrder.setSelectedIndex(0);
lbPolyOrder.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
actionPerformed(lbPolyOrder);
}
});
regressionLabels = new String[Regression.values().length];
setRegressionLabels(app.getLocalization());
lbRegression = new ListBox();
for (String item: regressionLabels) {
lbRegression.addItem(item);
}
lbRegression.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
actionPerformed(lbRegression);
}
});
lblEqn = new Label();
// regression combo panel
FlowPanel lbPanel = new FlowPanel();
lbPanel.add(lbRegression);
lbPanel.add(lbPolyOrder);
// regression label panel
FlowPanel eqnPanel = new FlowPanel();
latexCanvas = Canvas.createIfSupported();
latexCanvas.setStyleName("daRegEquation");
eqnPanel.add(latexCanvas);
ScrollPanel scroller = new ScrollPanel();
scroller.add(eqnPanel);
// prediction panel
createPredictionPanel();
// model panel: equation + prediction
FlowPanel modelPanel = new FlowPanel();
modelPanel.add(scroller);
modelPanel.add(predictionPanel);
regressionTitle = new Label(loc.getMenu("RegressionModel"));
regressionTitle.setStyleName("panelTitle");
// put it all together
regressionPanel = new FlowPanel();
regressionPanel.add(regressionTitle);
regressionPanel.add(LayoutUtilW.panelRow(lbPanel, modelPanel));
add(regressionPanel);
}
/**
* Creates a panel to evaluate the regression model for a given x value
*/
private void createPredictionPanel() {
lblEvaluate = new Label();
fldInputX = new AutoCompleteTextFieldW(6, app);
fldInputX.addKeyHandler(new KeyHandler() {
@Override
public void keyReleased(KeyEvent e) {
if (e.isEnterKey()) {
doTextFieldActionPerformed(fldInputX);
}
}
});
fldInputX.addBlurHandler(new BlurHandler() {
@Override
public void onBlur(BlurEvent event) {
doTextFieldActionPerformed(fldInputX);
}
});
Label lblOutputY = new Label();
fldOutputY = new Label();
predictionPanel = new FlowPanel();
predictionPanel.add(LayoutUtilW.panelRow(lblEvaluate, new Label("x = "), fldInputX,
new Label("y = "), lblOutputY, fldOutputY));
}
/**
* Updates the regression equation label and the prediction panel
*/
public void updateRegressionPanel() {
if (statDialog.getController().isValidData()) {
setRegressionEquationLabel();
doTextFieldActionPerformed(fldInputX);
} else {
setRegressionEquationLabelEmpty();
}
updateGUI();
}
/**
* Clears the X and Y fields of the prediction panel
*/
public void clearPredictionPanel() {
fldInputX.setText("");
fldOutputY.setText("");
}
private void setRegressionLabels(Localization loc) {
for (Regression r : Regression.values()) {
regressionLabels[r.ordinal()] = loc.getMenu(r.getLabel());
}
}
/**
* Sets the labels according to current locale
*/
@Override
public void setLabels() {
regressionLabels = new String[Regression.values().length];
setRegressionLabels(loc);
// we need to remove old labels from combobox and we don't want the
// listener to
// be operational since it will call unnecessary Construction updates
int j = lbRegression.getSelectedIndex();
lbRegression.clear();
for (int i = 0; i < regressionLabels.length; i++) {
lbRegression.addItem(regressionLabels[i]);
}
lbRegression.setSelectedIndex(j);
regressionTitle.setText(loc
.getMenu("RegressionModel"));
lblEqn.setText(loc.getMenu("Equation") + ":");
lblEvaluate.setText(loc.getMenu("Evaluate") + ": ");
}
/**
* Draws the regression equation into the regression equation JLabel icon
*/
public void setRegressionEquationLabel() {
// get the LaTeX string for the regression equation
String eqn;
// GeoElement geoRegression = statDialog.getRegressionModel();
try {
// prepare number format
StringTemplate highPrecision;
if (daModel.getPrintDecimals() >= 0) {
highPrecision = StringTemplate.printDecimals(StringType.LATEX,
daModel.getPrintDecimals(), false);
} else {
highPrecision = StringTemplate.printFigures(StringType.LATEX,
daModel.getPrintFigures(), false);
}
// no regression
if (daModel.getRegressionMode().equals(Regression.NONE)
|| statDialog.getRegressionModel() == null) {
eqn = "";
}
// linear
else if (daModel.getRegressionMode().equals(Regression.LINEAR)) {
eqn = statDialog.getRegressionModel().getFormulaString(
highPrecision, true);
}
// nonlinear
else {
eqn = "y = "
+ statDialog.getRegressionModel().getFormulaString(
highPrecision, true);
}
}
catch (Exception e) {
e.printStackTrace();
eqn = "\\text{" + loc.getPlain("NotAvailable") + "}";
}
DrawEquationW.paintOnCanvas(sample, eqn, latexCanvas,
app.getFontSizeWeb());
updateGUI();
}
/**
* Set the regression equation label to an empty string
*/
private void setRegressionEquationLabelEmpty() {
updateGUI();
}
private void updateGUI() {
lbPolyOrder.setVisible(daModel.getRegressionMode().equals(
Regression.POLY));
predictionPanel.setVisible(!(daModel.getRegressionMode()
.equals(Regression.NONE)));
}
public void actionPerformed(Object source) {
if (source instanceof AutoCompleteTextFieldW) {
doTextFieldActionPerformed((AutoCompleteTextFieldW) source);
}
else if (source == lbRegression) {
daModel.setRegressionMode(lbRegression.getSelectedIndex());
updateRegressionPanel();
}
else if (source == lbPolyOrder) {
daModel.setRegressionOrder(lbPolyOrder.getSelectedIndex() + 2);
statDialog.getController().setRegressionGeo();
statDialog.getController().updateRegressionPanel();
setRegressionEquationLabel();
// force update
daModel.setRegressionMode(Regression.POLY.ordinal());
}
}
private void doTextFieldActionPerformed(AutoCompleteTextFieldW source) {
if (isIniting) {
return;
}
if (source == fldInputX) {
try {
String inputText = source.getText().trim();
if (inputText == null || inputText.length() == 0) {
return;
}
NumberValue nv;
nv = app.getKernel().getAlgebraProcessor()
.evaluateToNumeric(inputText, ErrorHelper.silent());
double value = nv.getDouble();
double output = ((GeoFunctionable) statDialog
.getRegressionModel()).getGeoFunction().value(value);
fldOutputY.setText(statDialog.format(output));
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void updatePanel() {
// TODO Auto-generated method stub
}
public int getRegressionIdx() {
return lbRegression.getSelectedIndex();
}
public void setRegressionIdx(int idx) {
lbRegression.setSelectedIndex(idx);
}
}