package org.drools.compiler;

/*
 * Copyright 2005 JBoss Inc
 * 
 * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.drools.ruleflow.common.core.Process;
import org.drools.ruleflow.core.Connection;
import org.drools.ruleflow.core.MilestoneNode;
import org.drools.ruleflow.core.Node;
import org.drools.ruleflow.core.RuleFlowProcess;
import org.drools.ruleflow.core.RuleFlowProcessValidationError;
import org.drools.ruleflow.core.RuleFlowProcessValidator;
import org.drools.ruleflow.core.Split;
import org.drools.ruleflow.core.impl.RuleFlowProcessImpl;
import org.drools.ruleflow.core.impl.RuleFlowProcessValidatorImpl;

import com.thoughtworks.xstream.XStream;

/**
 * A ProcessBuilder can be used to build processes based on XML files
 * containing a process definition.
 * 
 * @author <a href="mailto:kris_verlaenen@hotmail.com">Kris Verlaenen</a>
 */
public class ProcessBuilder {
    
    
	
	private PackageBuilder packageBuilder;
    private final List processes = new ArrayList();
	private final List errors = new ArrayList(); 
	
	public ProcessBuilder(PackageBuilder packageBuilder) {
		this.packageBuilder = packageBuilder;
	}

    public Process[] getProcesses() {
        return (Process[]) this.processes.toArray( new Process[this.processes.size()] );
    }
    
    public List getErrors() {
    	return errors;
    }

    public void addProcess(final Process process) {
    	if (process instanceof RuleFlowProcess) {
    		RuleFlowProcessValidator validator = RuleFlowProcessValidatorImpl.getInstance();
    		RuleFlowProcessValidationError[] errors = validator.validateProcess((RuleFlowProcess) process);
    		if (errors.length != 0) {
    			for (int i = 0; i < errors.length; i++) {
    				this.errors.add(new ParserError(errors[i].toString(), -1, -1));
    			}
    		} else {
	            this.processes.add( process );
	            // generate and add rule for process
	            String rules = generateRules( process );
	            if (rules != null && rules.length() != 0) {
	            	try {
	            		packageBuilder.addPackageFromDrl(new StringReader(rules));
	            	} catch (Throwable t) {
	            		// should never occur
	            	}
	            }
    		}
    	}
    }

    public void addProcessFromFile(final Reader reader) throws Exception {
        final XStream stream = new XStream();
        stream.setMode( XStream.ID_REFERENCES );

        
        final ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
        final ClassLoader newLoader = this.getClass().getClassLoader();
        try {
            Thread.currentThread().setContextClassLoader( newLoader );
            final RuleFlowProcess process = (RuleFlowProcess) stream.fromXML( reader );
            addProcess( process );
        } catch ( final Exception t ) {
            t.printStackTrace();
            throw t;
        } finally {
            Thread.currentThread().setContextClassLoader( oldLoader );
        }
        reader.close();
    }
    
    private String generateRules(final Process process) {
    	String result = "";
    	if (process instanceof RuleFlowProcessImpl) {
    		RuleFlowProcessImpl ruleFlow = (RuleFlowProcessImpl) process;
    		List imports = ruleFlow.getImports();
    		if (imports != null) {
    			for (Iterator iterator = imports.iterator(); iterator.hasNext(); ) {
    				result += "import " + iterator.next() + ";\n";
    			}
    		}
    		Node[] nodes = ruleFlow.getNodes();
    		for (int i = 0; i < nodes.length; i++) {
    			 if (nodes[i] instanceof Split) {
    				 Split split = (Split) nodes[i];
    				 if (split.getType() == Split.TYPE_XOR || split.getType() == Split.TYPE_OR) {
    					 for (Iterator iterator = split.getOutgoingConnections().iterator(); iterator.hasNext(); ) {
    						 Connection connection = (Connection) iterator.next();
    						 result += createSplitRule(process, connection, split.getConstraint(connection).getConstraint());
    					 }
    				 }
    			 } else if (nodes[i] instanceof MilestoneNode) {
    				 MilestoneNode milestone = (MilestoneNode) nodes[i];
    				 result += createMilestoneRule(process, milestone);
    			 }
    		}
    	}
    	return result;
    }
    
    private String createSplitRule(Process process, Connection connection, String constraint) {
		return 
    		"rule \"RuleFlow-" + process.getId() + "-"
    			+ connection.getFrom().getId() + "-" + connection.getTo().getId() + "\" \n" + 
			"      ruleflow-group \"DROOLS_SYSTEM\" \n" + 
			"    when \n" + 
			"      " + constraint + "\n" +
			"    then \n" +
			"end \n\n";
    }
    
    private String createMilestoneRule(Process process, MilestoneNode milestone) {
		return 
    		"rule \"RuleFlow-" + process.getId() + "-" + milestone.getId() + "\" \n" + 
			"      ruleflow-group \"DROOLS_SYSTEM\" \n" + 
			"    when \n" + 
			"      " + milestone.getConstraint() + "\n" +
			"    then \n" +
			"end \n\n";
    }
}

@@ -773,16 +773,39 @@
 l.List;%0D
+%0Aimport java.util.Map;%0D
 %0A%0D%0Aimpor
@@ -1606,17 +1606,8 @@
   %0D%0A
-    %0D%0A%09%0D%0A
 %09pri
@@ -4194,24 +4194,343 @@
 %7D%0D%0A    %09%09%7D%0D%0A
+    %09%09Map globals = ruleFlow.getGlobals();%0D%0A    %09%09if (globals != null) %7B%0D%0A    %09%09%09for (Iterator iterator = globals.entrySet().iterator(); iterator.hasNext(); ) %7B%0D%0A    %09%09%09%09Map.Entry entry = (Map.Entry) iterator.next();%0D%0A    %09%09%09%09result += %22global %22 + entry.getValue() + %22 %22 + entry.getKey() + %22;%5Cn%22;%0D%0A    %09%09%09%7D%0D%0A    %09%09%7D%0D%0A%0D%0A
     %09%09Node%5B%5D

Add global support in ruleflow - added support for globals in ruleflow