/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Build
 * IBM UrbanCode Deploy
 * IBM UrbanCode Release
 * IBM AnthillPro
 * (c) Copyright IBM Corporation 2017, 2017. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 */
import static java.lang.Integer.valueOf

import com.ibm.urbancode.zos.common.Jobs
import com.ibm.urbancode.zos.common.PublishedSoftwareServiceTemplate
import com.ibm.urbancode.zos.common.SoftwareServiceInstance
import com.urbancode.air.AirPluginTool


try{
	def apTool = new AirPluginTool(this.args[0], this.args[1])
	final def workDir = new File('.').canonicalFile
	def props = apTool.getStepProperties();
	
    final def templateName   = props['templateName']?.trim();
    final def inputProperties   = props['inputProperties']?.trim();
    final def domainName   = props['domainName']?.trim();
    final def tenantName      = props['tenantName']?.trim();
    final def userDataId     = props['userDataId']?.trim();
    final def userData     = props['userData']?.trim();
    final def accountInfo     = props['accountInfo']?.trim();
    final def systemsNicknames   = props['systemsNicknames']?.trim();

    final def waitForWorkflow = Boolean.valueOf(props['waitForWorkflow']?.trim());
	final def timeout = props['timeout']?.trim();
	final def printRESTLOG = Boolean.valueOf(props['printRESTLOG']?.trim()); //checkbox
	final def printJOBLOG = Boolean.valueOf(props['printJOBLOG']?.trim()); //checkbox
	final def outputJOBLOG = Boolean.valueOf(props['outputJOBLOG']?.trim()); //checkbox
	final def jobPrefix = props['jobPrefix']?.trim();
	final def jobOwner = props['jobOwner']?.trim();
	final def ddnameFilter = props['ddnameFilter']?.trim();
	final def cutOff = Integer.valueOf(props['cutOff']?.trim());
	jobID = ""
			
	//hidden
	final def baseurl = props['baseurl']?.trim();
	final def untrustedSSL = Boolean.valueOf(props['untrustedSSL']?.trim()); //checkbox
	final def userid = props['userid']?.trim();
	final def password = props['password']?.trim();
	int timeoutValue=0;
	
	//validate required input
	if(baseurl == null || baseurl.length()==0){
		throw new Exception("zOSMF URL must be set.");
	}

	if(userid == null || userid.length()==0){
		throw new Exception("User Name must be set.");
	}

	if(password == null || password.trim().length()==0){
		throw new Exception("Password must be set.");
	}
	try{
		timeoutValue = valueOf(timeout as String);
	}catch(NumberFormatException e){
		throw new IllegalArgumentException("Time Out isn't a number.");
	}
    
    if(templateName == null || templateName.length()==0){
        throw new Exception("Template Name must be set.");
    }
    

	def JOBS, jobsBefore, jobsAfter, jobFilterMap = [:], ddnameFilterArray;
	if(printJOBLOG || outputJOBLOG){
		//verify job related input
		if(jobPrefix) jobFilterMap << [prefix : jobPrefix]
		if(jobOwner)  jobFilterMap << [owner : jobOwner]
		if(jobID)     jobFilterMap << [jobid : jobID]
		ddnameFilterArray = ddnameFilter.split("\n");
		
		//get the job list before running workflow
		JOBS= new Jobs(baseurl, userid, password, untrustedSSL);
        JOBS.printRESTLOG = false;
		jobsBefore = JOBS.listJobs(jobFilterMap);
	}

    def template =  new PublishedSoftwareServiceTemplate(baseurl, userid,password,untrustedSSL);
    template.printRESTLOG = printRESTLOG;
    if(inputProperties) template.inputProperties = inputProperties;
    if(domainName) template.domainName = domainName;
    if(tenantName) template.tenantName = tenantName;
    if(userDataId) template.userDataId = userDataId;
    if(userData) template.userData = userData;
    if(accountInfo) template.accountInfo = accountInfo;
    if(systemsNicknames) template.systemsNicknames = systemsNicknames;
    
    def data = template.run(templateName);
    if(data){
        def instanceId = data["registry-info"]["object-id"];
        def instanceName = data["registry-info"]["object-name"];
        println "Instance Name=${instanceName}"
        println "Instance ID=${instanceId}"
        
        apTool.setOutputProperty("zosmf.instanceId", instanceId);
        apTool.setOutputProperty("zosmf.instanceName", instanceName);
        apTool.setOutputProperty("zosmf.response.data", data.toString());
        apTool.storeOutputProperties();
        
        if(waitForWorkflow){
            println "Waiting for ${instanceName} to be provisioned."
            def elapseSeconds = 0;
            def stepSeconds = 2;
            def state;
            Thread.sleep(2000)
            while (elapseSeconds < timeoutValue) {
                softwareServiceInstance = new SoftwareServiceInstance(baseurl, userid,password,untrustedSSL);
                softwareServiceInstance.printRESTLOG = printRESTLOG
                def instanceData = softwareServiceInstance.getSoftwareServicesInstance(instanceId);
                if(instanceData){
                    state = instanceData["state"];
                    /**
                        being-initialized
                        being-provisioned
                        provisioned
                        provisioning-suspended
                        being-deprovisioned
                        deprovisioning-suspended
                        deprovisioned
                        provisioning-failed
                        deprovisioning-failed
                     */
                    println "...instance state=${state}"
                    if(state == "being-initialized" || state == "being-provisioned"){
                    }else if(state == "provisioned"){
                        println ""
                        println "Provision completed.";
                        
                        def variables = softwareServiceInstance.getVariables(instanceId);
                        variables["variables"].each {
                            def vName = it["name"];
                            def vValue = it["value"]; 
                            apTool.setOutputProperty("zosmf.instance.${vName}", vValue?vValue:"");
                        }
                        apTool.storeOutputProperties();
                        processJobLog(printJOBLOG, outputJOBLOG, apTool, JOBS, jobsBefore, jobFilterMap, ddnameFilterArray, cutOff)
                        System.exit(0);
                    }else if(state == "provisioning-suspended" || state == "provisioning-failed"){
                        println ""
                        println "Provision failed or suspended.";
                        processJobLog(printJOBLOG, outputJOBLOG, apTool, JOBS, jobsBefore, jobFilterMap, ddnameFilterArray, cutOff)
                        System.exit(1);
                    }else{
                        println ""
                        println "Provision failed.";
                        System.exit(1);
                    }
                }else{
                    println ""
                    println "Failed to get instance state";
                    System.exit(1);
                }
                
                Thread.sleep(stepSeconds * 1000)
                elapseSeconds = elapseSeconds + stepSeconds
            }
            println ""
            println "Timeout waiting for ${instanceName} to complete. Timeout=" + timeoutValue + " seconds."
            println "Instance state : ${state}"
        }
	}else{
        println "Failed to run template."
        System.exit(1)
	}
}catch (Exception e) {
	println "Error run software service template : ${e.message}";
	e.printStackTrace();
	System.exit(1);
}

