/*
 * 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-2453
// https://issues.jboss.org/browse/TEIID-3526
// https://issues.jboss.org/browse/TEIID-2619
// https://issues.jboss.org/browse/TEIID-4130
// https://issues.jboss.org/browse/TEIID-3046
// https://issues.jboss.org/browse/TEIID-4076
// https://issues.jboss.org/browse/TEIID-2904
// https://issues.jboss.org/browse/TEIID-5462
// https://issues.jboss.org/browse/TEIID-5327
// https://issues.jboss.org/browse/TEIID-3630
// https://issues.jboss.org/browse/TEIID-4692
// https://issues.jboss.org/browse/TEIID-3437
// https://issues.jboss.org/browse/TEIID-2555
// https://issues.jboss.org/browse/TEIID-3530
// https://issues.redhat.com/browse/TEIID-3156
// https://issues.redhat.com/browse/TEIID-4202
// https://issues.redhat.com/browse/TEIID-5480
// https://issues.redhat.com/browse/TEIID-2285
package org.teiid.translator;

import java.util.List;

import org.teiid.language.*;
import org.teiid.metadata.FunctionMethod;
import org.teiid.metadata.MetadataFactory;
import org.teiid.metadata.RuntimeMetadata;

/**
 * Base delegating translator. Will proxy all calls to another {@link ExecutionFactory}. 
 * You will create a custom translator as a subclass of this class containing overrides for
 * any method you wish to intercept.
 * Given that subclass is given a {@link Translator} name of 'custom-delegator', your 'vdb.xml' file will
 * contain an XML fragment like the following to assign the delegate:
 * <pre>
 * {@code
 <translator type="custom-delegator" name="my-translator" description="custom translator">
    <property value="delegateName" name="name of the delegate instance"/>
    <!-- any custom properties will also appear here -->
 </translator>}
 * </pre>
 *  
 */
public class BaseDelegatingExecutionFactory<F, C> extends ExecutionFactory<F, C> implements DelegatingExecutionFactory<F, C> {

	private String delegateName;
	private ExecutionFactory<F, C> delegate;
	
	/**
	 * For testing only
	 */
	protected ExecutionFactory<F, C> getDelegate() {
		return this.delegate;
	}
	
	/**
	 * Sets the delegate, will be called by Teiid after {@link #start()}
	 */
	public void setDelegate(ExecutionFactory<F, C> delegate) {
		this.delegate = delegate;
	}
	
	@TranslatorProperty(display="Delegate name", required = true)
	public String getDelegateName() {
		return this.delegateName;
	}
	
	public void setDelegateName(String delegateName) {
		this.delegateName = delegateName;
	}
	
