/*
DroidFish - An Android chess program.
Copyright (C) 2014-2016 Peter Ă–sterlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.petero.droidfish.engine;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
public class UCIOptions implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private ArrayList<String> names;
private Map<String, OptionBase> options;
public static enum Type {
CHECK,
SPIN,
COMBO,
BUTTON,
STRING
}
public abstract static class OptionBase implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
public String name;
public Type type;
public boolean visible = true;
@Override
public OptionBase clone() throws CloneNotSupportedException {
return (OptionBase)super.clone();
}
/** Return true if current value != default value. */
abstract public boolean modified();
/** Return current value as a string. */
abstract public String getStringValue();
/** Set option from string value. Return true if option was modified. */
public final boolean setFromString(String value) {
OptionBase o = this;
switch (o.type) {
case CHECK:
if (value.toLowerCase(Locale.US).equals("true"))
return ((CheckOption)o).set(true);
else if (value.toLowerCase(Locale.US).equals("false"))
return ((CheckOption)o).set(false);
return false;
case SPIN:
try {
int val = Integer.parseInt(value);
SpinOption so = (SpinOption)o;
return so.set(val);
} catch (NumberFormatException ex) {
}
return false;
case COMBO:
return ((ComboOption)o).set(value);
case BUTTON:
return false;
case STRING:
return ((StringOption)o).set(value);
}
return false;
}
}
public static final class CheckOption extends OptionBase {
private static final long serialVersionUID = 1L;
public boolean value;
public boolean defaultValue;
CheckOption(String name, boolean def) {
this.name = name;
this.type = Type.CHECK;
this.value = def;
this.defaultValue = def;
}
@Override
public boolean modified() {
return value != defaultValue;
}
@Override
public String getStringValue() {
return value ? "true" : "false";
}
public boolean set(boolean value) {
if (this.value != value) {
this.value = value;
return true;
}
return false;
}
}
public static final class SpinOption extends OptionBase {
private static final long serialVersionUID = 1L;
public int minValue;
public int maxValue;
public int value;
public int defaultValue;
SpinOption(String name, int minV, int maxV, int def) {
this.name = name;
this.type = Type.SPIN;
this.minValue = minV;
this.maxValue = maxV;
this.value = def;
this.defaultValue = def;
}
@Override
public boolean modified() {
return value != defaultValue;
}
@Override
public String getStringValue() {
return String.format(Locale.US, "%d", value);
}
public boolean set(int value) {
if ((value >= minValue) && (value <= maxValue)) {
if (this.value != value) {
this.value = value;
return true;
}
}
return false;
}
}
public static final class ComboOption extends OptionBase {
private static final long serialVersionUID = 1L;
public String[] allowedValues;
public String value;
public String defaultValue;
ComboOption(String name, String[] allowed, String def) {
this.name = name;
this.type = Type.COMBO;
this.allowedValues = allowed;
this.value = def;
this.defaultValue = def;
}
@Override
public boolean modified() {
return !value.equals(defaultValue);
}
@Override
public String getStringValue() {
return value;
}
public boolean set(String value) {
for (String allowed : allowedValues) {
if (allowed.toLowerCase(Locale.US).equals(value.toLowerCase(Locale.US))) {
if (!this.value.equals(allowed)) {
this.value = allowed;
return true;
}
break;
}
}
return false;
}
}
public static final class ButtonOption extends OptionBase {
private static final long serialVersionUID = 1L;
public boolean trigger;
ButtonOption(String name) {
this.name = name;
this.type = Type.BUTTON;
this.trigger = false;
}
@Override
public boolean modified() {
return false;
}
@Override
public String getStringValue() {
return "";
}
}
public static final class StringOption extends OptionBase {
private static final long serialVersionUID = 1L;
public String value;
public String defaultValue;
StringOption(String name, String def) {
this.name = name;
this.type = Type.STRING;
this.value = def;
this.defaultValue = def;
}
@Override
public boolean modified() {
return !value.equals(defaultValue);
}
@Override
public String getStringValue() {
return value;
}
public boolean set(String value) {
if (!this.value.equals(value)) {
this.value = value;
return true;
}
return false;
}
}
UCIOptions() {
names = new ArrayList<String>();
options = new TreeMap<String, OptionBase>();
}
@Override
public UCIOptions clone() throws CloneNotSupportedException {
UCIOptions copy = new UCIOptions();
copy.names = new ArrayList<String>();
copy.names.addAll(names);
copy.options = new TreeMap<String, OptionBase>();
for (Map.Entry<String, OptionBase> e : options.entrySet())
copy.options.put(e.getKey(), e.getValue().clone());
return copy;
}
public void clear() {
names.clear();
options.clear();
}
public boolean contains(String optName) {
return getOption(optName) != null;
}
public final String[] getOptionNames() {
return names.toArray(new String[names.size()]);
}
public final OptionBase getOption(String name) {
return options.get(name.toLowerCase(Locale.US));
}
final void addOption(OptionBase p) {
String name = p.name.toLowerCase(Locale.US);
names.add(name);
options.put(name, p);
}
}