/* <copyright                                       */
/* notice="cics-lm-source-program"                  */
/* pids="CA0U"                                      */
/* years="2014,2015"                                */
/* crc="2494330917" >                               */
/* 	Licensed Materials - Property of IBM            */
/* 	CA0U                                            */
/* 	(C) Copyright IBM Corp. 2014, 2015 All Rights Reserved. */
/* 	US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */
/* </copyright>                                     */
package com.ibm.cics.ucd

import com.ibm.cics.core.comm.ConnectionConfiguration
import com.ibm.cics.core.comm.ConnectionException
import com.ibm.cics.core.model.Context
import com.ibm.cics.core.model.ScopedContext
import com.ibm.cics.sm.comm.IContext
import com.ibm.cics.sm.comm.IResourceTables
import com.ibm.cics.sm.comm.IScopedContext
import com.ibm.cics.sm.comm.ISystemManagerConnection
import com.ibm.cics.sm.comm.SMConnectionRecord
import com.ibm.cics.sm.comm.SMConnectionResponse
import com.ibm.cics.sm.comm.SystemManagerConnectionException
import com.ibm.cics.sm.comm.sm.SMConnection
import com.ibm.cics.ucd.msg.CICSUCDMessage
import com.ibm.cics.ucd.properties.CommonCICSNameProperty
import com.ibm.cics.ucd.properties.HostProperty
import com.ibm.cics.ucd.properties.PortProperty
import com.ibm.cics.ucd.properties.PropertyException
import com.ibm.cics.ucd.properties.RequiredPropertyException
import com.ibm.cics.ucd.properties.StringProperty
import com.ibm.cics.ucd.steplabel.CICSUCDStepLabel
import static com.ibm.cics.ucd.StepLogHelper.printStepLog 

import java.text.MessageFormat

public class CMCIConnectionHelper {
	
	// <copyright 
	// notice="cics-lm-java-class" 
	// pids="CA0U" 
	// years="2014,2015" 
	// crc="3623644007" > 
	static final String COPYRIGHT = "Licensed Materials - Property of IBM CA0U (c) Copyright IBM Corp. 2014, 2015 All Rights Reserved. US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp."; //$NON-NLS-1$
	// </copyright> 
	
	private def responseCICSplex
	private def responseCICSRGN
	private def detectCICSplexes = ''
	
	private final def password
	private final def username
	private final def port
	private final def hostname
	private final def cicsplex
	private final def cicsscope
	
	static def HOSTNAME_PROPERTY = 'hostname'
	static def PORT_PROPERTY = 'port'
	static def USERNAME_PROPERTY = 'username'
	static def PASSWORD_PROPERTY = 'password'
	static def CICSPLEX_PROPERTY = 'cicsplex'
	static def CICSSCOPE_PROPERTY = 'cicsscope'
	
	public CMCIConnectionHelper(Properties props) throws PropertyException {
		hostname = new HostProperty(CICSUCDStepLabel.HOSTNAME, true).parse(props[HOSTNAME_PROPERTY]).getValue()
		port = new PortProperty(CICSUCDStepLabel.PORT, true).parse(props[PORT_PROPERTY]).getValue()
		username = new StringProperty(CICSUCDStepLabel.USERNAME, false).parse(props[USERNAME_PROPERTY]).getValue()
		password = new StringProperty(CICSUCDStepLabel.PASSWORD, false).parse(props[PASSWORD_PROPERTY]).getValue()
		cicsplex = new CommonCICSNameProperty(CICSUCDStepLabel.CICSPLEX, false).parse(props[CICSPLEX_PROPERTY]).getValue()
		cicsscope = new CommonCICSNameProperty(CICSUCDStepLabel.CICS_SCOPE, false).parse(props[CICSSCOPE_PROPERTY]).getValue()
	}
	
	def ISystemManagerConnection establishCMCIConnection() throws ConnectionException {
		
		//establish CMCI connection
		ConnectionConfiguration config = new ConnectionConfiguration("conn-conf-id", "conn-conf-name", hostname, port, "cred-id", false)
		config.setUserID(username)
		config.setPassword(password)
		ISystemManagerConnection conn = createConnection()
		conn.setConfiguration(config)
		String msg = null
		try {
			conn.connect()
			msg = MessageFormat.format(CICSUCDMessage.connectionEstablished, hostname + ":" + port)
			printStepLog(msg)
		} catch (ConnectionException e) {
			printStepLog(createConnectionErrorMessage(e))
			throw e
		}
		
		return conn
	}
	
	protected ISystemManagerConnection createConnection() {
		new SMConnection()
	}
	