	@Override
	public boolean areLobsUsableAfterClose() {
		return delegate.areLobsUsableAfterClose();
	}
	@Override
	public void closeConnection(C connection, F factory) {
		delegate.closeConnection(connection, factory);
	}
	@Override
	public Execution createExecution(Command command,
			ExecutionContext executionContext, RuntimeMetadata metadata,
			C connection) throws TranslatorException {
		return delegate.createExecution(command, executionContext, metadata,
				connection);
	}
	@Override
	public ProcedureExecution createProcedureExecution(Call command,
			ExecutionContext executionContext, RuntimeMetadata metadata,
			C connection) throws TranslatorException {
		return delegate.createProcedureExecution(command, executionContext,
				metadata, connection);
	}
	@Override
	public ResultSetExecution createResultSetExecution(QueryExpression command,
			ExecutionContext executionContext, RuntimeMetadata metadata,
			C connection) throws TranslatorException {
		return delegate.createResultSetExecution(command, executionContext,
				metadata, connection);
	}
	@Override
	public UpdateExecution createUpdateExecution(Command command,
			ExecutionContext executionContext, RuntimeMetadata metadata,
			C connection) throws TranslatorException {
		return delegate.createUpdateExecution(command, executionContext,
				metadata, connection);
	}
	@Override
	public C getConnection(F factory, ExecutionContext executionContext) throws TranslatorException {
		return delegate.getConnection(factory, executionContext);
	}
	@Override
	public NullOrder getDefaultNullOrder() {
		return delegate.getDefaultNullOrder();
	}
	@Override
	public LanguageFactory getLanguageFactory() {
		return delegate.getLanguageFactory();
	}
	@Override
	public int getMaxFromGroups() {
		return delegate.getMaxFromGroups();
	}
	@Override
	public void getMetadata(MetadataFactory metadataFactory, C conn)
			throws TranslatorException {
		delegate.getMetadata(metadataFactory, conn);
	}
	@Override
	public List<FunctionMethod> getPushDownFunctions() {
		return delegate.getPushDownFunctions();
	}
	@Override
	public List<String> getSupportedFunctions() {
		return delegate.getSupportedFunctions();
	}
	@Override
	public TypeFacility getTypeFacility() {
		return delegate.getTypeFacility();
	}
	@Override
	public boolean isImmutable() {
		return delegate.isImmutable();
	}
	@Override
	public boolean isSourceRequired() {
		return delegate.isSourceRequired();
	}
	@Override
	public boolean supportsAggregatesAvg() {
		return delegate.supportsAggregatesAvg();
	}
	@Override
	public boolean supportsAggregatesCount() {
		return delegate.supportsAggregatesCount();
	}
	@Override
	public boolean supportsAggregatesCountStar() {
		return delegate.supportsAggregatesCountStar();
	}
	@Override
	public boolean supportsAggregatesDistinct() {
		return delegate.supportsAggregatesDistinct();
	}
	@Override
	public boolean supportsAggregatesEnhancedNumeric() {
		return delegate.supportsAggregatesEnhancedNumeric();
	}
	@Override
	public boolean supportsAggregatesMax() {
		return delegate.supportsAggregatesMax();
	}
	@Override
	public boolean supportsAggregatesMin() {
		return delegate.supportsAggregatesMin();
	}
	@Override
	public boolean supportsAggregatesSum() {
		return delegate.supportsAggregatesSum();
	}
	@Override
	public boolean supportsAliasedTable() {
		return delegate.supportsAliasedTable();
	}
	@Override
	public boolean supportsBatchedUpdates() {
		return delegate.supportsBatchedUpdates();
	}
	@Override
	public boolean supportsBulkUpdate() {
		return delegate.supportsBulkUpdate();
	}
	@Override
	public boolean supportsCommonTableExpressions() {
		return delegate.supportsCommonTableExpressions();
	}
	@Override
	public boolean supportsCompareCriteriaEquals() {
		return delegate.supportsCompareCriteriaEquals();
	}
	@Override
	public boolean supportsCompareCriteriaOrdered() {
		return delegate.supportsCompareCriteriaOrdered();
	}
	@Override
	public boolean supportsCorrelatedSubqueries() {
		return delegate.supportsCorrelatedSubqueries();
	}
	@Override
	public boolean supportsExcept() {
		return delegate.supportsExcept();
	}
	@Override
	public boolean supportsExistsCriteria() {
		return delegate.supportsExistsCriteria();
	}
	@Override
	public boolean supportsFunctionsInGroupBy() {
		return delegate.supportsFunctionsInGroupBy();
	}
	@Override
	public boolean supportsGroupBy() {
		return delegate.supportsGroupBy();
	}
	@Override
	public boolean supportsHaving() {
		return delegate.supportsHaving();
	}
	@Override
	public boolean supportsInCriteria() {
		return delegate.supportsInCriteria();
	}
	@Override
	public boolean supportsInCriteriaSubquery() {
		return delegate.supportsInCriteriaSubquery();
	}
	@Override
	public boolean supportsInlineViews() {
		return delegate.supportsInlineViews();
	}
	@Override
	public boolean supportsInsertWithQueryExpression() {
		return delegate.supportsInsertWithQueryExpression();
	}
	@Override
	public boolean supportsIntersect() {
		return delegate.supportsIntersect();
	}
	@Override
	public boolean supportsIsNullCriteria() {
		return delegate.supportsIsNullCriteria();
	}
	@Override
	public boolean supportsLikeCriteria() {
		return delegate.supportsLikeCriteria();
	}
	@Override
	public boolean supportsLikeCriteriaEscapeCharacter() {
		return delegate.supportsLikeCriteriaEscapeCharacter();
	}
	@Override
	public boolean supportsNotCriteria() {
		return delegate.supportsNotCriteria();
	}
	@Override
	public boolean supportsOrCriteria() {
		return delegate.supportsOrCriteria();
	}
	@Override
	public boolean supportsOrderByNullOrdering() {
		return delegate.supportsOrderByNullOrdering();
	}
	@Override
	public boolean supportsOrderByUnrelated() {
		return delegate.supportsOrderByUnrelated();
	}
	@Override
	public boolean supportsQuantifiedCompareCriteriaAll() {
		return delegate.supportsQuantifiedCompareCriteriaAll();
	}
	@Override
	public boolean supportsQuantifiedCompareCriteriaSome() {
		return delegate.supportsQuantifiedCompareCriteriaSome();
	}
	@Override
	public boolean supportsRowLimit() {
		return delegate.supportsRowLimit();
	}
	@Override
	public boolean supportsRowOffset() {
		return delegate.supportsRowOffset();
	}
	@Override
	public boolean supportsScalarSubqueries() {
		return delegate.supportsScalarSubqueries();
	}
	@Override
	public boolean supportsSearchedCaseExpressions() {
		return delegate.supportsSearchedCaseExpressions();
	}

