/*
 - Licensed Materials - Property of IBM* and/or HCL**
 * IBM UrbanCode Build
 * IBM UrbanCode Deploy
 * IBM UrbanCode Release
 * IBM AnthillPro
 * (c) Copyright IBM Corporation 2002, 2016. All Rights Reserved.
 * (c) Copyright HCL Technologies Ltd. 2018. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 *
 * Trademark of International Business Machines
 ** Trademark of HCL Technologies Limited
 */
package com.ibm.urbancode.zos.common;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;

import com.urbancode.commons.util.ssl.OpenX509TrustManager;

import groovyx.net.http.*
import groovyx.net.http.RESTClient
import groovyx.net.http.AuthConfig
import groovyx.net.http.ContentType
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import org.apache.http.conn.ssl.SSLSocketFactory
import org.apache.http.conn.scheme.Scheme
import org.apache.http.conn.ssl.TrustStrategy

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class ZOSJOBS {
    def count = 0;
    def baseURL;
    def client;
    def VERSION_DEFAULT = "1.0";

    def ZOSJOBS(baseURL, username, password){
        this.baseURL = baseURL;
        client = new RESTClient(baseURL);
        client.encoder.setCharset("UTF-8");
        client.auth.basic username, password;
    
        TrustStrategy trustStrat = new TrustStrategy(){
            public boolean isTrusted(X509Certificate[] chain, String authtype)
                  throws CertificateException {
                         return true;
                  }
        };
        SSLSocketFactory sslSocketFactory = new SSLSocketFactory(trustStrat,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);                       
        client.client.connectionManager.schemeRegistry.register(new Scheme("https",443,sslSocketFactory ) );

    }
    
    /**
      params: a map of Query parameters
        owner        User ID of the job owner whose jobs are being queried; the default is the z/OS user ID. Folded to uppercase; cannot exceed eight characters.
        prefix       Job name prefix; defaults is *. Folded to uppercase; cannot exceed eight characters.
        jobid        Job ID. Folded to uppercase; cannot exceed eight characters. This query parameter is mutually exclusive with user-correlator.
        max-jobs     Maximum number of jobs returned. The value must be between 1 and 1000, inclusive. If this parameter is not specified, or is specified incorrectly, the default value of 1000 is used.
        
        Observe the following conventions:
            Query parameters are optional; you can specify one or more query parameters, as needed.
            You use a question mark (?) to separate the first query parameter from the resource.
            To specify multiple query parameters in combination, use an ampersand (&).
            Wildcard characters are permitted in the owner and prefix query parameter values. Use an asterisk (*) for multiple characters, and a question mark (?) for a single character.
        Example: 
            [prefix : "IZU*" , "max-jobs": 1000]
            
      return: response of the RESTClient call.
          
    */
    def listJobs(params){
				client.contentType = "*/*"
		    def URI_JOBS_LIST = "/zosmf/restjobs/jobs"
		    params << [count : count ] 
		    count ++
        def resp  = client.get(  path : URI_JOBS_LIST,
                         query : params,
                         requestContentType: ContentType.JSON
                      )
        println resp.statusLine
        if(resp.status == 200){
            println "" + resp.data.size() + "jobs found."
            resp.data.each {
//                println it.jobname + " " + it.jobid + " " + it.url
            }
            println ""
       }
       return resp;
    }
    
    def getJobJCL(name, id){
    	getJobJCL(name, id,0);
    }
    /**
      lines:  0 for the entire file
    */
    def getJobJCL(name, id, lines){
    		assert !name.contains("/") : "Job name can not contain /";
    		assert !id.contains("/") : "Job id can not contain /";
    		def headerMap = [:]
    		if(lines == 0){
    				headerMap["X-IBM-Record-Range"] = "0-0"
    		}else{
    				headerMap["X-IBM-Record-Range"] = "0,${lines}"
				}    		
    		
				client.contentType = "*/*"
				def URI_JOBS_JCL = "/zosmf/restjobs/jobs/${name}/${id}/files/JCL/records"
    		def resp  = client.get(  path : URI_JOBS_JCL,
																 headers :  headerMap,   														
    														 query: [mode:"text"],
                         requestContentType: ContentType.TEXT
                      )
        /*println resp.statusLine
        if(resp.status == 200){
            println resp.data.text
            println ""
       }*/
       return resp;
    } 

    def getJobOutput(){
    	
    } 

    def getSpoolFiles(name, id){
    	getSpoolFiles(name, id, "*", 0);
    }
    /**
      lines:  0 for the entire file
    */
    def getSpoolFiles(name, id, ddnames, lines){
    		assert !name.contains("/") : "Job name can not contain /";
    		assert !id.contains("/") : "Job id can not contain /";
//    		assert !ddnames.contains("/") : "ddname can not contain /";
    		
    		
    		def headerMap = [:]
    		if(lines == 0){
    				headerMap["X-IBM-Record-Range"] = "0-0"
    		}else{
    				headerMap["X-IBM-Record-Range"] = "0,${lines}"
				}    		
    		
				client.contentType = "*/*"
        def URI_JOBS_FILES = "/zosmf/restjobs/jobs/${name}/${id}/files"
    		def resp  = client.get(  path : URI_JOBS_FILES,
                         requestContentType: ContentType.JSON
                      )
        if(resp.status != 200){
            println "Failed to retrieve spool files"
       		println resp.statusLine
            return 
       }
        if(resp.data.size() <= 0 ){
            println "No spool files found"
            return 
       }
       
       def fileMap = [:]
       resp.data.each{
       			if(matchName(it.ddname, ddnames)){
	       			println "Retriving ${it.ddname} for job ${name} ${id} ..."
	       			def URI_JOBS_FILE_RECORDS = "/zosmf/restjobs/jobs/${name}/${id}/files/${it.id}/records"
							def recordsResp  = client.get(  path : URI_JOBS_FILE_RECORDS,
																	 headers :  headerMap,   														
	    														 query: [mode:"text"],
	                         				 requestContentType: ContentType.TEXT
	                      					)
	       		  if(recordsResp.status == 200){
	            		println "${it.ddname} retrived."
	            		fileMap[it.id+" "+it.ddname] = recordsResp.data.text
	            }else{
		    	        println "Failed to retrieve ${it.ddname}"
	  		      		println recordsResp.statusLine
	  		      }
	  		   }else{
	  		   		println "${it.ddname} does not match ${ddnames}."
	  		   }
       }
       return fileMap;
    } 
    
    
    def matchName(name, patterns){
       //match everything if there's no pattern
		if(patterns.size() == 0){
			return true;
		}
		
		def match = false;
		patterns.each{
		   def patternText = it.trim();
		   if(patternText != ""){
				def pattern;
				if(patternText.startsWith("/") && patternText.endsWith("/")){
					//if pattern is regular expression
					pattern = ~patternText.substring(1,patternText.length()-1)
				}else{
				  	//if pattern conatins ISPF stype wildcards, convert it to regular expression
					patternText = patternText.replace ("*", ".*")
					patternText = patternText.replace ("?", ".")
					pattern = ~patternText
				}
				if(name ==~ pattern){
					match = true;
				}
		   }
		}
		return match;
    }
		
		/**
		 return JSON 
		 
		*/
		def submitJob(jcl){
				
				try  { 
					def URI_JOBS_SUBMIT = "/zosmf/restjobs/jobs"
					client.contentType = "text/plain"
	        def resp  = client.put(  path : URI_JOBS_SUBMIT,
	        												 body : jcl,
	                         requestContentType: ContentType.TEXT
	                      )
	        assert resp.status == 201
	        //TODO response is in JSON actually, need to parse it.
   				return resp
	      }catch (HttpResponseException e){
					//any HTTP status code > 399 will end up here.
						println e.response.statusLine
						println ""
						println e.response.data? e.response.data.text : ""
						println ""
						throw e
				}
  	}
}

