content: /*
   *    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 2 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, write to the Free Software
   *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
  
  /*
   *    FieldMetaInfo.java
   *    Copyright (C) 2008 University of Waikato, Hamilton, New Zealand
   *
   */
  
  package weka.core.pmml;
  
  import java.io.Serializable;
  import org.w3c.dom.Element;
  
  import weka.core.Attribute;
  
  /**
   * Abstract superclass for various types of field meta
   * data.
   * 
   * @author Mark Hall (mhall{[at]}pentaho{[dot]}com
   * @version $Revision 1.0 $
   */
  public abstract class FieldMetaInfo implements Serializable {
  
    /**
     * Inner class for Values
     */
    public static class Value implements Serializable {
      
      /**
       * For serialization
       */
      private static final long serialVersionUID = -3981030320273649739L;
  
      /** The value */
      protected String m_value;
      
      /** 
       * The display value (might hold a human readable value - e.g.
       * product name instead of cryptic code).
       */
      protected String m_displayValue;
      
      /**
       * Enumerated type for the property. A value
       * can be valid, invalid or indicate a value
       * that should be considered as "missing".
       */
      public enum Property {
        VALID ("valid"),
        INVALID ("invalid"),
        MISSING ("missing");
        
        private final String m_stringVal;
        
        Property(String name) {
          m_stringVal = name;
        }
        
        public String toString() {
          return m_stringVal;
        }
      }
      protected Property m_property = Property.VALID;
      
      /**
       * Construct a value.
       * 
       * @param value the Element containing the value
       * @throws Exception if there is a problem constucting the value
       */
      protected Value(Element value) throws Exception {
        m_value = value.getAttribute("value");
        String displayV = value.getAttribute("displayValue");
        if (displayV != null && displayV.length() > 0) {
          m_displayValue = displayV;
        }
        String property = value.getAttribute("property");
        if (property != null && property.length() > 0) {
          for (Property p: Property.values()) {
            if (p.toString().equals(property)) {
              m_property = p;
              break;
            }
          }
        }
      }
      
      public String toString() {
        String retV = m_value;
        if (m_displayValue != null) {
          retV += "(" + m_displayValue + "): " + m_property.toString();
        }
        return retV;
      }
      
      public String getValue() {
        return m_value;
      }
      
      public String getDisplayValue() {
        return m_displayValue;
      }
      
      public Property getProperty() {
        return m_property;
      }
    }
    
    /**
     * Inner class for an Interval.
     */
    public static class Interval implements Serializable {
      
      /**
       * For serialization
       */
      private static final long serialVersionUID = -7339790632684638012L;
  
      /** The left boundary value */
      protected double m_leftMargin = Double.NEGATIVE_INFINITY;
      
      /** The right boundary value */
      protected double m_rightMargin = Double.POSITIVE_INFINITY;
      
      /**
       * Enumerated type for the closure.
       */
      public enum Closure {
        OPENCLOSED ("openClosed", "(", "]"),
        OPENOPEN ("openOpen", "(", ")"),
        CLOSEDOPEN ("closedOpen", "[", ")"),
        CLOSEDCLOSED ("closedClosed", "[", "]");
        
        private final String m_stringVal;
        private final String m_left;
        private final String m_right;
        
        Closure(String name, String left, String right) {
          m_stringVal = name;
          m_left = left;
          m_right = right;
        }
        
        public String toString() {
          return m_stringVal;
        }
        
        public String toString(double leftMargin, double rightMargin) {
          return m_left + leftMargin + "-" + rightMargin + m_right;
        }
      }
      protected Closure m_closure = Closure.OPENOPEN;
      
      /**
       * Construct an interval.
       * 
       * @param interval the Element containing the interval
       * @throws Exception if there is a problem constructing the interval
       */
      protected Interval(Element interval) throws Exception {
        String leftM = interval.getAttribute("leftMargin");
        try {
          m_leftMargin = Double.parseDouble(leftM);
        } catch (IllegalArgumentException ex) {
          throw new Exception("[Interval] Can't parse left margin as a number");
        }
        
        String rightM = interval.getAttribute("rightMargin");
        try {
          m_rightMargin = Double.parseDouble(rightM);
        } catch (IllegalArgumentException ex) {
          throw new Exception("[Interval] Can't parse right margin as a number");
        }
        
        String closure = interval.getAttribute("closure");
        if (closure == null || closure.length() == 0) {
          throw new Exception("[Interval] No closure specified!");
        }
        for (Closure c : Closure.values()) {
          if (c.toString().equals(closure)) {
            m_closure = c;
            break;
          }
        }
      }
      
      /**
       * Returns true if this interval contains the supplied value.
       * 
       * @param value the value to check
       * @return true if the interval contains the supplied value
       */
      public boolean containsValue(double value) {
        boolean result = false;
        
        switch (m_closure) {
        case OPENCLOSED:
          if (value > m_leftMargin && value <= m_rightMargin) {
            result = true;
          }
          break;
        case OPENOPEN:
          if (value > m_leftMargin && value < m_rightMargin) {
            result = true;
          }
          break;
        case CLOSEDOPEN:
          if (value >= m_leftMargin && value < m_rightMargin) {
            result = true;
          }
          break;
        case CLOSEDCLOSED:
          if (value >= m_leftMargin && value <= m_rightMargin) {
            result = true;
          }
          break;
        default:
          result = false;
          break;
        }
          
        return result;
      }
      
      public String toString() {
        return m_closure.toString(m_leftMargin, m_rightMargin);
      }
    }
  
    // -----------------------------
    
  
    /** the name of the field */
    protected String m_fieldName;
  
    /**
     * Enumerated type for the Optype
     */
    public enum Optype {
      NONE ("none"), 
      CONTINUOUS ("continuous"), 
      CATEGORICAL ("categorical"),
      ORDINAL ("ordinal");
    
      private final String m_stringVal;
      
      Optype(String name) {
        m_stringVal = name;
      }
    
      public String toString() {
        return m_stringVal;
      }
    }
  
    /** The optype for the target */
    protected Optype m_optype = Optype.NONE;
    
    /**
     * Get the optype.
     * 
     * @return the optype
     */
    public Optype getOptype() {
      return m_optype;
    }
    
    /**
     * Get the name of this field.
     * 
     * @return the name of this field
     */
    public String getFieldName() {
      return m_fieldName;
    }
    
    /**
     * Construct a new FieldMetaInfo.
     * 
     * @param field the Element containing the field
     */
    public FieldMetaInfo(Element field) {
      m_fieldName = field.getAttribute("name");
      
      String opType = field.getAttribute("optype");
      if (opType != null && opType.length() > 0) {
        for (Optype o : Optype.values()) {
          if (o.toString().equals(opType)) {
            m_optype = o;
            break;
          }
        }
      }
    }
    
    /**
     * Return this field as an Attribute.
     * 
     * @return an Attribute for this field.
     */
    public abstract Attribute getFieldAsAttribute();
  }
  