	Boolean supportsSelectExpression;
	@TranslatorProperty(display="Supports SELECT expressions", advanced=true)
	@Override
	public boolean supportsSelectExpression() {
		if (supportsSelectExpression != null) {
			return supportsSelectExpression;
		}
		return delegate.supportsSelectExpression();
	}
	public void setSupportsSelectExpression(boolean value) {
		supportsSelectExpression = value;
	}

	@Override
	public boolean supportsSelfJoins() {
		return delegate.supportsSelfJoins();
	}
	@Override
	public boolean supportsSetQueryOrderBy() {
		return delegate.supportsSetQueryOrderBy();
	}
	@Override
	public boolean supportsUnions() {
		return delegate.supportsUnions();
	}
	@Override
	public String toString() {
		return delegate.toString();
	}
	@Override
	public boolean useAnsiJoin() {
		return delegate.useAnsiJoin();
	}
	@Override
	public boolean equals(Object obj) {
		return delegate.equals(obj);
	}
	@Override
	public int hashCode() {
		return delegate.hashCode();
	}
	@Override
	public boolean isCopyLobs() {
		return delegate.isCopyLobs();
	}
	@Override
	public boolean supportsArrayAgg() {
		return delegate.supportsArrayAgg();
	}
	@Override
	public boolean supportsElementaryOlapOperations() {
		return delegate.supportsElementaryOlapOperations();
	}
	@Override
	public boolean supportsFormatLiteral(String literal,
			org.teiid.translator.ExecutionFactory.Format format) {
		return delegate.supportsFormatLiteral(literal, format);
	}
	@Override
	public boolean supportsLikeRegex() {
		return delegate.supportsLikeRegex();
	}
	@Override
	public boolean supportsOnlyFormatLiterals() {
		return delegate.supportsOnlyFormatLiterals();
	}
	@Override
	public boolean supportsOnlySingleTableGroupBy() {
		return delegate.supportsOnlySingleTableGroupBy();
	}
	@Override
	public boolean supportsSimilarTo() {
		return delegate.supportsSimilarTo();
	}
	@Override
	public boolean supportsWindowDistinctAggregates() {
		return delegate.supportsWindowDistinctAggregates();
	}
	@Override
	public boolean supportsWindowOrderByWithAggregates() {
		return delegate.supportsWindowOrderByWithAggregates();
	}
	@Override
	public int getMaxInCriteriaSize() {
		return delegate.getMaxInCriteriaSize();
	}
	@Override
	public org.teiid.translator.ExecutionFactory.SupportedJoinCriteria getSupportedJoinCriteria() {
		return delegate.getSupportedJoinCriteria();
	}
	@Override
	public boolean requiresCriteria() {
		return delegate.requiresCriteria();
	}
	@Override
	public boolean supportsFullOuterJoins() {
		return delegate.supportsFullOuterJoins();
	}
	@Override
	public boolean supportsInnerJoins() {
		return delegate.supportsInnerJoins();
	}
	@Override
	public boolean supportsOrderBy() {
		return delegate.supportsOrderBy();
	}
	@Override
	public boolean supportsOuterJoins() {
		return delegate.supportsOuterJoins();
	}
	@Override
	public boolean supportsSelectDistinct() {
		return delegate.supportsSelectDistinct();
	}
	
