package org.drools.compiler.integrationTests;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.definition.KiePackage;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.EntryPoint;

import com.ibm.jvm.Dump;
import com.ibm.jvm.InvalidDumpOptionException;


public class WhyTwoClassoaders {
	
	final String artifactId = "vsc-rule-engine";
	final String defaultBaseName = "defaultKBase";
	final String pkgName = "org.drools.compiler.integrationTests";
	final KieServices ks = KieServices.Factory.get();
	final KieRepository kr = ks.getRepository();
	final String pathSep = System.getProperty("file.separator");
	final String pathToRule108 = "src/main/resources/rules/1081.drl";
	final String rulePath = "src/main/resources/rules/";
	static final int numOfRuns = 1;
	static int internalRuleID = Integer.MAX_VALUE - 5000;
	final String pathToInternalRule = rulePath+internalRuleID + ".drl";
	
	int ver=0;
	String updateTo = " ";
	KieSession kSession = null;
	ReleaseId prevReleaseId = null;
	KieFileSystem kfs = null;
	KieBuilder kb = null;
	KieContainer kContainer = null;
	KiePackage testPkg = null;
	KieModuleModel defaultModuleModel = null;
	KieBaseModel defaultBaseModel = null;
	KieBase kBase = null;
	EntryPoint currStream = null;
	static int counter = 1;
    
    final static String genRulePart1 =
    		"package org.drools.compiler.integrationTests \n" +
    		"declare Entity\n" +
    		"@role(event)\n" +
    		"	end\n" +
    		"rule \""; 
    final static String genRulePart2 = "\"\n" +
    		"no-loop true\n" + 
    		"when \n" +
			" then \n" +
			"end \n";

    	
	public static void main(String[] args) {
		System.out.println("current working dir is: " + System.getProperty("user.dir"));
		WhyTwoClassoaders whyTwoCL = new WhyTwoClassoaders();
		whyTwoCL.firstBuildOfRulesAndContainer();
		whyTwoCL.done(null);
	}

	
	void makeDump(String fileName) {
		System.gc();
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e1) {
			done(e1);
		}
		String fName = "c:" + pathSep + "Users" + pathSep + "Administrator" + pathSep +"Desktop" + pathSep + fileName;
		Path pName = Paths.get(fName);
		try {
			Files.deleteIfExists(pName);
			Dump.systemDumpToFile(fName);
		} catch (IOException e) {
			done(e);
		} catch (InvalidDumpOptionException e) {
			done(e);
		}
	}
	
	
	void done(Exception e) {
		System.out.println("done...");
		if (e != null) {
			e.printStackTrace();
			System.exit(1);
		} else {
			System.exit(0);
		}
	}

	boolean firstBuildOfRulesAndContainer(){
		updateTo = "1.0." + ver++;
		prevReleaseId = ks.newReleaseId(pkgName, artifactId, updateTo);
		kfs = ks.newKieFileSystem();
		kfs.generateAndWritePomXML(prevReleaseId);
		defaultModuleModel = ks.newKieModuleModel();
		defaultBaseModel = defaultModuleModel.newKieBaseModel(defaultBaseName);
		defaultBaseModel.setEventProcessingMode(EventProcessingOption.STREAM).setDefault(true);
		defaultBaseModel.newKieSessionModel("defaultKSession").setDefault(true);
		kfs.writeKModuleXML(defaultModuleModel.toXML());

		byte[] baseRuleBytes = null;
		try {
			String ruleName = "108" + counter;
			String temp = genRulePart1 + ruleName + genRulePart2; 
			baseRuleBytes = temp.getBytes("US-ASCII");
			if (baseRuleBytes != null && baseRuleBytes.length > 0) 
				kfs.write(pathToRule108, baseRuleBytes); 
		} catch (UnsupportedEncodingException e) {
			done(e);
		};
		kb = ks.newKieBuilder(kfs);
		kb.buildAll();
		if (kb.getResults().hasMessages(org.kie.api.builder.Message.Level.ERROR)) {
			System.out.println(kb.getResults().toString());
			return false;
		}
		kContainer = ks.newKieContainer(prevReleaseId);
		makeDump("ckpoint1.dmp");
		kSession = kContainer.newKieSession();
		makeDump("ckpoint2.dmp");
		currStream = kSession.getEntryPoint( "currStream" );
		kBase = kContainer.getKieBase(defaultBaseName);

		printRules("firstBuildOfRulesAndContainer");
		return true;
	}


	void printRules(String caller) {
		kBase = kContainer.getKieBase(defaultBaseName);
		testPkg = kBase.getKiePackage(pkgName);
		int ruleCount = 0;
		System.out.println("Caller: " + caller );
		if (testPkg == null) {
			System.out.println("Rule package not found: " + pkgName);
		}
		else {
			System.out.println(testPkg.getName() + ":");
			for( Rule oneRule : testPkg.getRules()){
				System.out.println("\t" + oneRule.getName());
				++ruleCount;
			}
		}
		System.out.println("Rule count: " + ruleCount + "\n");
	}
	
}