def processJobLog(printJOBLOG, outputJOBLOG, apTool, JOBS, jobsBefore, jobFilterMap, ddnameFilterArray, cutOff){
	//def JOBS, jobsBefore, jobsAfter, jobFilterMap = [:], ddnameFilterArray;
	if(! (printJOBLOG || outputJOBLOG)){
		return
	}
	
	sleep(2000); // wait a little longer so the jobs can be retrieved. 
	def jobsAfter = JOBS.listJobs(jobFilterMap);
	def joblogs = "";
    def newjobs = null;
    if(jobsAfter){
        if(jobsBefore){
            newjobs = jobsAfter.data.jobid - jobsBefore.data.jobid
        }else{
            newjobs = jobsAfter.data.jobid
        }
    }

    if(newjobs){        
        println "${newjobs.size()} jobs submitted after the workflow is started: " + newjobs
    }else{
        println "No job submitted after the workflow is started."
    }
	if(newjobs && newjobs.size() > 0) {
		jobsAfter.data.each{
			if(newjobs.contains(it.jobid)){
				joblogs += "===================== Output for ${it.jobid} ======================================\n"
				files = JOBS.getSpoolFiles(it.jobname, it.jobid, ddnameFilterArray, cutOff)
				joblogs += "Total ${files.size()} output data sets retrieved for job(${it.jobid}) with ddname matching ${ddnameFilterArray}\n"
				files.each {k,v->
				   joblogs += k
				   joblogs += "\n"
				   joblogs += v
				   joblogs += "\n\n"
				}
			}
		}
	}

	if(printJOBLOG){
		println joblogs
	}
	if(outputJOBLOG){
		apTool.setOutputProperty("zosmf.workflowJoblog", joblogs);
		apTool.storeOutputProperties();
	}
}
