package it.albertus.cycles.gui;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import it.albertus.cycles.gui.FormProperty.LabelDataKey;
import it.albertus.cycles.gui.FormProperty.TextDataKey;
import it.albertus.cycles.gui.listener.PropertyFocusListener;
import it.albertus.cycles.gui.listener.PropertyKeyListener;
import it.albertus.cycles.gui.listener.PropertyVerifyListener;
import it.albertus.cycles.gui.listener.TorqueGraphMouseListener;
import it.albertus.cycles.gui.listener.TorquePropertyFocusListener;
import it.albertus.cycles.model.Bike;
import it.albertus.cycles.model.Bike.BikeType;
import it.albertus.cycles.model.BikesCfg;
import it.albertus.cycles.model.Gearbox;
import it.albertus.cycles.model.Setting;
import it.albertus.cycles.model.Settings;
import it.albertus.cycles.model.Torque;
import it.albertus.cycles.resources.Messages;
public class Tabs {
private final CyclesModGui gui;
private final TextFormatter textFormatter;
private final TabFolder tabFolder;
private final Map<String, FormProperty> formProperties = new HashMap<String, FormProperty>();
private final Map<BikeType, Group> settingsGroups = new EnumMap<BikeType, Group>(BikeType.class);
private final Map<BikeType, Group> gearboxGroups = new EnumMap<BikeType, Group>(BikeType.class);
private final Map<BikeType, Group> torqueGroups = new EnumMap<BikeType, Group>(BikeType.class);
private final Map<BikeType, TorqueGraph> torqueGraphs = new EnumMap<BikeType, TorqueGraph>(BikeType.class);
private final PropertyVerifyListener propertyVerifyListener;
private final PropertyFocusListener propertyFocusListener;
private final TorquePropertyFocusListener torquePropertyFocusListener;
private final PropertyKeyListener propertyKeyListener;
Tabs(final CyclesModGui gui) {
this.gui = gui;
textFormatter = new TextFormatter(gui);
propertyVerifyListener = new PropertyVerifyListener(gui);
propertyFocusListener = new PropertyFocusListener(gui);
torquePropertyFocusListener = new TorquePropertyFocusListener(gui);
propertyKeyListener = new PropertyKeyListener(gui);
tabFolder = new TabFolder(gui.getShell(), SWT.NULL);
for (final Bike bike : gui.getBikesInf().getBikes()) {
final TabItem tabItem = new TabItem(tabFolder, SWT.NULL);
tabItem.setText(bike.getType().getDisplacement() + " cc");
// This outer composite is required for GTK!
final Composite outerComposite = new Composite(tabFolder, SWT.NONE);
outerComposite.setLayout(new FillLayout());
final ScrolledComposite tabScrolledComposite = new ScrolledComposite(outerComposite, SWT.V_SCROLL | SWT.H_SCROLL);
final Composite tabComposite = new Composite(tabScrolledComposite, SWT.NONE);
GridLayoutFactory.swtDefaults().numColumns(2).applyTo(tabComposite);
// Settings
final Group settingsGroup = new Group(tabComposite, SWT.NULL);
settingsGroup.setText(Messages.get("lbl.settings"));
// Posizionamento dell'elemento all'interno del contenitore...
GridDataFactory.fillDefaults().grab(false, true).applyTo(settingsGroup);
// Definizione di come saranno disposti gli elementi contenuti...
GridLayoutFactory.swtDefaults().numColumns(6).applyTo(settingsGroup);
settingsGroups.put(bike.getType(), settingsGroup);
for (final Setting setting : bike.getSettings().getValues().keySet()) {
final String key = BikesCfg.buildPropertyKey(bike.getType(), Settings.class, setting.toString());
final Integer defaultValue = gui.getDefaultProperties().get(key);
final Label label = new Label(settingsGroup, SWT.NULL);
GridDataFactory.swtDefaults().applyTo(label);
final String labelTextKey = "lbl." + setting.toString();
label.setText(Messages.get(labelTextKey));
label.setData(LabelDataKey.KEY.toString(), labelTextKey);
label.setToolTipText(key);
final Text text = new Text(settingsGroup, SWT.BORDER);
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, true).applyTo(text);
final int textSize = Integer.toString(Settings.MAX_VALUE).length();
text.setData(TextDataKey.DEFAULT.toString(), defaultValue);
text.setData(TextDataKey.KEY.toString(), key);
text.setData(TextDataKey.SIZE.toString(), textSize);
text.setData(TextDataKey.MAX.toString(), Settings.MAX_VALUE);
textFormatter.setSampleNumber(text);
text.addKeyListener(propertyKeyListener);
text.addFocusListener(propertyFocusListener);
text.addVerifyListener(propertyVerifyListener);
formProperties.put(key, new FormProperty(label, text));
}
// Torque graph
final TorqueGraph graph = new TorqueGraph(tabComposite, bike);
graph.getXyGraph().getPlotArea().addMouseListener(new TorqueGraphMouseListener(bike, formProperties));
GridDataFactory.fillDefaults().grab(true, true).span(1, 2).applyTo(graph);
torqueGraphs.put(bike.getType(), graph);
// Gearbox
final Group gearboxGroup = new Group(tabComposite, SWT.NULL);
gearboxGroup.setText(Messages.get("lbl.gearbox"));
GridDataFactory.fillDefaults().grab(false, true).applyTo(gearboxGroup);
GridLayoutFactory.swtDefaults().numColumns(10).applyTo(gearboxGroup);
gearboxGroups.put(bike.getType(), gearboxGroup);
for (int index = 0; index < bike.getGearbox().getRatios().length; index++) {
final String key = BikesCfg.buildPropertyKey(bike.getType(), Gearbox.class, index);
final Integer defaultValue = gui.getDefaultProperties().get(key);
final Label label = new Label(gearboxGroup, SWT.NULL);
GridDataFactory.swtDefaults().applyTo(label);
final String labelTextKey = "lbl.gear";
final String labelTextArgument = index != 0 ? String.valueOf(index) : "N";
label.setText(Messages.get(labelTextKey, labelTextArgument));
label.setData(LabelDataKey.KEY.toString(), labelTextKey);
label.setData(LabelDataKey.ARGUMENT.toString(), labelTextArgument);
label.setToolTipText(key);
final Text text = new Text(gearboxGroup, SWT.BORDER);
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, true).applyTo(text);
final int textSize = Integer.toString(Gearbox.MAX_VALUE).length();
text.setData(TextDataKey.DEFAULT.toString(), defaultValue);
text.setData(TextDataKey.KEY.toString(), key);
text.setData(TextDataKey.SIZE.toString(), textSize);
text.setData(TextDataKey.MAX.toString(), Gearbox.MAX_VALUE);
textFormatter.setSampleNumber(text);
text.addKeyListener(propertyKeyListener);
text.addFocusListener(propertyFocusListener);
text.addVerifyListener(propertyVerifyListener);
formProperties.put(key, new FormProperty(label, text));
}
// Torque
final Group torqueGroup = new Group(tabComposite, SWT.NULL);
torqueGroup.setText(Messages.get("lbl.torque"));
GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(torqueGroup);
GridLayoutFactory.swtDefaults().numColumns(18).applyTo(torqueGroup);
torqueGroups.put(bike.getType(), torqueGroup);
for (int index = 0; index < bike.getTorque().getCurve().length; index++) {
final String key = BikesCfg.buildPropertyKey(bike.getType(), Torque.class, index);
final Integer defaultValue = gui.getDefaultProperties().get(key);
final Label label = new Label(torqueGroup, SWT.NULL);
GridDataFactory.swtDefaults().align(SWT.TRAIL, SWT.CENTER).applyTo(label);
final String labelTextKey = "lbl.rpm";
final String labelTextArgument = String.valueOf(Torque.getRpm(index));
label.setText(Messages.get(labelTextKey, labelTextArgument));
label.setData(LabelDataKey.KEY.toString(), labelTextKey);
label.setData(LabelDataKey.ARGUMENT.toString(), labelTextArgument);
label.setToolTipText(key);
final Text text = new Text(torqueGroup, SWT.BORDER);
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, true).applyTo(text);
final int textSize = Integer.toString(Torque.MAX_VALUE).length();
text.setData(TextDataKey.DEFAULT.toString(), defaultValue);
text.setData(TextDataKey.KEY.toString(), key);
text.setData(TextDataKey.GRAPH.toString(), graph);
text.setData(TextDataKey.INDEX.toString(), index);
text.setData(TextDataKey.SIZE.toString(), textSize);
text.setData(TextDataKey.MAX.toString(), Integer.valueOf(Torque.MAX_VALUE));
textFormatter.setSampleNumber(text);
text.addKeyListener(propertyKeyListener);
text.addFocusListener(torquePropertyFocusListener);
text.addVerifyListener(propertyVerifyListener);
formProperties.put(key, new FormProperty(label, text));
}
tabScrolledComposite.setContent(tabComposite);
tabScrolledComposite.setExpandVertical(true);
tabScrolledComposite.setExpandHorizontal(true);
tabScrolledComposite.setMinSize(tabComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
tabItem.setControl(outerComposite);
}
}
public void updateTexts() {
for (final Group settingsGroup : settingsGroups.values()) {
settingsGroup.setText(Messages.get("lbl.settings"));
}
for (final Group gearboxGroup : gearboxGroups.values()) {
gearboxGroup.setText(Messages.get("lbl.gearbox"));
}
for (final Group torqueGroup : torqueGroups.values()) {
torqueGroup.setText(Messages.get("lbl.torque"));
}
for (final TorqueGraph torqueGraph : torqueGraphs.values()) {
torqueGraph.updateTexts();
}
// Update form fields...
disableTextListeners();
for (final FormProperty formProperty : formProperties.values()) {
final Label label = formProperty.getLabel();
final String updatedLabelText = Messages.get((String) label.getData(LabelDataKey.KEY.toString()), label.getData(LabelDataKey.ARGUMENT.toString()));
if (!label.getText().equals(updatedLabelText)) {
label.setText(updatedLabelText);
}
formProperty.backup();
final Text text = formProperty.getText();
text.setVisible(false);
textFormatter.setSampleNumber(text);
}
gui.getShell().layout(true, true);
for (final FormProperty formProperty : formProperties.values()) {
formProperty.restore();
}
enableTextListeners();
}
public void updateFormValues() {
final Map<String, Integer> properties = new BikesCfg(gui.getBikesInf()).getMap();
// Consistency check...
if (properties.size() != formProperties.size()) {
throw new IllegalStateException(Messages.get("err.properties.number"));
}
// Update screen values...
disableTextListeners();
updateFields(properties);
enableTextListeners();
// Update torque graphs...
for (final Bike bike : gui.getBikesInf().getBikes()) {
final TorqueGraph graph = torqueGraphs.get(bike.getType());
for (short i = 0; i < bike.getTorque().getCurve().length; i++) {
graph.getValues()[i] = bike.getTorque().getCurve()[i];
}
graph.refresh();
}
}
private void updateFields(final Map<String, Integer> properties) {
for (final Entry<String, FormProperty> entry : formProperties.entrySet()) {
if (!properties.containsKey(entry.getKey())) {
throw new IllegalStateException(Messages.get("err.property.missing", entry.getKey()));
}
final Text field = entry.getValue().getText();
// Update field max length...
final int textLimit;
if (gui.isSettingsProperty(entry.getKey())) {
textLimit = Integer.toString(Settings.MAX_VALUE, gui.getNumeralSystem().getRadix()).length();
}
else if (gui.isGearboxProperty(entry.getKey())) {
textLimit = Integer.toString(Gearbox.MAX_VALUE, gui.getNumeralSystem().getRadix()).length();
}
else if (gui.isTorqueProperty(entry.getKey())) {
textLimit = Integer.toString(Torque.MAX_VALUE, gui.getNumeralSystem().getRadix()).length();
}
else {
throw new IllegalStateException(Messages.get("err.unsupported.property", entry.getKey(), entry.getValue().getValue()));
}
if (field.getTextLimit() != textLimit) {
field.setTextLimit(textLimit);
}
// Update field value...
final String text = Integer.toString(properties.get(entry.getKey()), gui.getNumeralSystem().getRadix()).toUpperCase();
if (!field.getText().equals(text)) {
field.setText(text);
}
// Update tooltip text...
final String toolTipText = Messages.get("msg.tooltip.default", Integer.toString((Integer) field.getData(FormProperty.TextDataKey.DEFAULT.toString()), gui.getNumeralSystem().getRadix()).toUpperCase());
if (field.getToolTipText() == null || !field.getToolTipText().equals(toolTipText)) {
field.setToolTipText(toolTipText);
}
// Update font style...
textFormatter.updateFontStyle(field);
}
}
private void enableTextListeners() {
propertyKeyListener.setEnabled(true);
propertyVerifyListener.setEnabled(true);
propertyFocusListener.setEnabled(true);
torquePropertyFocusListener.setEnabled(true);
}
private void disableTextListeners() {
propertyKeyListener.setEnabled(false);
propertyVerifyListener.setEnabled(false);
propertyFocusListener.setEnabled(false);
torquePropertyFocusListener.setEnabled(false);
}
public TabFolder getTabFolder() {
return tabFolder;
}
public TextFormatter getTextFormatter() {
return textFormatter;
}
public Map<String, FormProperty> getFormProperties() {
return Collections.unmodifiableMap(formProperties);
}
public Map<BikeType, TorqueGraph> getTorqueGraphs() {
return Collections.unmodifiableMap(torqueGraphs);
}
public Map<BikeType, Group> getSettingsGroups() {
return Collections.unmodifiableMap(settingsGroups);
}
public Map<BikeType, Group> getGearboxGroups() {
return Collections.unmodifiableMap(gearboxGroups);
}
public Map<BikeType, Group> getTorqueGroups() {
return Collections.unmodifiableMap(torqueGroups);
}
}