	def String createConnectionErrorMessage(ConnectionException e) {
		Throwable cause = e;
		if (e.getCause() != null) {
			cause = e.getCause();
		}
		def msg
		if (cause instanceof UnknownHostException) {
			String unknownHost = cause.getMessage();
			msg = MessageFormat.format(CICSUCDMessage.unknownHost, unknownHost)
		} else {
			msg = MessageFormat.format(CICSUCDMessage.connectionFailedWithError, hostname + ":" + port, cause.getMessage())
		}
		return msg
	}
	
	def isCICSplex(ISystemManagerConnection conn) {
		SMConnectionResponse responseCMAS = null
		
		try{//attempt CICSPlex first, get PLEXNAME
			responseCMAS = conn.getResources(IResourceTables.MANAGER_CMAS,IContext.NULL_CONTEXT)   //SMRecord CMAS
			if (responseCMAS.getRecordCount() > 0) {
				responseCICSplex = conn.getResources(IResourceTables.MANAGER_CICSPLEX,IContext.NULL_CONTEXT)  //SMRecord CICSplex
				if (responseCICSplex.getRecordCount() > 0) {
					return true
				} else {
					throw new Exception('Missing CICSplex record')
				}
			} else {
				throw new Exception('Missing CMAS Record')
			}
		}catch(SystemManagerConnectionException e) {
			//then attempt SMSS, get APPLID
			responseCICSRGN = conn.getResources(IResourceTables.RESOURCE_CICSRGN,IContext.NULL_CONTEXT)//SMRecord CICSRGN
			if (responseCICSRGN.getRecordCount() > 0) {
				return false
			} else {
				throw new Exception('Missing regionRecord')
			}
		}
	}
	
	def IContext getContext(ISystemManagerConnection conn) throws Exception{
		//determine whether is CICSplex
		def isCICSplex = isCICSplex(conn)
		
		//set context
		IContext context = null
		String cicsPlexName = null
		
		if (isCICSplex == false) {//SMSS
			ignoreCICSplexScope()
			context = new ScopedContext(responseCICSRGN.getRecord(0).get('APPLID'), responseCICSRGN.getRecord(0).get('APPLID'))
		} else {//CICSplex
			if(responseCICSplex.getRecordCount() == 1) {	//one single CICSplex
				cicsPlexName = responseCICSplex.getRecord(0).get("PLEXNAME")
				if(noCICSplexSpecified()) {
					printStepLog(MessageFormat.format(CICSUCDMessage.setDefaultCICSplex, CICSUCDStepLabel.CICSPLEX, cicsPlexName))
				} else {
					if( !cicsPlexName.equalsIgnoreCase(cicsplex) )
						throw new Exception(MessageFormat.format(CICSUCDMessage.incorrectCICSplexSuggestion, CICSUCDStepLabel.CICSPLEX, cicsPlexName))
				}
			} else {					//more than one CICSplex
				if(noCICSplexSpecified()) {
					throw new RequiredPropertyException(MessageFormat.format(CICSUCDMessage.missingCICSplex, CICSUCDStepLabel.CICSPLEX))
				} else {
					if(findMatchingCICSplex())
						cicsPlexName = cicsplex
					else {//can not find matching cicsplex
						throw new Exception(MessageFormat.format(CICSUCDMessage.incorrectCICSplexSuggestion, CICSUCDStepLabel.CICSPLEX, detectCICSplexes))
					}
				}
			}
			
			context = new ScopedContext(new Context(cicsPlexName), cicsscope)
			
		}
			
		return context
	}
	
	def findMatchingCICSplex() {
		def countCICSplex = responseCICSplex.getRecordCount()
		for(int i = 0; i < countCICSplex; i++) {
			
			def detectCICSplexName = responseCICSplex.getRecord(i).get('PLEXNAME')
			detectCICSplexes += detectCICSplexName
			if(i < countCICSplex - 1)
				detectCICSplexes += '/'
			
			if(detectCICSplexName.equalsIgnoreCase(cicsplex)) {
				return true
			}
		}
		return false
	}
	
	def noCICSplexSpecified() {
		if(cicsplex == null || cicsplex.isEmpty())
			return true
		else 
			return false
	}
	
	def ignoreCICSplexScope() {
		if(cicsplex && cicsplex.length() > 0) 		//CICSplex is ignored
			printStepLog(MessageFormat.format(CICSUCDMessage.ignoreContextPropertySMSS, CICSUCDStepLabel.CICSPLEX))
		if(cicsscope && cicsscope.length() > 0) 		//Scope is ignored
			printStepLog(MessageFormat.format(CICSUCDMessage.ignoreScopePropertySMSS, CICSUCDStepLabel.CICS_SCOPE, CICSUCDStepLabel.TARGET_SCOPE))
	}
}
