/*
 * JBoss, Home of Professional Open Source.
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 * Modified by
 * @author  Data Virtuality GmbH
 * @date    $Date$
 *  
 */
// https://issues.jboss.org/browse/TEIID-2597
package org.teiid.resource.adapter.ws;

import com.datavirtuality.dv.core.interfaces.ControllerInject;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBusFactory;
import org.apache.cxf.configuration.Configurer;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.jaxws.JaxWsClientFactoryBean;
import org.teiid.core.BundleUtil;
import org.teiid.core.util.EquivalenceUtil;
import org.teiid.resource.spi.BasicConnection;
import org.teiid.resource.spi.BasicConnectionFactory;
import org.teiid.resource.spi.BasicManagedConnectionFactory;

import javax.resource.ResourceException;
import javax.xml.namespace.QName;
import java.util.List;

public class WSManagedConnectionFactory extends BasicManagedConnectionFactory {

	private static final long serialVersionUID = -2998163922934555003L;
	
	public static final BundleUtil UTIL = BundleUtil.getBundleUtil(WSManagedConnectionFactory.class);

	// EXTENSION
	// ISSUE: DVCORE-1187
	// FIXED BY: Salvatore Raunich
	// DATE: 2014.06.27
//	public enum SecurityType {None,HTTPBasic,WSSecurity}
	public enum SecurityType {NONE, HTTPBASIC, WSSECURITY, KERBEROS, OAUTH2, NTLM}

	private String accessToken; // oauth2 - accessToken
	private String refreshToken; // oauth2 - refreshToken
	private String clientId; // oauth2 - clientId
	private String clientSecret; // oauth2 - clientSecret
	private String scope; // oauth2 -microsoft- scope
	private String accessTokenEndpoint; // oauth2 - accessTokenEndpoint
	// END EXTENSION
	private String translatorName; // oauth2 - translator key
	
	private String endPoint;
	private String securityType = SecurityType.NONE.name(); // None, HTTPBasic, WS-Security
	private String configFile; // path to the "jbossws-cxf.xml" file
	private String configName; // config name in the above file
	private String authPassword; // httpbasic/ntlm - password
	private String authUserName; // httpbasic/ntlm - username
	private String authDomain; // ntlm - domain
	private String authHost; // ntlm - host
	private String cloudAgentWsHost;

	private Bus bus;
	private QName portQName;
	private List<? extends Interceptor> outInterceptors;
	private Long requestTimeout;
	private Long connectTimeout;

	private String authCode;
	private String redirectUri;
	private String dataSourceName;
	private Boolean decompressCompressedFiles;

	@Override
	public BasicConnectionFactory createConnectionFactory() throws ResourceException {
		String configName = getConfigName();
		if (configName == null) {
			configName = WSConnectionImpl.DEFAULT_LOCAL_NAME; 
		}
		this.portQName = new QName(WSConnectionImpl.DEFAULT_NAMESPACE_URI, configName);
		if (configFile != null) {
			bus = new SpringBusFactory().createBus(configFile);
			JaxWsClientFactoryBean instance = new JaxWsClientFactoryBean();
			Configurer configurer = bus.getExtension(Configurer.class);
	        if (null != configurer) {
	            configurer.configureBean(portQName.toString() + ".jaxws-client.proxyFactory", instance); //$NON-NLS-1$
	        }
	        outInterceptors = instance.getOutInterceptors();
		}
		return new BasicConnectionFactory() {
			@Override
			public BasicConnection getConnection() throws ResourceException {
				return new WSConnectionImpl(WSManagedConnectionFactory.this);
			}
		};
	}
	
	public String getAuthPassword() {
		return this.authPassword;
	}

	public void setAuthPassword(String authPassword) {
		this.authPassword = authPassword;
	}

	public String getAuthUserName() {
		return this.authUserName;
	}

	public void setAuthUserName(String authUserName) {
		this.authUserName = authUserName;
	}

	public String getAuthDomain() {
		return authDomain;
	}

	public void setAuthDomain(String authDomain) {
		this.authDomain = authDomain;
	}

	public String getAuthHost() {
		return authHost;
	}

	public void setAuthHost(String authHost) {
		this.authHost = authHost;
	}

	// EXTENSION
	// ISSUE: DVCORE-1187
	// FIXED BY: Salvatore Raunich
	// DATE: 2014.06.27
	public String getAccessToken() {
		return this.accessToken;
	}
	
	public void setAccessToken(String accessToken) {
		this.accessToken = accessToken;
	}
	
	public String getRefreshToken() {
		return this.refreshToken;
	}
	
	public void setRefreshToken(String refreshToken) {
		this.refreshToken = refreshToken;
	}

	public String getClientId() {
		return clientId;
	}

