/**
* SPINdle (version 2.2.2)
* Copyright (C) 2009-2012 NICTA Ltd.
*
* This file is part of SPINdle project.
*
* SPINdle is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPINdle 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SPINdle. If not, see <http://www.gnu.org/licenses/>.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
*/
package spindle.core.dom;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import spindle.sys.AppFeatureConst;
import spindle.sys.Messages;
import spindle.sys.message.ErrorMessage;
/**
* DOM for representing a literal in theory.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
* @since version 1.0.0
* @version Last modified 2012.08.01
*/
public class Literal implements Comparable<Object>, Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private static final char LITERAL_NEGATION_SIGN = DomConst.Literal.LITERAL_NEGATION_SIGN;
private static final char LITERAL_SEPARATOR = DomConst.Literal.LITERAL_SEPARATOR;
private static final char PREDICATE_START = DomConst.Literal.PREDICATE_START;
private static final char PREDICATE_END = DomConst.Literal.PREDICATE_END;
private static final String DEFAULT_PREDICATE_VALUE = DomConst.Literal.DEFAULT_PREDICATE_VALUE;
private static final Comparator<Literal> DEFAULT_LITERAL_COMPARATOR = new LiteralComparator(true);
protected String name;
protected boolean isNegation;
protected Mode mode;
protected String[] predicates = null;
protected Literal[] predicates2 = null;
protected boolean[] isPredicatesGrounded = null;
protected boolean isPlaceHolder;
protected Temporal temporal = null;
public Literal(final String name) {
this(name, false, null, null, (String[]) null, false);
}
public Literal(final String name, final boolean isNegation) {
this(name, isNegation, null, null, (String[]) null, false);
}
public Literal(final String name, final boolean isNegation, final Mode mode) {
this(name, isNegation, mode, null, (String[]) null, false);
}
public Literal(final String name, final boolean isNegation, final Mode mode, final Temporal temporal, final String[] predicates,
final boolean isPlaceHolder) {
setName(name);
setNegation(isNegation);
setMode(mode);
setTemporal(temporal);
setPredicates(predicates);
setPlaceHolder(isPlaceHolder);
}
public Literal(Literal literal) {
this(literal, true);
}
protected Literal(Literal literal, boolean withTemporal) {
if (null == literal) throw new IllegalArgumentException(Messages.getErrorMessage(ErrorMessage.LITERAL_NULL_LITERAL));
setName(literal.name);
setNegation(literal.isNegation);
setMode(literal.mode);
if (withTemporal) setTemporal(literal.temporal);
setPredicates(literal.predicates);
setPlaceHolder(literal.isPlaceHolder);
}
public String getName() {
return name;
}
public void setName(final String name) {
if (null == name || "".equals(name.trim()))
throw new IllegalArgumentException(Messages.getErrorMessage(ErrorMessage.LITERAL_NAME_MISSING));
this.name = name.trim();
}
public boolean isNegation() {
return isNegation;
}
public void setNegation(final boolean isNegation) {
this.isNegation = isNegation;
}
public Mode getMode() {
return mode;
}
public void setMode(final Mode mode) {
this.mode = (mode == null) ? new Mode("", false) : mode.clone();
}
public String[] getPredicates() {
return predicates;
}
public void setPredicates(final String[] predicates) {
if (null == predicates || predicates.length < 1) {
this.predicates = new String[] { DEFAULT_PREDICATE_VALUE };
this.isPredicatesGrounded = new boolean[] { false };
} else {
this.predicates = new String[predicates.length];
this.isPredicatesGrounded = new boolean[predicates.length];
for (int i = 0; i < predicates.length; i++) {
setPredicate(i, predicates[i]);
}
// List<Literal>predicatesL=new ArrayList<Literal>();
// try{
// for (int i=0;i<predicates.length;i++){
// System.out.println(getName());
// predicatesL.add(DflTheoryParser2.extractLiteral(predicates[i]));
// }
// predicates2=new Literal[predicates.length];
// predicatesL.toArray(predicates2);
// }catch (Exception e){
// e.printStackTrace();
// }
}
}
public void setPredicate(final int loc, final String predicate) {
if (loc >= predicates.length) throw new IllegalArgumentException("index is out of boundary");
String tPredicate = (null == predicate) ? "" : predicate.trim();
if ("".equals(tPredicate)) {
predicates[loc] = DEFAULT_PREDICATE_VALUE;
isPredicatesGrounded[loc] = false;
} else {
if (Character.isUpperCase(tPredicate.charAt(0))) {
predicates[loc] = tPredicate.toUpperCase();
isPredicatesGrounded[loc] = false;
} else {
predicates[loc] = tPredicate;
isPredicatesGrounded[loc] = true;
}
}
}
public String getPredicate(final int loc) {
if (loc >= predicates.length) throw new IllegalArgumentException("index is out of boundary");
return predicates[loc];
}
public int getPredicatesSize() {
return predicates.length;
}
public boolean isPredicateGrounded(final int loc) {
if (loc >= predicates.length) throw new IllegalArgumentException("index is out of boundary");
return isPredicatesGrounded[loc];
}
public void updatePredicatesValues(Map<String, String> predicateValues) {
for (int i = 0; i < predicates.length; i++) {
if (!isPredicatesGrounded[i]) {
String value = predicateValues.get(predicates[i]);
if (null != value) setPredicate(i, value);
}
}
}
public Literal cloneWithUpdatePredicatesValues(Map<String, String> predicateValues) {
String[] newPredicates = new String[predicates.length];
for (int i = 0; i < predicates.length; i++) {
if (isPredicatesGrounded[i]) {
newPredicates[i] = predicates[i];
} else {
String value = predicateValues.get(predicates[i]);
newPredicates[i] = (null == value) ? predicates[i] : value;
}
}
return new Literal(name, isNegation, mode, temporal, newPredicates, isPlaceHolder);
}
public Temporal getTemporal() {
return temporal;
}
public void setTemporal(Temporal temporal) {
if (null == temporal || !temporal.hasTemporalInfo()) this.temporal = null;
else this.temporal = temporal.clone();
}
/**
* check if the literal contains any temporal information.
*
* @return true if there is no temporal information; and false otherwise.
*/
public boolean hasTemporalInfo() {
return null == temporal ? false : temporal.hasTemporalInfo();
}
public boolean contains(Literal literal) {
if (!equals(literal, false)) return false;
if (hasTemporalInfo()) {
if (literal.hasTemporalInfo()) return temporal.contains(literal.getTemporal());
else return false;
} else {
// the two literals are of the same
// and this literal does not contains any temporal information,
// if (literal.hasTemporalInfo())return true;
return true;
}
// if (hasTemporalInfo() && literal.hasTemporalInfo()) {
// return temporal.includes(literal.temporal);
// } else return equals(literal);// return false;
}
public boolean isPlaceHolder() {
return isPlaceHolder;
}
public void setPlaceHolder(final boolean isPlaceHolder) {
this.isPlaceHolder = isPlaceHolder;
}
public Literal clone() {
return new Literal(this);
}
/**
* check if the literal is a complement of the input literal.
*
* @return true if the literal is a complement of the input literal; false otherwise.
*/
public boolean isComplementTo(Literal literal) {
if (!this.name.equals(literal.name)) return false;
if (!this.mode.getName().equals(literal.mode.getName())) return false;
Temporal literalTemporal = literal.temporal;
if (null == temporal) {
if (null != literalTemporal) {
if (AppFeatureConst.checkConflictLiteralsWithTemporalStartOnly) {
if (Long.MIN_VALUE!=literalTemporal.getStartTime())return false;
}
//else return false;
}
} else {
if (null == literalTemporal) {
if (AppFeatureConst.checkConflictLiteralsWithTemporalStartOnly){
if (Long.MIN_VALUE!=temporal.getStartTime())return false;
}
//else return false;
} else{
if (AppFeatureConst.checkConflictLiteralsWithTemporalStartOnly) {
if (!temporal.sameStart(literalTemporal)) return false;
} else {
if (!temporal.overlap(literalTemporal)) return false;
}
}
}
if (predicates.length != literal.predicates.length) return false;
for (int i = 0; i < predicates.length; i++) {
if (!isPredicatesGrounded[i] && !literal.isPredicatesGrounded[i]) {
} else if (isPredicatesGrounded[i] && literal.isPredicatesGrounded[i]) {
if (!predicates[i].equals(literal.predicates[i])) return false;
} else {
return false;
}
}
// if (null == temporal && null != literalTemporal) return false;
// if (null != temporal) {
// if (null == literalTemporal) return false;
// // if (!temporal.sameStartTime(literal.temporal)) return false;
//
// if (AppFeatureConst.checkConflictLiteralsWithTemporalStartOnly) {
// if (!temporal.sameStartTime(literalTemporal)) return false;
// } else {
// if (!temporal.overlap(literalTemporal)) return false;
// }
// // if (!temporal.equals(literal.temporal)) return false;
// }
if (!"".equals(mode.getName()) && this.isNegation == literal.isNegation) { return mode.isComplementTo(literal.getMode()); }
return this.isNegation != literal.isNegation;
}
/**
* create a complement clone of this literal.
*
* @return a complemented clone of this literal.
*/
public Literal getComplementClone() {
Literal l = new Literal(this);
l.setNegation(!isNegation);
return l;
}
public Literal getComplementCloneWithNoTemporal() {
Literal l = new Literal(this, false);
l.setNegation(!isNegation);
return l;
}
/**
* Return a copy of literal without temporal information.
*
* @return A copy of the literal without temporal information.
*/
public Literal cloneWithNoTemporal() {
return new Literal(this, false);
}
public String getPredicateString() {
StringBuilder sb = new StringBuilder();
sb.append(PREDICATE_START);
if (predicates.length > 0) {
for (int i = 0; i < predicates.length; i++) {
if (i > 0) sb.append(LITERAL_SEPARATOR);
sb.append(predicates[i]);
}
} else {
sb.append(DEFAULT_PREDICATE_VALUE);
}
sb.append(PREDICATE_END);
return sb.toString();
}
@Override
public int compareTo(Object o) {
if (this == o) return 0;
if (!(o instanceof Literal)) return getClass().getName().compareTo(o.getClass().getName());
return DEFAULT_LITERAL_COMPARATOR.compare(this, (Literal) o);
// Literal literal = (Literal) o;
// int c = name.compareTo(literal.name);
// if (c != 0) return c;
// if (isNegation != literal.isNegation) return (this.isNegation) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
//
// // same name, negation sign
// // check mode and temporal
// c = mode.compareTo(literal.mode);
// if (c != 0) return c;
//
// if (null == temporal) {
// if (null != literal.temporal) return Integer.MIN_VALUE;
// } else {
// if (null == literal.temporal)
// return Integer.MAX_VALUE;
// else {
// c = temporal.compareTo(literal.temporal);
// if (c != 0) return c;
// }
// }
//
// // check predicates
// c=predicates.length-literal.predicates.length;
// if (c!=0)return c;
// // if (predicates.length != literal.predicates.length) return predicates.length - literal.predicates.length;
// for (int i = 0; i < predicates.length; i++) {
// if (!isPredicatesGrounded[i] && !literal.isPredicatesGrounded[i]) {
// } else if (isPredicatesGrounded[i] && literal.isPredicatesGrounded[i]) {
// c = predicates[i].compareTo(literal.predicates[i]);
// if (c != 0) return c;
// // if (!predicates[i].equals(literal.predicates[i])) return
// // predicates[i].compareTo(literal.predicates[i]);
// } else {
// return (isPredicatesGrounded[i]) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
// }
// }
// return 0;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (isNegation ? 1231 : 1237);
result = prime * result + ((mode == null) ? 0 : mode.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + Arrays.hashCode(predicates);
result = prime * result + ((temporal == null) ? 0 : temporal.hashCode());
return result;
}
private boolean equals(Literal literal, boolean checkTemporal) {
if (!name.equals(literal.name)) return false;
if (isNegation != literal.isNegation) return false;
if (!mode.equals(literal.mode)) return false;
if (checkTemporal) {
if (null == temporal) {
if (null != literal.temporal) return false;
} else if (!temporal.equals(literal.temporal)) return false;
}
if (predicates.length != literal.predicates.length) return false;
for (int i = 0; i < predicates.length; i++) {
if (!isPredicatesGrounded[i] && !literal.isPredicatesGrounded[i]) {
} else if (isPredicatesGrounded[i] && literal.isPredicatesGrounded[i]) {
if (!predicates[i].equals(literal.predicates[i])) return false;
} else {
return false;
}
}
return true;
}
public boolean equalsWithNoTemporal(Literal literal) {
return equals(literal, false);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof Literal)) return false;
return equals((Literal) o, true);
// Literal literal = (Literal) o;
// if (!name.equals(literal.name)) return false;
// if (isNegation != literal.isNegation) return false;
// if (!mode.equals(literal.mode)) return false;
// if (predicates.length != literal.predicates.length) return false;
// for (int i = 0; i < predicates.length; i++) {
// if (!isPredicatesGrounded[i] && !literal.isPredicatesGrounded[i]) {
// } else if (isPredicatesGrounded[i] && literal.isPredicatesGrounded[i]) {
// if (!predicates[i].equals(literal.predicates[i])) return false;
// } else {
// return false;
// }
// }
// if (null == temporal) {
// if (null != literal.temporal) return false;
// } else if (!temporal.equals(literal.temporal)) return false;
// return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (!"".equals(mode.getName())) sb.append(mode.toString());
if (isNegation) sb.append(LITERAL_NEGATION_SIGN);
sb.append(name);
sb.append(getPredicateString());
if (null != temporal) sb.append(temporal.toString());
if (isPlaceHolder) {
if (DomConst.Literal.IS_SHOW_PLACE_HOLDER) sb.append("[PlaceHolder]");
}
return sb.toString();
}
}