import com.ibm.urbancode.zos.common.DeploymentConstants;
import com.ibm.urbancode.zos.common.DeploymentHelper;
import com.ibm.urbancode.zos.common.PackageManifestXMLHelper;
import com.ibm.urbancode.zos.deploy.common.DeploymentResultHelper;
import com.urbancode.air.AirPluginTool
import com.urbancode.ud.client.ResourceClient
import org.codehaus.jettison.json.JSONObject

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

try {
	final def workDir = new File('.').canonicalFile
	final def props = new Properties();
	final def inputPropsFile = new File(args[0]);
	try {
		inputPropsStream = new FileInputStream(inputPropsFile);
		props.load(inputPropsStream);
	}
	catch (IOException e) {
		throw new RuntimeException(e);
	}


	final def resourceId   		= DeploymentHelper.getStringInput(props['resourceId']);
	final def componentId		= DeploymentHelper.getStringInput(props['componentId']);
	final def componentName   	= DeploymentHelper.getStringInput(props['componentName']);
	final def versionName 	  	= DeploymentHelper.getStringInput(props['versionName']);
	final def deployBasePath  	= DeploymentHelper.getStringInput(props['deployBasePath']);
	final def pdsMapping 	  	= DeploymentHelper.getStringInput(props['pdsMapping']);
	final def checkAccess 	  	= DeploymentHelper.getBooleanInput(props['checkAccess']);
	final def allowCreateDataset  = DeploymentHelper.getBooleanInput(props['allowCreateDataset']);
	
	final def workDirPath = workDir.canonicalPath;
	final def componentVersionWorkingDir  = DeploymentHelper.getVersionDirPathInWorkingDir(workDirPath,versionName,resourceId);
	final def packageManifestFileNamePath = DeploymentHelper.getFilePathInWorkingDir(workDirPath, versionName, resourceId, DeploymentConstants.PACKAGE_MANIFEST_FILE_NAME);
	final def packageZipFilePath 		  = DeploymentHelper.getFilePathInWorkingDir(workDirPath, versionName, resourceId, DeploymentConstants.PACKAGE_FILE_NAME);
	DeploymentHelper.validateFileExist(packageManifestFileNamePath, "${packageManifestFileNamePath} not found. Please make sure a Copy or FTP plug-in step is successfully executed before the Deploy plug-in step.");
	
	def pkgManifestHelper = new PackageManifestXMLHelper();
	if (pkgManifestHelper.isGenericOnlyVersion(packageManifestFileNamePath)) {
		DeploymentHelper.printActionTitle("Warning: No artifacts to deploy.");
		DeploymentHelper.postDeployForGenericOnly(deployBasePath, resourceId, componentName, versionName, componentVersionWorkingDir);
		DeploymentHelper.cleanWorkDir(componentVersionWorkingDir);
		System.exit(0);
	} else {
		DeploymentHelper.validateFileExist(packageZipFilePath, "${packageZipFilePath} not found. Please make sure a Copy or FTP plug-in step is successfully executed before the Deploy plug-in step.");
	}
	
	//final def backupPds = Boolean.valueOf(props['backupPds']);
	final def backupPds = true;
	if (DeploymentResultHelper.checkVersionDeployed(deployBasePath, resourceId, componentName, versionName)) {
		//Initialize the EnvironmentClient help class and pass the auth.
		def apTool = new AirPluginTool(this.args[0], this.args[1]);
		def udUser = apTool.getAuthTokenUsername();
		def udPass = apTool.getAuthToken();
		def weburl = System.getenv("AH_WEB_URL");
		ResourceClient resClient = new ResourceClient(new URI(weburl), udUser, udPass);
		com.urbancode.air.XTrustProvider.install();
		
		JSONObject latestVesionJson = resClient.getLatestVersionByResourceAndComponent(resourceId, componentId);
		if (null != latestVesionJson && latestVesionJson.has("version")) {
			latestVesionJson = latestVesionJson.getJSONObject("version");
			if (null != latestVesionJson && latestVesionJson.has("name")) {
				def latestVersionName = latestVesionJson.getString("name")?.trim();
				if (latestVersionName == versionName) {
					backupPds = false; //If currently deploying version same with latest version, we will not do the backup action
					DeploymentHelper.printProcessOutput("A backup is already taken by the previous deploy.");
				}
			}
		}
	}
	
	def toolKitHome 	= DeploymentHelper.getStringInput(System.getenv().get("BUZ_TOOLKIT_HOME"));
	if (!toolKitHome) {//try to compatible with application build on old plug-in(before v5)
		toolKitHome = DeploymentHelper.getStringInput(props['ucdToolKitHome']);
	}

	DeploymentHelper.validateDirectoryExist(deployBasePath, "Deploy Base Path ${deployBasePath} does not exist.");

	//The deploy working directory
	final def packageManifestFileDeployNamePath = DeploymentHelper.getFilePathInWorkingDir(workDirPath, versionName, resourceId, DeploymentConstants.PACKAGE_MANIFEST_FILE_DEPLOY_NAME);
	final def conainerMapperXmlFilePath   = DeploymentHelper.getFilePathInWorkingDir(workDirPath, versionName, resourceId, DeploymentConstants.CONTAINER_MAPPER_FILE_NAME);
	final def dsListFile4BackUpPath 	  = DeploymentHelper.getFilePathInWorkingDir(workDirPath, versionName, resourceId, DeploymentConstants.CHECK_ACCESS_DS_FILE_NAME_BACKUP);
	final def dsListFilePath 			  = DeploymentHelper.getFilePathInWorkingDir(workDirPath, versionName, resourceId, DeploymentConstants.CHECK_ACCESS_DS_FILE_NAME);
	final def zosScriptPath 			  = DeploymentHelper.getPath4ExecScriptInToolkit(toolKitHome , DeploymentConstants.ZOS_TOOLKIT_ISPF_SCRIPT_NAME);
	final def checkAccessExePath 		  = DeploymentHelper.getPath4ExecScriptInToolkit(toolKitHome , DeploymentConstants.CHECK_ACCESS_EXE);

	//Do parameter checking
	DeploymentHelper.validateFileExist(zosScriptPath, "Can not find the ispf gateway script:${zosScriptPath}. Please make sure z/OS Deploy Toolkit is installed and z/OS Toolkit Home is set to the correct location.");
	

	//Combile the user input and the environment pds mapping
	def src2TargetMap = [:];
	//collect those ruler with wildcard "*" character, the key will be an regular express pattern
	def containsWildcardMap = [:];
	
	//Handle user input pds mapping
	DeploymentHelper.handleMappingRule(pdsMapping, src2TargetMap, containsWildcardMap);
	
	//Check the mapping rule to see if some datasets were missed
	pkgManifestHelper.removeGenericResourceNodes(packageManifestFileNamePath, packageManifestFileDeployNamePath);
	def dsNeedToDeploy 		= 	pkgManifestHelper.getAllDeployDatasets(packageManifestFileDeployNamePath);
	def dsIncludedByUser 	= 	src2TargetMap.keySet();
	def missedDsByUser 		= 	dsNeedToDeploy - dsIncludedByUser;
	
	def notResolvedByWildcard = dsNeedToDeploy - dsIncludedByUser;
	if(missedDsByUser && missedDsByUser.size() > 0){
		missedDsByUser.each { missedDsItem ->
			containsWildcardMap.keySet().each {keywithWildcardPattern->
				if(missedDsItem ==~ keywithWildcardPattern) {
					if(!src2TargetMap.get(missedDsItem)) {
						src2TargetMap.put(missedDsItem, containsWildcardMap.get(keywithWildcardPattern));
						notResolvedByWildcard.remove(missedDsItem);
					}
					return(true);//If find the ruler, escape the loop
				}
			}
		}
	}
	
	//#comment it first, will add back later#If the dataset was not set with a.b.c,a1.b1.c1 and not set by *.c,a2.b2.c2. We will use a.b.c,a.b.c ruler as the default 
	if(notResolvedByWildcard && notResolvedByWildcard.size() >0) {
//		notResolvedByWildcard.each { noRulerItem ->
//			if(!src2TargetMap.get(noRulerItem)) {
//				src2TargetMap.put(noRulerItem, noRulerItem);
//			}
//		}
		def dsStr = "";
		for (ds in notResolvedByWildcard) {
			dsStr += " " + ds;
		}
		DeploymentHelper.printProcessOutput("Missing PDS mapping rules for: ${dsStr}");
		System.exit(1);
	}
	
	def dsToDeploySrc2TargetMap = [:];
	dsNeedToDeploy.each {ds2Deploy ->
		dsToDeploySrc2TargetMap.put(ds2Deploy, src2TargetMap.get(ds2Deploy));
	}

	
	def targetDsSet =  dsToDeploySrc2TargetMap.values().toSet();
	
	//check allowCreateDataset
	if(!allowCreateDataset){
		DeploymentHelper.printActionTitle("Check data sets exist:");
		def datasetsExist = DeploymentHelper.checkDatasetsExist(targetDsSet)
		if(!datasetsExist){
			DeploymentHelper.printProcessOutput("Deploy failed because target data set could not be opened and Allow Creating Data Set is set to false.");
			System.exit(1) 
		}
		println "";
	}
	
	//Check access
	//If use back up the data, we need to check "INPUT" access for those target dataset
	if(backupPds && checkAccess){
		DeploymentHelper.printActionTitle("Check access for back up action:")
		DeploymentHelper.checkAccess4Input(targetDsSet, dsListFile4BackUpPath, checkAccessExePath)
		println "";
	}
	//Check access for "OUTPUT" access for deployment process.
	if(checkAccess){
		DeploymentHelper.printActionTitle("Check access for deployment action:")
		DeploymentHelper.checkAccess4Output(targetDsSet, dsListFilePath, checkAccessExePath)
		println "";
	}


	//Generate the containerMapping file logic
	def pdsXmlStrWriter = new StringWriter();
	pdsXmlStrWriter.append('<?xml version="1.0" encoding="IBM-1047"?>');
	def containerMapperXml = new groovy.xml.MarkupBuilder(pdsXmlStrWriter);
	containerMapperXml.setDoubleQuotes(true);
	if(dsToDeploySrc2TargetMap.size() > 0){
		containerMapperXml.maps(){
			dsToDeploySrc2TargetMap.each { pdsSrc, pdsTarget->
				map(type:"PDS"){
					sourceContainer(name:pdsSrc);
					targetContainer(name:pdsTarget);
				}
			}
		}
	}else{
		//Handle the issue of no mapping
		throw new IllegalArgumentException("PDS mapping not found. Make sure you have specified the mapping either in PDS mapping or Environment PDS mapping.");
	}


	//Put the content into log
	DeploymentHelper.printActionTitle("The containerMapper.xml contents:")
	def pdsXmlStr = pdsXmlStrWriter.toString();
	DeploymentHelper.printProcessOutput(pdsXmlStr);
	println "";
	
	//Generate the containerMapper.xml file
	new File(conainerMapperXmlFilePath).withWriter('IBM-1047'){ out ->
		out.print(pdsXmlStrWriter);
	}

	//deploy
	DeploymentHelper.doDeploymentAction(deployBasePath, resourceId, componentName, versionName, zosScriptPath, componentVersionWorkingDir, backupPds);
	
	//Clear the working directory to avoid dirty data
	//Just delete those files we created
	DeploymentHelper.cleanWorkDir(componentVersionWorkingDir);
} catch (Exception e) {
	DeploymentHelper.printActionTitle("Error deploying version. ${e.message}");
//	e.printStackTrace();
	System.exit(1);
}

System.exit(0);