/*
 * Copyright (C) 1999-2006 <a href="mailto:paschke@in.tum.de">Adrian Paschke</a>
 * 
 * The ECA Interpreter is part of the Rule Based Service Level Agreement (RBSLA)
 * framework, available at 
 * <a href=" http://ibis.in.tum.de/staff/paschke/rbsla/index.htm">RBSLA</a>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package rbsla.wrapper;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.mandarax.kernel.InferenceException;
import org.mandarax.kernel.ResultSet;
import org.mandarax.kernel.VariableTerm;

import rbsla.eca.ActiveRule;
import rbsla.eca.ProvaAction;
import rbsla.eca.ProvaCondition;
import rbsla.eca.ProvaEvent;
import rbsla.eca.ProvaTime;
import rbsla.utils.ConsoleWriter;
import ws.prova.Communicator;
import ws.prova.reference.ProvaResultSetImpl2;
import ws.prova.reference.VariableTermImpl;

/**
 * Wrappes the prova system like a fassade pattern.
 * This is used to easyly adopt new versions of prova.
 * Later it may a first step to implement a manadarax wrapper.
 * 
 * @author <A HREF="mailto:paschke@in.tum.de">Adrian Paschke</A>
 * @version 0.1 <1 Sept 2005>
 * @since 0.1
 */
public class ProvaWrapper implements KnowledgeBaseWrapper
{

    private Communicator comm;
	private PrintWriter writer = new ConsoleWriter(System.out);	
	private boolean console = true; // show console


		
	
	 public ProvaWrapper(String provaFile) {
		 	// Create an in-thread Communicator that will exit the message loop
	        // immediately to make synchronous queries possible
		 
		 	 		 	
		 comm = new Communicator("prova", null, "./ContractLog/empty.prova", -1,
	                Communicator.ASYNC);	
		 
			try
            {
                String query = ":-eval(consult(\'" + provaFile + "\')).";
				comm.setPrintWriter(writer);
                comm.consultSync(query,"", new Object[] {});				
            } catch (Exception e)
            {
                System.err.println("Exception Raised during loading libraries (ProvaWrapper): "
                        + provaFile);
            }
	 }

    public ProvaWrapper(String[] provaFile)
    {
        
        // Create an in-thread Communicator that will exit the message loop
        // immediately
        // to make synchronous queries possible
        comm = new Communicator("prova", null, "./ContractLog/empty.prova", -1,
                Communicator.ASYNC);

        for (int i = 0; i < provaFile.length; i++)
        {
            try
            {
                String query = ":-eval(consult(\'" + provaFile[i] + "\')).";
				comm.setPrintWriter(writer);
                comm.consultSync(query,"", new Object[] {});
				


            } catch (Exception e)
            {
                System.err.println("Exception Raised during loading libraries (ProvaWrapper): "
                        + provaFile);
            }
        }

    }

    public KnowledgeBaseWrapper createChild()
    {
		ProvaWrapper pw = new ProvaWrapper(comm);
		pw.setPrintWriter(writer);
		pw.showPrintWriter(console);		
		return (KnowledgeBaseWrapper) pw;
    }

    private ProvaWrapper(Communicator _comm)
    {
        comm = _comm;        
    }

	/**
	 * Set a new PrintWriter for console output
	 * @param _writer PrintWriter
	 */
	public void setPrintWriter(PrintWriter _writer) {
		writer = _writer;
		comm.setPrintWriter(writer);
	}

	/**
	 * Get the active PrintWriter for console output
	 */
	public PrintWriter getPrintWriter() {
		return writer;		
	}
	
	/**
	 * Print to console
	 * @param _showConsole boolean true = show / false = hide
	 */
	public void showPrintWriter(boolean _showConsole) {
		console = _showConsole;
		((ConsoleWriter)writer).showConsole(console);
	}
	
	
	/**
	 * Consult the prova knowledgebase
	 * @param input Query
	 * @result ResultSet
	 */
    public ResultSet consult(String input) {
		Object[] obj = new Object[] {};
		return consult(input,obj);
    }
	
	/**
	 * Consult the prova knowledgebase
	 * @param input query
	 * @param objects embedded objects within query 
	 * @result ResultSet
	 */
    public ResultSet consult(String input, Object[] objects) {
        try
        {		
			
			List resultSets  = comm.consultSync(":- solve(" + input + ").","", objects);
            Iterator rsit = resultSets.iterator();						
            if (rsit.hasNext())
            {				
				ResultSet rs = (ResultSet) rsit.next();				
				return rs;
            }

        } catch (Exception e)
        {
            System.err.println("Exception " + e.toString()
                    + "\r\n Raised during inference (ProvaWrapper): " + input);
			return new ProvaResultSetImpl2(); // empty result set
        } 
		return null;		
    }
	

	/**
	 * Simple test if query succeeds or fails.
	 * Without processing of variable bindings.
	 * @param query Query
	 * @result
	 */
    public boolean isTrue(String query) {
		return isTrue(query, new Object[] {});
    }
	
