gt: 					return (valueBoolean == null ? false : valueBoolean);
context: /**
   * The contents of this file are subject to the OpenMRS Public License
   * Version 1.0 (the "License"); you may not use this file except in
   * compliance with the License. You may obtain a copy of the License at
   * http://license.openmrs.org
   *
   * Software distributed under the License is distributed on an "AS IS"
   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
   * License for the specific language governing rights and limitations
   * under the License.
   *
   * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
   */
  package org.openmrs.logic.result;
  
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.List;
  
  import org.openmrs.Concept;
  import org.openmrs.ConceptDatatype;
  import org.openmrs.Obs;
  import org.openmrs.api.context.Context;
  import org.openmrs.logic.LogicException;
  
  /**
   * A result from the logic service. A result can be 0-to-n date-values pairs. You can treat the
   * result as a list or easily coerce it into a simple value as needed. <br/>
   * <br/>
   * When possible, results carry references to more complex objects so that code that deals with
   * results and has some prior knowledge of the objects returned by a particular rule can more easily
   * get to the full-featured objects instead of the simplified values in the date-value pairs.<br/>
   * <br/>
   * TODO: eliminate unnecessary methods (toDatetime(), getDatetime(), and getDate() should all do the
   * same thing)<br/>
   * TODO: better support/handling of NULL_RESULT
   */
  public class Result extends ArrayList<Result> {
  	
  	private static final long serialVersionUID = -5587574403423820797L;
  	
  	/**
  	 * Core datatypes for a result. Each result is one of these datatypes, but can be easily coerced
  	 * into the other datatypes. To promote flexibility and maximize re-usability of logic rules,
  	 * the value of a result can be controlled individually for each datatype &mdash; i.e., specfic
  	 * datatype representations of a single result can be overridden. For example, a result could
  	 * have a <em>numeric</em> value of 0.15 and its text value could be overridden to be
  	 * "15 percent" or "Fifteen percent."
  	 */
  	public enum Datatype {
  		/**
  		 * Represents a true/false type of result
  		 */
  		BOOLEAN,
  		/**
  		 * Represents a Concept type of result
  		 */
  		CODED,
  		/**
  		 * Represents a date type of result
  		 */
  		DATETIME,
  		/**
  		 * Represents number (float, double, int) type of results
  		 */
  		NUMERIC,
  		/**
  		 * Represents string type of results
  		 */
  		TEXT
  	}
  	
  	private Datatype datatype;
  	
  	private Date resultDatetime;
  	
  	private Boolean valueBoolean;
  	
  	private Concept valueCoded;
  	
  	private Date valueDatetime;
  	
  	private Double valueNumeric;
  	
  	private String valueText;
  	
  	private Object resultObject;
  	
  	private static final Result emptyResult = new EmptyResult();
  	
  	public Result() {
  	}
  	
  	/**
  	 * Builds result upon another result &mdash; the first step in create a result that contains a
  	 * list of other results.
  	 * 
  	 * @param result the result that will be the sole member of the new result
  	 * @should not fail with null result
  	 */
  	public Result(Result result) {
  		if (result != null) {
  			this.add(result);
  		}
  	}
  	
  	/**
  	 * Builds a result from a list of results
  	 * 
  	 * @param list a list of results
  	 * @should not fail with null list
  	 * @should not fail with empty list
  	 */
  	public Result(List<Result> list) {
  		if (!(list == null || list.size() < 1))
  			this.addAll(list);
  	}
  	
  	/**
  	 * Builds a boolean result with a result date of today
  	 * 
  	 * @param valueBoolean
  	 */
  	public Result(Boolean valueBoolean) {
  		this(new Date(), valueBoolean, null);
  	}
  	
  	/**
  	 * Builds a boolean result with a specific result date
  	 * 
  	 * @param resultDate
  	 * @param valueBoolean
  	 */
  	public Result(Date resultDate, Boolean valueBoolean, Object obj) {
  		this(resultDate, Datatype.BOOLEAN, valueBoolean, null, null, null, null, obj);
  	}
  	
  	/**
  	 * Builds a coded result with a result date of today
  	 * 
  	 * @param valueCoded
  	 */
  	public Result(Concept valueCoded) {
  		this(new Date(), valueCoded, null);
  	}
  	
  	/**
  	 * Builds a coded result with a specific result date
  	 * 
  	 * @param resultDate
  	 * @param valueCoded
  	 */
  	public Result(Date resultDate, Concept valueCoded, Object obj) {
  		this(resultDate, Datatype.CODED, null, valueCoded, null, null, null, obj);
  	}
  	
  	/**
  	 * Builds a coded result from an observation
  	 * 
  	 * @param obs
  	 */
  	public Result(Obs obs) {
  		this(obs.getObsDatetime(), null, obs.getValueAsBoolean(), obs.getValueCoded(), obs.getValueDatetime(), obs
  		        .getValueNumeric(), obs.getValueText(), obs);
  		
  		Concept concept = obs.getConcept();
  		ConceptDatatype conceptDatatype = null;
  		
  		if (concept != null) {
  			conceptDatatype = concept.getDatatype();
  			
  			if (conceptDatatype == null) {
  				return;
  			}
  			if (conceptDatatype.isCoded())
  				this.datatype = Datatype.CODED;
  			else if (conceptDatatype.isNumeric())
  				this.datatype = Datatype.NUMERIC;
  			else if (conceptDatatype.isDate())
  				this.datatype = Datatype.DATETIME;
  			else if (conceptDatatype.isText())
  				this.datatype = Datatype.TEXT;
  			else if (conceptDatatype.isBoolean())
  				this.datatype = Datatype.BOOLEAN;
  		}
  	}
  	
  	/**
  	 * Builds a datetime result with a result date of today
  	 * 
  	 * @param valueDatetime
  	 */
  	public Result(Date valueDatetime) {
  		this(new Date(), valueDatetime, null);
  	}
  	
  	/**
  	 * Builds a datetime result with a specific result date
  	 * 
  	 * @param resultDate
  	 * @param valueDatetime
  	 */
  	public Result(Date resultDate, Date valueDatetime, Object obj) {
  		this(resultDate, Datatype.DATETIME, null, null, valueDatetime, null, null, obj);
  	}
  	
  	/**
  	 * Builds a numeric result with a result date of today
  	 * 
  	 * @param valueNumeric
  	 */
  	public Result(Double valueNumeric) {
  		this(new Date(), valueNumeric, null);
  	}
  	
  	/**
  	 * Builds a numeric result with a specific result date
  	 * 
  	 * @param resultDate
  	 * @param valueNumeric
  	 */
  	public Result(Date resultDate, Double valueNumeric, Object obj) {
  		this(resultDate, Datatype.NUMERIC, null, null, null, valueNumeric, null, obj);
  	}
  	
  	/**
  	 * Builds a numeric result with a result date of today
  	 * 
  	 * @param valueNumeric
  	 */
  	public Result(Integer valueNumeric) {
  		this(new Date(), valueNumeric, null);
  	}
  	
  	/**
  	 * Builds a numeric result with a specific result date
  	 * 
  	 * @param resultDate
  	 * @param valueNumeric
  	 */
  	public Result(Date resultDate, Integer valueNumeric, Object obj) {
  		this(resultDate, Datatype.NUMERIC, null, null, null, valueNumeric.doubleValue(), null, obj);
  	}
  	
  	/**
  	 * Builds a text result with a result date of today
  	 * 
  	 * @param valueText
  	 */
  	public Result(String valueText) {
  		this(new Date(), valueText, null);
  	}
  	
  	/**
  	 * Builds a text result with a specific result date
  	 * 
  	 * @param resultDate
  	 * @param valueText
  	 */
  	public Result(Date resultDate, String valueText, Object obj) {
  		this(resultDate, Datatype.TEXT, null, null, null, null, valueText, obj);
  	}
  	
  	/**
  	 * Builds a result date with specific (overloaded) values &mdash; i.e., instead of simply
  	 * accepting the default translation of one datatype into another (e.g., a date translated
  	 * automatically into string format), this contructor allows the various datatype
  	 * representations of the result to be individually controlled. Any values set to <em>null</em>
  	 * will yield the natural translation of the default datatype. For example,
  	 * 
  	 * <pre>
  	 * Result result = new Result(new Date(), 2.5);
  	 * assertEqualtes(&quot;2.5&quot;, result.toString());
  	 * 
  	 * Result result = new Result(new Date(),
  	 *                            Result.Datatype.NUMERIC,
  	 *                            2.5,
  	 *                            null,
  	 *                            null,
  	 *                            &quot;Two and a half&quot;,
  	 *                            null);
  	 * assertEquals(&quot;Two and a half&quot;, result.toString());
  	 * </pre>
  	 * 
  	 * @param resultDate
  	 * @param datatype
  	 * @param valueBoolean
  	 * @param valueCoded
  	 * @param valueDatetime
  	 * @param valueNumeric
  	 * @param valueText
  	 * @param object
  	 */
  	public Result(Date resultDate, Datatype datatype, Boolean valueBoolean, Concept valueCoded, Date valueDatetime,
  	    Double valueNumeric, String valueText, Object object) {
  		this.resultDatetime = resultDate;
  		this.valueNumeric = valueNumeric;
  		this.valueDatetime = valueDatetime;
  		this.valueCoded = valueCoded;
  		this.valueText = valueText;
  		this.valueBoolean = valueBoolean;
  		this.datatype = datatype;
  		this.resultObject = object;
  	}
  	
  	@Deprecated
  	public static final Result nullResult() {
  		return emptyResult;
  	}
  	
  	/**
  	 * @return null/empty result
  	 */
  	public static final Result emptyResult() {
  		return emptyResult;
  	}
  	
  	/**
  	 * Returns the datatype of the result. If the result is a list of other results, then the
  	 * datatype of the first element is returned
  	 * 
  	 * @return datatype of the result
  	 */
  	public Datatype getDatatype() {
  		if (isSingleResult())
  			return this.datatype;
  		// TODO: better option than defaulting to first element's datatype?
  		return this.get(0).getDatatype();
  	}
  	
  	/**
  	 * Changes the result date time &mdash; not to be confused with a value that is a date. The
  	 * result date time is typically the datetime that the observation was recorded.
  	 * 
  	 * @param resultDatetime
  	 */
  	public void setResultDate(Date resultDatetime) {
  		this.resultDatetime = resultDatetime;
  	}
  	
  	/**
  	 * Changes the default datatype of the result
  	 * 
  	 * @param datatype
  	 */
  	public void setDatatype(Datatype datatype) {
  		this.datatype = datatype;
  	}
  	
  	/**
  	 * Overrides the boolean representation of ths result without changing the default datatype
  	 * 
  	 * @param valueBoolean
  	 */
  	public void setValueBoolean(Boolean valueBoolean) {
  		this.valueBoolean = valueBoolean;
  	}
  	
  	/**
  	 * Overrides the coded representation of ths result without changing the default datatype
  	 * 
  	 * @param valueCoded
  	 */
  	public void setValueCoded(Concept valueCoded) {
  		this.valueCoded = valueCoded;
  	}
  	
  	/**
  	 * Overrides the datetime representation of ths result without changing the default datatype
  	 * 
  	 * @param valueDatetime
  	 */
  	public void setValueDatetime(Date valueDatetime) {
  		this.valueDatetime = valueDatetime;
  	}
  	
  	/**
  	 * Overrides the numeric representation of ths result without changing the default datatype
  	 * 
  	 * @param valueNumeric
  	 */
  	public void setValueNumeric(Integer valueNumeric) {
  		this.valueNumeric = valueNumeric.doubleValue();
  	}
  	
  	/**
  	 * Overrides the numeric representation of ths result without changing the default datatype
  	 * 
  	 * @param valueNumeric
  	 */
  	public void setValueNumeric(Double valueNumeric) {
  		this.valueNumeric = valueNumeric;
  	}
  	
  	/**
  	 * Overrides the text representation of ths result without changing the default datatype
  	 * 
  	 * @param valueText
  	 */
  	public void setValueText(String valueText) {
  		this.valueText = valueText;
  	}
  	
  	/**
  	 * Returns the data of the result (not to be confused with a data value). For example, if a
  	 * result represents an observation like DATE STARTED ON HIV TREATMENT, the <em>result date</em>
  	 * (returned by this method) would be the date the observation was recorded while the
  	 * <em>toDatetime()</em> method would be used to get the actual answer (when the patient started
  	 * their treatment).
  	 * 
  	 * @return date of the result (usually the date the result was recorded or observed)
  	 * @see #toDatetime()
  	 */
  	public Date getResultDate() {
  		if (isSingleResult())
  			return resultDatetime;
  		return this.get(0).getResultDate();
  	}
  	
  	/**
  	 * Get the result object
  	 * 
  	 * @return the underlying result object
  	 */
  	public Object getResultObject() {
  		return this.resultObject;
  	}
  	
  	/**
  	 * Set the result object
  	 * 
  	 * @param object
  	 */
  	public void setResultObject(Object object) {
  		this.resultObject = object;
  	}
  	
  	/**
  	 * @return boolean representation of the result. For non-boolean results, this will either be
  	 *         the overridden boolean value (if specifically defined) or a boolean representation of
  	 *         the default datatype. If the result is a list, then return false only if all members
  	 *         are false
  	 *         <table>
  	 *         <th>
  	 *         <td>Datatype</td>
  	 *         <td>Returns</td></th>
  	 *         <tr>
  	 *         <td>CODED</td>
  	 *         <td>false for concept FALSE<br>
  	 *         true for all others</td>
  	 *         </tr>
  	 *         <tr>
  	 *         <td>DATETIME</td>
  	 *         <td>true for any date value<br>
  	 *         false if the date is null</td>
  	 *         </tr>
  	 *         <tr>
  	 *         <td>NUMERIC</td>
  	 *         <td>true for any non-zero number<br>
  	 *         false for zero</td>
  	 *         </tr>
  	 *         <tr>
  	 *         <td>TEXT</td>
  	 *         <td>true for any non-blank value<br>
  	 *         false if blank or null</td>
  	 *         </tr>
  	 *         </table>
  	 */
  	public Boolean toBoolean() {
  		
  		if (isSingleResult()) {
  			
  			if (datatype == null) {
  				return valueBoolean;
  			}
  			
  			switch (datatype) {
  				case BOOLEAN:
  