/*
* This file is part of INDI for Java Client.
*
* INDI for Java Client 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.
*
* INDI for Java Client 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 INDI for Java Client. If not, see
* <http://www.gnu.org/licenses/>.
*/
package laazotea.indi.client;
import java.util.ArrayList;
import java.util.List;
import laazotea.indi.ClassInstantiator;
import laazotea.indi.Constants.PropertyPermissions;
import laazotea.indi.Constants.PropertyStates;
import laazotea.indi.Constants.SwitchRules;
import laazotea.indi.Constants.SwitchStatus;
import laazotea.indi.INDIDateFormat;
import laazotea.indi.INDIException;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* A class representing a INDI Switch Property. <p> It implements a listener
* mechanism to notify changes in its Elements.
*
* @author S. Alonso (Zerjillo) [zerjioi at ugr.es]
* @version 1.36, November 18, 2013
*/
public class INDISwitchProperty extends INDIProperty {
/**
* A UI component that can be used in graphical interfaces for this Switch
* Property.
*/
private INDIPropertyListener UIComponent;
/**
* The current Rule for this Switch Property.
*/
private SwitchRules rule;
/**
* Constructs an instance of
* <code>INDISwitchProperty</code>.
* <code>INDISwitchProperty</code>s are not usually directly instantiated.
* Usually used by
* <code>INDIDevice</code>.
*
* @param xml A XML Element <code><defSwitchVector></code> describing
* the Property.
* @param device The <code>INDIDevice</code> to which this Property belongs.
* @throws IllegalArgumentException if the XML Property is not well formed
* (for example if the Elements are not well formed or if the Rule is not
* valid).
*/
protected INDISwitchProperty(Element xml, INDIDevice device) throws IllegalArgumentException {
super(xml, device);
String rul = xml.getAttribute("rule").trim();
if (rul.compareTo("OneOfMany") == 0) {
rule = SwitchRules.ONE_OF_MANY;
} else if (rul.compareTo("AtMostOne") == 0) {
rule = SwitchRules.AT_MOST_ONE;
} else if (rul.compareTo("AnyOfMany") == 0) {
rule = SwitchRules.ANY_OF_MANY;
} else {
throw new IllegalArgumentException("Illegal Rule for the Switch Property");
}
NodeList list = xml.getElementsByTagName("defSwitch");
for (int i = 0 ; i < list.getLength() ; i++) {
Element child = (Element)list.item(i);
String name = child.getAttribute("name");
INDIElement iel = getElement(name);
if (iel != null) { // It already exists
} else { // Does not exist
INDISwitchElement ite = new INDISwitchElement(child, this);
addElement(ite);
}
}
if (!checkCorrectValues()) {
if (getSelectedCount() != 0) { // Sometimes de CONFIG_PROCESS is not correct at the beginning. skip
throw new IllegalArgumentException("Illegal initial value for Switch Property");
}
setState(PropertyStates.ALERT);
}
}
@Override
protected void update(Element el) {
super.update(el, "oneSwitch");
if (!checkCorrectValues()) {
setState(PropertyStates.ALERT);
}
}
/**
* Gets the current Rule for this Switch Property
*
* @return the current Rule for this Switch Property
*/
public SwitchRules getRule() {
return rule;
}
/**
* Sets the Permission of this Property. If set to Write Only it defaults to
* Read Only (Switch properties cannot be Read Only).
*
* @param permission the new Permission for this Property.
*/
@Override
protected void setPermission(PropertyPermissions permission) {
if (permission == PropertyPermissions.WO) {
super.setPermission(PropertyPermissions.RO);
} else {
super.setPermission(permission);
}
}
/**
* Checks if the Rule of this Switch property holds.
*
* @return <code>true</code> if the values of the Elements of this Property
* comply with the Rule. <code>false</code> otherwise.
*/
private boolean checkCorrectValues() {
if (getState() == PropertyStates.OK) {
int selectedCount = getSelectedCount();
if ((rule == SwitchRules.ONE_OF_MANY) && (selectedCount != 1)) {
return false;
}
if ((rule == SwitchRules.AT_MOST_ONE) && (selectedCount > 1)) {
return false;
}
}
return true;
}
/**
* Gets the number of selected Switch Elements.
*
* @return the number of selected Elements.
*/
private int getSelectedCount() {
int selectedCount = 0;
List<INDIElement> list = getElementsAsList();
for (int i = 0 ; i < list.size() ; i++) {
INDISwitchElement el = (INDISwitchElement)list.get(i);
// System.out.println("-->" + el.getName() + el.getValue());
if (el.getValue() == SwitchStatus.ON) {
selectedCount++;
}
}
return selectedCount;
}
/**
* Gets the opening XML Element <newSwitchVector> for this Property.
*
* @return the opening XML Element <newSwitchVector> for this Property.
*/
@Override
protected String getXMLPropertyChangeInit() {
String xml = "<newSwitchVector device=\"" + getDevice().getName() + "\" name=\"" + getName() + "\" timestamp=\"" + INDIDateFormat.getCurrentTimestamp() + "\">";
return xml;
}
/**
* Gets the closing XML Element </newSwitchVector> for this Property.
*
* @return the closing XML Element </newSwitchVector> for this Property.
*/
@Override
protected String getXMLPropertyChangeEnd() {
String xml = "</newSwitchVector>";
return xml;
}
@Override
public INDIPropertyListener getDefaultUIComponent() throws INDIException {
if (UIComponent != null) {
removeINDIPropertyListener(UIComponent);
}
Object[] arguments = new Object[]{this};
String[] possibleUIClassNames;
if (getName().equals("CONNECTION")) {
possibleUIClassNames = new String[]{"laazotea.indi.client.ui.INDIConnectionPropertyPanel", "laazotea.indi.client.ui.INDIDefaultPropertyPanel", "laazotea.indi.androidui.INDIDefaultPropertyView"};
} else if (rule == SwitchRules.ONE_OF_MANY) {
possibleUIClassNames = new String[]{"laazotea.indi.client.ui.INDISwitchOneOfManyPropertyPanel", "laazotea.indi.androidui.INDIDefaultPropertyView"};
} else {
possibleUIClassNames = new String[]{"laazotea.indi.client.ui.INDIDefaultPropertyPanel", "laazotea.indi.androidui.INDIDefaultPropertyView"};
}
try {
UIComponent = (INDIPropertyListener)ClassInstantiator.instantiate(possibleUIClassNames, arguments);
} catch (ClassCastException e) {
throw new INDIException("The UI component is not a valid INDIPropertyListener. Probably a incorrect library in the classpath.");
}
addINDIPropertyListener(UIComponent);
return UIComponent;
}
/**
* Gets a particular Element of this Property by its name.
*
* @param name The name of the Element to be returned
* @return The Element of this Property with the given <code>name</code>.
* <code>null</code> if there is no Element with that <code>name</code>.
*/
@Override
public final INDISwitchElement getElement(String name) {
return (INDISwitchElement)super.getElement(name);
}
/**
* Gets the values of the Property as a String.
*
* @return A String representation of the value of the Property.
*/
@Override
public String getValuesAsString() {
String aux = "";
ArrayList<INDIElement> l = this.getElementsAsList();
int n = 0;
for (int i = 0 ; i < l.size() ; i++) {
if (l.get(i).getValue() == SwitchStatus.ON) {
if (n == 0) {
aux += l.get(i).getLabel();
n++;
} else {
aux += ", " + l.get(i).getLabel();
n++;
}
}
}
if (n > 1) {
return "[" + aux + "]";
}
return aux;
}
}