	/**
	 * Simple test if query succeeds or fails.
	 * Without processing of variable bindings.
	 * @param query Query
	 * @param objs embbeded objects within query
	 * @result true/false
	 */
    public boolean isTrue(String query, Object[] objs)
    {
		try
        {
			ResultSet rs = consult(query, objs);
			if (rs==null) return false;
			if (rs.first()) return true; // query succeeds
			else return false;
        
        } catch (InferenceException ie)
        {
            System.err.println("Exception " + ie.toString()
                    + " Raised during inference (ProvaWrapper): " + query);
            return false;
        }
			
    }
	
	
    /**
     * Returns all results for the specified variable. If no match the result is null.
     * @param query query
     * @param var variable name
     * @result List
     */
    public List solveVar(String query, String var)
    {
      try
        {
		  
        // perpare result list structur
        ResultSet rs = consult(query);
		
		List list = new ArrayList();
		
		if (rs==null) return null;
		boolean more = rs.first();
		if (!more) return null; // query fails
		while (more)
	    {
			Object value = rs.getResult(Object.class, var); //variable binding			
			if (value != null) list.add(value); // add value to list
			more = rs.next();
	    }
		
		if (list.isEmpty()) return null; else return list;

      } catch (InferenceException ie)
      {
            System.err.println("Exception " + ie.toString()
                    + " Raised during inference (ProvaWrapper): " + query);
            return null;
      }	
           
    }


	   public ResultSet modKB(String input) 
	    {
	    	Object[] objects = new Object[] {};
	        try
	        {		
				
				List resultSets  = comm.consultSync(":- eval(" + input + ").","", objects);
	            Iterator rsit = resultSets.iterator();			

	            if (rsit.hasNext())
	            {
					ResultSet rs = (ResultSet) rsit.next();			
					return rs;
	            }

	        } catch (Exception e)
	        {
	            System.err.println("Exception " + e.toString()
	                    + "\r\n Raised during inference (ProvaWrapper): " + input);
				return new ProvaResultSetImpl2(); // empty result set
	        } 
			return null;		
	    }
 

 

   
   public String getResultStrings(String query)
   {
       String resultStr = "\n";

       /*
        * consult the query from prova interface
        */
		try
		{		
			ResultSet rs = consult(query);
			
			if (rs==null) return "\nfalse\n";
			boolean more = rs.first();
			if (!rs.first()) return "\nfalse\n"; // query fails
			
			int ecaCounter = 1;						
			while (more)
		    {
				List vars = rs.getQueryVariables(); // get all variable names
				if (vars.isEmpty()) return "\ntrue\n"; // query succeeds, but no variable bindings
				
				// process variable bindings
				for (int i=0;i<vars.size();i++)
				{
					Object tVar = vars.get(i);
					if(tVar instanceof String)
					{
						String tmpVar = (String)tVar; // variable name
						resultStr = resultStr + "\n"+tmpVar+" = " + rs.getResult(Object.class, tmpVar) + "\n";
					}
					else if (tVar instanceof VariableTerm)
					{
						ActiveRule rule = new ActiveRule(
								(ecaCounter+1) + "||||",
								new ProvaTime(rs.getResult(Object.class, "TIME")),
								new ProvaEvent(rs.getResult(Object.class, "EVENT")),
								new ProvaCondition(rs.getResult(Object.class, "CONDITION")),
								new ProvaAction(rs.getResult(Object.class, "ACTION")),
								new ProvaCondition(rs.getResult(Object.class, "POSTCONDITION")),
								new ProvaAction(rs.getResult(Object.class, "ELSE")));
						resultStr += rule.toString() + "\n";
						ecaCounter++;
						break;
					}
				}
				
				more = rs.next();
		    }

			        
       } catch (InferenceException ie)
       {
           System.err.println("Exception " + ie.toString()
                   + " Raised during inference (ProvaWrapper): " + query);
           return "\nfalse\n";
       }		
		
		return resultStr;
       
   }
  
  public String getResultString(String query)
  {
	   String resultStr = "";
	   
	   try
	   {		
		   ResultSet rs = consult(query);
		
		   if (rs==null) return "\nfalse\n";
		   boolean more = rs.first();
		   if (!rs.first()) return "\nfalse\n"; // query fails
		   while(more)
		   {
			   List vars = rs.getQueryVariables(); // get all variable names
			   for (int i=0;i<vars.size();i++)
			   {
				   Object tVar = vars.get(i);
				   if(tVar instanceof VariableTerm)
				   {
					   VariableTermImpl tmpVar = (VariableTermImpl)tVar;
					   resultStr = resultStr + "\n"+tmpVar+" = " + rs.getResult(tmpVar) + "\n";
				   }
			   }
			   
			   more = rs.next();
		   }
	   }
	   catch (InferenceException ie)
      {
	   		System.err.println("Exception " + ie.toString()
                  + " Raised during inference (ProvaWrapper): " + query);
          return "\nfalse\n";
      }	
	   return  resultStr;
	   
  }
   
    private static Logger logger = Logger.getLogger(ProvaWrapper.class);


}

