content: package aima.core.logic.propositional.parsing.ast;
  
  /**
   * Artificial Intelligence A Modern Approach (3rd Edition): page 244.<br>
   * <br>
   * <b>Complex Sentence:</b> are constructed from simpler sentences, using
   * parentheses (and square brackets) and logical connectives.
   *
   * @author Ciaran O'Reilly
   * @author Ravi Mohan 
   */
  public class ComplexSentence extends Sentence {
  
  	private Connective connective;
  	private Sentence[] simplerSentences;
  	// Lazy initialize these values.
  	private int cachedHashCode = -1;
  	private String cachedConcreteSyntax = null;
  
  	/**
  	 * Constructor.
  	 * 
  	 * @param connective
  	 *            the complex sentence's connective.
  	 * @param sentences
  	 *            the simpler sentences making up the complex sentence.
  	 */
  	public ComplexSentence(Connective connective, Sentence... sentences) {
  		// Assertion checks
  		assertLegalArguments(connective, sentences);
  		
  		this.connective = connective;
  		simplerSentences = new Sentence[sentences.length];
  		System.arraycopy(sentences, 0, simplerSentences, 0, sentences.length);
  	}
  	
  	/**
  	 * Convenience constructor for binary sentences.
  	 * 
  	 * @param sentenceL
  	 * 			the left hand sentence.
  	 * @param binaryConnective
  	 * 			the binary connective.
  	 * @param sentenceR
  	 *  		the right hand sentence.
  	 */
  	public ComplexSentence(Sentence sentenceL, Connective binaryConnective, Sentence sentenceR) {
  		this(binaryConnective, sentenceL, sentenceR);
  	}
  
  	@Override
  	public Connective getConnective() {
  		return connective;
  	}
  
  	@Override
  	public int getNumberSimplerSentences() {
  		return simplerSentences.length;
  	}
  
  	@Override
  	public Sentence getSimplerSentence(int offset) {
  		return simplerSentences[offset];
  	}
  
  	@Override
  	public boolean equals(Object o) {
  		if (this == o) {
  			return true;
  		}
  		if ((o == null) || (this.getClass() != o.getClass())) {
  			return false;
  		}
  
  		boolean result = false;
  		ComplexSentence other = (ComplexSentence) o;
  		if (other.hashCode() == this.hashCode()) {
  			if (other.getConnective().equals(this.getConnective())
  					&& other.getNumberSimplerSentences() == this
  							.getNumberSimplerSentences()) {
  				// connective and # of simpler sentences match
  				// assume match and then test each simpler sentence
  				result = true;
  				for (int i = 0; i < this.getNumberSimplerSentences(); i++) {
  					if (!other.getSimplerSentence(i).equals(
  							this.getSimplerSentence(i))) {
  						result = false;
  						break;
  					}
  				}
  			}
  		}
  
  		return result;
  	}
  
  	@Override
  	public int hashCode() {
  		if (cachedHashCode == -1) {
  			cachedHashCode = 17 * getConnective().hashCode();
  			for (Sentence s : simplerSentences) {
  				cachedHashCode = (cachedHashCode * 37) + s.hashCode();
  			}
  		}
  
  		return cachedHashCode;
  	}
  
  	@Override
  	public String toString() {
  		if (cachedConcreteSyntax == null) {
  			if (isUnarySentence()) {
  				cachedConcreteSyntax = getConnective()
  						+ bracketSentenceIfNecessary(getConnective(), getSimplerSentence(0));
  			} else if (isBinarySentence()) {
  				cachedConcreteSyntax = bracketSentenceIfNecessary(getConnective(), getSimplerSentence(0))
  						+ " "
  						+ getConnective()
  						+ " "
  						+ bracketSentenceIfNecessary(getConnective(), getSimplerSentence(1));
  			}
  		}
  		return cachedConcreteSyntax;
  	}
  	
  	//
  	// PRIVATE
  	//
  	private void assertLegalArguments(Connective connective, Sentence...sentences) {
  		if (connective == null) {
  			throw new IllegalArgumentException("Connective must be specified.");
  		}
  		if (sentences == null) {
  			throw new IllegalArgumentException("> 0 simpler sentences must be specified.");
  		}
  		if (connective == Connective.NOT) {
  			if (sentences.length != 1) {
  				throw new IllegalArgumentException("A not (~) complex sentence only take 1 simpler sentence not "+sentences.length);
  			}
  		}
  		else {
  			if (sentences.length != 2) {
  				throw new IllegalArgumentException("Connective is binary ("+connective+") but only "+sentences.length + " simpler sentences provided");
  			}
  		}
  	}
  }