	@Override
	public int getMaxDependentInPredicates() {
		return delegate.getMaxDependentInPredicates();
	}
	@Override
	public boolean supportsAdvancedOlapOperations() {
		return delegate.supportsAdvancedOlapOperations();
	}
	@Override
	public boolean supportsSubqueryInOn() {
		return delegate.supportsSubqueryInOn();
	}
	@Override
	public boolean supportsConvert(int fromType, int toType) {
		return delegate.supportsConvert(fromType, toType);
	}
	@Override
	public boolean supportsDependentJoins() {
		return delegate.supportsDependentJoins();
	}
	@Override
	public boolean supportsOnlyLiteralComparison() {
		return delegate.supportsOnlyLiteralComparison();
	}
	@Override
	public CacheDirective getCacheDirective(Command command,
			ExecutionContext executionContext, RuntimeMetadata metadata)
			throws TranslatorException {
		return delegate.getCacheDirective(command, executionContext, metadata);
	}
	@Override
	public boolean isSourceRequiredForMetadata() {
		return delegate.isSourceRequiredForMetadata();
	}
	@Override
	public boolean isForkable() {
		return delegate.isForkable();
	}
	@Override
	public boolean supportsArrayType() {
		return delegate.supportsArrayType();
	}
	
	// EXTENSION
	// ISSUE: DV-99
	// FIXED BY: Salvatore Raunich
	// Applied solution from TEIID-2344
	// DATE: 2013.11.08
	@Override
	public boolean isSourceRequiredForCapabilities() {
		return delegate.isSourceRequiredForCapabilities();
    }
	
	@Override
	public void initCapabilities(C connection) throws TranslatorException {
		delegate.initCapabilities(connection);
    }	
	// END EXTENSION
	// EXTENSION
	// ISSUE: DVCORE-2440
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.10.18
	// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-2176,https://issues.jboss.org/browse/TEIID-2177

	@Override
	public String getNativeQueryProcedureName() {
		return delegate.getNativeQueryProcedureName();
	}	
	
	public boolean supportsNativeQueries() {
		return delegate.supportsNativeQueries();
	}
	@Override
	public ProcedureExecution createDirectExecution(List<Argument> arguments,
			Command command, ExecutionContext executionContext,
			RuntimeMetadata metadata, C connection) throws TranslatorException {
		 return delegate.createDirectExecution(arguments, command, executionContext, metadata, connection);
	}	
	// END EXTENSION
	// EXTENSION
	// ISSUE: DVCORE-2441
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.10.23
	// ADOPTED FROM: https://issues.jboss.org/browse/TEIID-247, 2166, 2151, 2234, 2581, 2571, 2369, 1386, 2226, 2233, 2224, 2225, 2257

	@Override
	public boolean supportsSelectWithoutFrom() {
		return delegate.supportsSelectWithoutFrom();
	}
	// END EXTENSION
	
