
package ve;

import java.util.*;
import java.io.IOException;

/**
 * A DecisionNetwork that is constructed from the Bayesian Interchange
 * Format (BIF).
 **/

public class DecisionNetworkFromBIF extends DecisionNetwork {

    public DecisionNetworkFromBIF(String file,int maxVariables) {
	System.out.println("Entering DecisionNetworkFromBIF");
	probFactors = new Factor[maxVariables];
	variables = new Variable[maxVariables];
	System.out.println(parseBif(file));
    }

    /** 
     * This builds a new graph based on a string generated from a .bif file. */

    public String parseBif( String file ) {
	System.out.println("Entering ParseBIF");
	String errorMessage = new String("");
	String inString = file;
	int p1 = -1;
	int p2 = file.indexOf("}\n");
	
	int lineCount = 0;
	p1 = p2;
	p2 = file.indexOf( "}\n",p1+1);


       	//try 
	    {
	    while (p2 != -1) {
		System.out.println("p1 = "+p1+"; p2 = "+p2);
		inString = file.substring(p1+1, p2).trim();
		errorMessage = parseBifLine( inString );
		
		if (errorMessage.length() > 0) {
		    System.out.println(errorMessage);
		    // throw (new Exception());
		}
		p1 = p2;
		p2 = file.indexOf("}\n",p1+1);
		if (p2 == -1) { 
		    p2 = file.indexOf("};\n", p1+1);
		    p1 = p1+1;
		}
		System.out.print(lineCount++ + "...");
	    }
	    return "OK";
	    }
//  	    catch (Exception e) {
//  		String message = "";
//  	    if (errorMessage.length() > 0) {
//  		message = "Error at line " + (lineCount + 1) + " -- " + errorMessage;
//  	    }
//  	    else {
//  		message = "Error at line " + (lineCount + 1) + " -- " + e.toString();	    catch (Exception e) {
	    //	    return message;  
    }

//  	    }
//  	    return message;  
//  	}

  /** Parses an individual "line" of a .bif file. A line is the definition of a variable or
   * a variable's conditional probability table. */
	
public String parseBifLine( String inString ) //throws IOException 
{
    String errorMessage = "";
    StringTokenizer tok = new StringTokenizer( inString );
    String doing = tok.nextToken();
    
    //parsing a variable
    if (doing.equalsIgnoreCase("variable")) {
      String nodeName = tok.nextToken();
      String blank = tok.nextToken();
      while (!blank.equals("[")) {
        blank = tok.nextToken();
      }
      String domSize = tok.nextToken();
      String[] domain = new String[ Integer.parseInt( domSize.trim() ) ];
      while (!blank.startsWith("{")) {
        blank = tok.nextToken();
      }
      int domPos=0;
      String domElement = tok.nextToken();
      while (!domElement.endsWith(";")) {
        if (domElement.endsWith(",")) {
          domElement = domElement.substring(0,domElement.indexOf(","));
        }
        domain[domPos++]=domElement;
        domElement = tok.nextToken();
      }
      variables[numVariables] = new Variable(nodeName,domain);
      stringToVar.put(nodeName,variables[numVariables]);
      numVariables++;
    }
    else if (doing.equalsIgnoreCase("probability")) {
      String blank = tok.nextToken();
      String nodeName = tok.nextToken();
      Variable curNode = (Variable) stringToVar.get( nodeName );
      if (curNode == null) {
        return "Invalid node name "+nodeName;
      }
      Variable[] parents = new Variable[numVariables];
      int numParents=0;
      int factorSize=curNode.getDomain().length;
      blank = tok.nextToken();
      if (blank.equals("|")) {
        nodeName = tok.nextToken().trim();
        while (!nodeName.equals(")")) {
          
          if (nodeName.endsWith(",")) {
            nodeName = nodeName.substring(0, nodeName.indexOf(","));
          }
          Variable parent = (Variable) stringToVar.get( nodeName );
          parents[numParents++] = parent;
	  if (parent == null) {
            return "Invalid parent: "+nodeName;
          }
          factorSize*=parent.getDomain().length;
	  nodeName = tok.nextToken().trim();
        }
      }
      double[] factorValues = new double[factorSize];
      int factorPos=0;
      if (!tok.hasMoreTokens()) return errorMessage;
      blank = tok.nextToken();
      while (!blank.startsWith("}") && tok.hasMoreTokens()) {
        blank = tok.nextToken();
        if (!blank.equals("table")) {
          while (!blank.endsWith(")")) {
            blank = tok.nextToken();
          }
        }
        String prob = "";
        while (!prob.endsWith(";") && tok.hasMoreTokens()) {
          prob = tok.nextToken();
          String toAdd = prob;
          if (prob.endsWith(",")) {
            toAdd = prob.substring(0, prob.indexOf(","));
          }
          else if (prob.endsWith(";")) {
            toAdd = prob.substring(0, prob.indexOf(";"));
          }
          factorValues[factorPos++]= Double.parseDouble(toAdd);
          //prob = tok.nextToken();
        }
       }
      Variable[] factorVars = new Variable[numParents+1];
      for (int i=0; i<numParents; i++) {
	  factorVars[i]=parents[i];
      }
      factorVars[numParents] = curNode;
      FactorCPT newFactor = new FactorCPT(factorVars,factorValues);
      if (sorted(factorVars,numParents+1)) {
	  probFactors[numProbFactors++]=newFactor;
      }
      else {
	  Variable[] vars = new Variable[numParents+1];
	  for (int i=0; i<numParents+1; i++) {
	  vars[i]=factorVars[i];
	  }
	  mysort(vars);
	  probFactors[numProbFactors++]= new FactorReorder(newFactor,vars);
      }
    }
    return errorMessage;
  }
	 
    static private boolean sorted(Variable[] varray, int size) {
	for (int i=1; i<size; i++) {
	    if (varray[i-1].getId() >= varray[i].getId()) {
		return false;
	    }
	}
	return true;
    }
}
