
//This class represents one of the general models.
//Each of these models is a node in the general model tree.
//The vector Children holds the child nodes of this model. A vector is used as we do not know how many children
//each node will have.

import java.awt.* ;
import java.util.* ;

public class Model {

   public Comentry comentry = null ;
	public static int lowestDepth ;

   //These are needed for drawing the node
   public int xpos ;
   public int ypos ;

 	public Vector Children = new Vector () ;
   public Vector Attributes ;
   public boolean pruned = false ;

   //We have two constructors
   //The root node is created using this constructor
   //so that it can display messages on the comentry object
   public Model ( Vector atts, Comentry comentry ){
    	this.Attributes = atts ;
      this.comentry = comentry ;
   }

   //The other nodes are created using this constructor
   public Model ( Vector atts ){
   	this.Attributes = atts ;
   }

   //The root node produces its children using this method
   public void firstGeneration( Sample e, Vector SpecAttributes ){
   //for each attribute
   //if the value in SpecAttributes is not equal to the value in Sample e
   //then produce a child in which the ? is replaced by the value from SpecAttributes

	   Attribute specAtt, SampleAtt  ;
	   Vector    TempChildren = new Vector();

      comentry.appendText( "This sample is negative so we must specialise the general node." +
                                      "\nNew general models are produced, by setting attribute values to those of the specific model.") ;

	   for ( int count =  0 ; count < Attributes.size() ; count ++ ){
	    	specAtt  = ( Attribute ) SpecAttributes.elementAt( count ) ;
	      SampleAtt =   e.Attributes[count] ;
// corrected by Goto and Sakurai
//	    	if ( !specAtt.value.equals( SampleAtt.value )){
		if ( (!specAtt.value.equals( SampleAtt.value )) && (!specAtt.value.equals( "?" ))){
   	      Vector Temp = new Vector () ;
      	   Temp = ( Vector ) Attributes.clone() ;
	         Attribute anAtt = new Attribute( specAtt.index, specAtt.value ) ;
   	      Temp.setElementAt( anAtt ,count ) ;
      		Model m = new Model(Temp) ;
         	TempChildren.addElement( m ) ;
    	   }
        else {
        		comentry.appendText("We do not produce a general model with, " + SampleAtt.value +", as a value as this value is contained in the " +
                        "negative sample." );
        //the general models can only become more specific so to add negative information is no good .

        }
  		}
   	Children = TempChildren ;
   }

  //Produces child nodes according to a new sample and the specific model attributes
  //This needs to return a vector of the chidren so that they can be checked for speciailisation
  //against the other leaf nodes
  public Vector produceChildren( Sample e, Vector SpecAttributes ){

	  Attribute thisAtt, specAtt, SampleAtt  ;
	  Vector    TempChildren = new Vector();

     //for each attribute
	  for ( int count =  0 ; count < Attributes.size() ; count ++ ){
   	   thisAtt  = ( Attribute ) Attributes.elementAt( count ) ;
	    	specAtt  = ( Attribute ) SpecAttributes.elementAt( count ) ;
   	   SampleAtt =   e.Attributes[count] ;

         //If this model is valueless and the specific model has a definite value and that value is
         //not equal to the value in the negative sample e.
	    	if ( (thisAtt.value.equals("?")) && (!specAtt.value.equals("?"))&&
   	   	(!specAtt.value.equals(SampleAtt.value)) ){
        		Vector Temp = new Vector () ;
	         Temp = ( Vector ) Attributes.clone() ;

            //produce a new child, replacing the valueless attribute with the definite value from the specific model.
  		      Attribute anAtt = new Attribute( specAtt.index, specAtt.value ) ;
     	      Temp.setElementAt( anAtt ,count ) ;
      		Model m = new Model(Temp) ;
				TempChildren.addElement( m ) ;
      	}
 	  }
	  Children = TempChildren ;
	  return TempChildren ;
  }

  //Enables us to find the depth of the tree and the number of nodes at each level
  //given the root node.
  public int findWidthDepth ( int currentDepth, int[] widths ){

  		widths[currentDepth] += 1 ;
      Model child ;

      if ( !Children.isEmpty ( ) ){
       	if ( currentDepth == lowestDepth ) lowestDepth += 1 ;
         for ( Enumeration en = Children.elements( ) ; en.hasMoreElements ( ) ; ){
         	child = ( Model ) en.nextElement ( ) ;
            child.findWidthDepth( currentDepth + 1 , widths ) ;
         }
      }
    return lowestDepth  ;
  }

  //Returns a string of the longest attribute value and index.
  //Needed for drawing the node.
  public String longestAttribute ( ){

      String longest = ""  ;

  		Attribute att ;
      for ( Enumeration en = Attributes.elements ( ) ; en.hasMoreElements ( ) ; ) {
      	att = ( Attribute ) en.nextElement ( ) ;
         if ( ( att.index + " : " + att.value ).length ( ) > longest.length ( ) ) longest = att.index +" : "+ att.value ;
      }
      return longest ;
  }

   //Returns the leaf nodes of the tree
   //that have not been pruned i.e. had pruned set to true
   public Vector returnLeaves( Vector leaves ){
   	if ( (Children.isEmpty( )) && (!this.pruned) ){
      	leaves.addElement( this ) ;
      }
      else{
        Model Child ;
        for( Enumeration en = Children.elements() ; en.hasMoreElements() ;){
        		Child = ( Model ) en.nextElement() ;
        		Child.returnLeaves ( leaves ) ;
        }
      }
      return leaves ;
   }


}//end class