	@Override
    public boolean supportsPartialFiltering() {
		return delegate.supportsPartialFiltering();
	}
	@Override
 	public boolean useBindingsForDependentJoin() {
		return delegate.useBindingsForDependentJoin();
	}
	@Override
	public Boolean supportsStringAgg() {
		return delegate.supportsStringAgg();
	}
	@Override
 	public boolean supportsFullDependentJoins() {
		return delegate.supportsFullDependentJoins();
	}
	@Override
	public boolean supportsSubqueryCommonTableExpressions() {
		return delegate.supportsSubqueryCommonTableExpressions();
    }
	@Override
	public boolean supportsLateralJoin() {
		return delegate.supportsLateralJoin();
	}
	@Override
	public boolean supportsLateralJoinCondition() {
		return delegate.supportsLateralJoinCondition();
	}
	@Override
	public boolean supportsProcedureTable() {
		return delegate.supportsProcedureTable();
	}
	@Override
	public boolean isThreadBound() {
		return delegate.isThreadBound();
	}
	@Override
	public String getCollationLocale() {
		return delegate.getCollationLocale();
	}
	@Override
 	public MetadataProcessor<C> getMetadataProcessor(){
		if(delegate != null) {
			return delegate.getMetadataProcessor();
		}
		return null;
	}

	@Override
	public boolean supportsRecursiveCommonTableExpressions() {
		return delegate.supportsRecursiveCommonTableExpressions();
	}

	@Override
 	public boolean returnsSingleUpdateCount() {
		return delegate.returnsSingleUpdateCount();
	}

	@Override
	public org.teiid.translator.ExecutionFactory.TransactionSupport getTransactionSupport() {
		return delegate.getTransactionSupport();
	}

	Boolean supportsUpsert;
 	@TranslatorProperty(display="Supports Upsert", advanced=true)
 	@Override
 	public boolean supportsUpsert() {
		if (supportsUpsert != null) {
			return supportsUpsert;
		}
		return delegate.supportsUpsert();
 	}
 	public void setSupportsUpsert(boolean value) {
		supportsUpsert = value;
 	}

	Boolean supportsSelectExpressionArrayType;
	@TranslatorProperty(display="Supports SELECT array type expressions", advanced=true)
	@Override
	public boolean supportsSelectExpressionArrayType() {
		if (supportsSelectExpressionArrayType != null) {
			return supportsSelectExpressionArrayType;
		}
		return delegate.supportsSelectExpressionArrayType();
	}
	public void setSupportsSelectExpressionArrayType(boolean value) {
		supportsSelectExpressionArrayType = value;
	}

	Boolean supportsOnlyTimestampAddLiteral;
	@TranslatorProperty(display="Supports Only TimestampAdd literal", advanced=true)
	@Override
	public boolean supportsOnlyTimestampAddLiteral() {
		if (supportsOnlyTimestampAddLiteral != null) {
			return supportsOnlyTimestampAddLiteral;
		}
		return delegate.supportsOnlyTimestampAddLiteral();
	}

	Boolean supportsMultipleOpenStatements;
 	@Override
 	public boolean supportsMultipleOpenExecutions() {
		if (supportsMultipleOpenStatements != null) {
			return supportsMultipleOpenStatements;
		}
		return delegate.supportsMultipleOpenExecutions();
 	}

	public void setSupportsMultipleOpenStatements(
 	        boolean supportsMultipleOpenStatements) {
		this.supportsMultipleOpenStatements = supportsMultipleOpenStatements;
 	}

	Boolean supportsGeographyType;
	@Override
	public boolean supportsGeographyType() {
		if (supportsGeographyType != null) {
			return supportsGeographyType;
		}
		return delegate.supportsGeographyType();
	}

	public void setSupportsGeographyType(
			boolean supportsGeographyType) {
		this.supportsGeographyType = supportsGeographyType;
	}
}