	public void setClientId(String clientId) {
		this.clientId = clientId;
	}

	public String getClientSecret() {
		return clientSecret;
	}

	public void setClientSecret(String clientSecret) {
		this.clientSecret = clientSecret;
	}

	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getAccessTokenEndpoint() {
		return accessTokenEndpoint;
	}

	public void setAccessTokenEndpoint(String accessTokenEndpoint) {
		this.accessTokenEndpoint = accessTokenEndpoint;
	}
	// END EXTENSION

	public String getTranslatorName() {
		return translatorName;
	}

	@ControllerInject("translatorName")
	public void setTranslatorName(String translatorName) {
		this.translatorName = translatorName;
	}
	
	public String getEndPoint() {
		return this.endPoint;
	}

	@ControllerInject("endPoint")
	public void setEndPoint(String endPoint) {
		this.endPoint = endPoint;
	}

	public String getCloudAgentWsHost() {
		return cloudAgentWsHost;
	}

	@ControllerInject("cloudAgentWsHost")
	public void setCloudAgentWsHost(String cloudAgentWsHost) {
		this.cloudAgentWsHost = cloudAgentWsHost;
	}
	
	public Long getRequestTimeout() {
		return this.requestTimeout;
	}

	public void setRequestTimeout(Long timeout) {
		this.requestTimeout = timeout;
	}	
	
	public SecurityType getAsSecurityType() {
		return SecurityType.valueOf(this.securityType != null ? this.securityType.toUpperCase() : "");
	}

	public String getSecurityType() {
		return this.securityType;
	}

	public void setSecurityType(String securityType) {
		this.securityType = securityType;
	}	

	public String getConfigFile() {
		return configFile;
	}

	public void setConfigFile(String config) {
		this.configFile = config;
	}
	
	public String getConfigName() {
		return configName;
	}

	public void setConfigName(String configName) {
		this.configName = configName;
	}

	public String getAuthCode() {
		return authCode;
	}

	public void setAuthCode(String authCode) {
		this.authCode = authCode;
	}

	public String getRedirectUri() {
		return redirectUri;
	}

	public void setRedirectUri(String redirectUri) {
		this.redirectUri = redirectUri;
	}

	public String getDataSourceName() {
		return dataSourceName;
	}

	public void setDataSourceName(String dataSourceName) {
		this.dataSourceName = dataSourceName;
	}
	
	public Boolean getDecompressCompressedFiles() {
		return decompressCompressedFiles;
	}

	public void setDecompressCompressedFiles(Boolean decompressCompressedFiles) {
		this.decompressCompressedFiles = decompressCompressedFiles;
	}

	public Bus getBus() {
		return bus;
	}
	
	public QName getPortQName() {
		return portQName;
	}

	public List<? extends Interceptor> getOutInterceptors() {
		return outInterceptors;
	}

	public Long getConnectTimeout() {
		return connectTimeout;
	}

	public void setConnectTimeout(Long connectTimeout) {
		this.connectTimeout = connectTimeout;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((authPassword == null) ? 0 : authPassword.hashCode());
		result = prime * result + ((authUserName == null) ? 0 : authUserName.hashCode());
		result = prime * result + ((authDomain == null) ? 0 : authDomain.hashCode());
		result = prime * result + ((authHost == null) ? 0 : authHost.hashCode());
		result = prime * result + ((configFile == null) ? 0 : configFile.hashCode());
		result = prime * result + ((configName == null) ? 0 : configName.hashCode());
		result = prime * result + ((endPoint == null) ? 0 : endPoint.hashCode());
		result = prime * result + ((securityType == null) ? 0 : securityType.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) return true;
		if (obj == null) return false;
		//if (getClass() != obj.getClass()) return false;
		if (!(obj instanceof WSManagedConnectionFactory)) return false;
		WSManagedConnectionFactory other = (WSManagedConnectionFactory) obj;
		if (!checkEquals(this.authPassword, other.authPassword)) {
			return false;
		}
		if (!checkEquals(this.authUserName, other.authUserName)) {
			return false;
		}
		if (!checkEquals(this.authDomain, other.authDomain)) {
			return false;
		}
		if (!checkEquals(this.authHost, other.authHost)) {
			return false;
		}
		if (!checkEquals(this.configFile, other.configFile)) {
			return false;
		}
		if (!checkEquals(this.configName, other.configName)) {
			return false;
		}
		if (!checkEquals(this.endPoint, other.endPoint)) {
			return false;
		}
		if (!checkEquals(this.securityType, other.securityType)) {
			return false;
		}
		return EquivalenceUtil.areEqual(this.requestTimeout, other.requestTimeout)
						&& EquivalenceUtil.areEqual(this.connectTimeout, other.connectTimeout);
	}
	
}
