/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.sysml.conf;

import org.apache.hadoop.mapred.JobConf;
import org.apache.sysml.conf.CompilerConfig.ConfigType;
import org.apache.sysml.runtime.matrix.mapred.MRConfigurationNames;
import org.apache.sysml.runtime.matrix.mapred.MRJobConfiguration;
import org.apache.sysml.utils.lite.LiteCheck;



/**
 * Singleton for accessing the parsed and merged system configuration.
 * 
 * NOTE: parallel execution of multiple DML scripts (in the same JVM) with different configurations  
 *       would require changes/extensions of this class. 
 */
public class ConfigurationManager 
{
	/** Global cached job conf for read-only operations	*/
	private static JobConf _rJob = null; 
	
	/** Global DML configuration (read or defaults) */
	private static DMLConfig _dmlconf = null; 
	
	/** Local DML configuration for thread-local config updates */
	private static ThreadLocalDMLConfig _ldmlconf = new ThreadLocalDMLConfig();
	
    /** Global compiler configuration (defaults) */
    private static CompilerConfig _cconf = null;
	
    /** Local compiler configuration for thead-local config updates */
    private static ThreadLocalCompilerConfig _lcconf = new ThreadLocalCompilerConfig();
    
    //global static initialization
	static {
		_rJob = new JobConf();
		
		//initialization after job conf in order to prevent cyclic initialization issues 
		//ConfigManager -> OptimizerUtils -> InfrastructureAnalyer -> ConfigManager 
 		_dmlconf = new DMLConfig();
		_cconf = new CompilerConfig();

		if (LiteCheck.isLite() && MRJobConfiguration.USE_BINARYBLOCK_SERIALIZATION) {
			// to be able to write using binary format
			// WritableSerialization -> MatrixIndexes
			// BinaryBlockSerialization -> MatrixBlock
			_rJob.set(MRConfigurationNames.IO_SERIALIZATIONS,
					"org.apache.hadoop.io.serializer.WritableSerialization,org.apache.sysml.runtime.io.BinaryBlockSerialization");
		}
	}
	
	
    /**
     * Returns a cached JobConf object, intended for global use by all operations 
     * with read-only access to job conf. This prevents to read the hadoop conf files
     * over and over again from classpath. However, 
     * 
     * @return the cached JobConf
     */
	public static JobConf getCachedJobConf() {
		return _rJob;
	}
	
	public static void setCachedJobConf(JobConf job) {
		_rJob = job;
	}
	
	/**
	 * Sets a global configuration as a basis for any thread-local configurations.
	 * NOTE: This global configuration should never be accessed directly but only
	 * through its thread-local derivatives. 
	 * 
	 * @param conf the configuration
	 */
	public synchronized static void setGlobalConfig( DMLConfig conf ) {
		_dmlconf = conf;
		
		//reinitialize thread-local dml configs w/ _dmlconf
		_ldmlconf = new ThreadLocalDMLConfig();
	}
	
	/**
	 * Sets the current thread-local dml configuration to the given config.
	 * 
	 * @param conf the configuration
	 */
	public static void setLocalConfig( DMLConfig conf ) {
		_ldmlconf.set(conf);
	}
	
	/**
	 * Gets the current thread-local dml configuration.
	 * 
	 * @return the dml configuration
	 */
	public static DMLConfig getDMLConfig() {
		return _ldmlconf.get();
	}
	
	public synchronized static void setGlobalConfig( CompilerConfig conf ) {
		_cconf = conf;
		
		//reinitialize thread-local compiler configs w/ _cconf
		_lcconf = new ThreadLocalCompilerConfig();
	}
	
	/**
	 * Sets the current thread-local compiler configuration to the given config.
	 * 
	 * @param conf the compiler configuration
	 */
	public static void setLocalConfig( CompilerConfig conf ) {
		_lcconf.set(conf);
	}
	
	/**
	 * Removes the thread-local dml and compiler configurations, leading to
	 * a reinitialization on the next get unless set in between.
	 */
	public static void clearLocalConfigs() {
		_ldmlconf.remove();
		_lcconf.remove();
	}
	
	/**
	 * Gets the current thread-local compiler configuration.
	 * 
	 * @return the compiler configuration
	 */
	public static CompilerConfig getCompilerConfig() {
		return _lcconf.get();
	}
	
	/**
	 * Get a boolean compiler config in a robust manner,
	 * returning false if config not existing.
	 * 
	 * @param key config type
	 * @return compiler config flag
	 */
	public static boolean getCompilerConfigFlag(ConfigType key) {
		CompilerConfig cconf = getCompilerConfig();
		return (cconf!=null) ? cconf.getBool(key) : false;
	}
	
	/////////////////////////////////////
	// shorthand methods for common local configurations
	
	public static String getScratchSpace() {
		return getDMLConfig().getTextValue(DMLConfig.SCRATCH_SPACE);
	}
	
	public static int getBlocksize() {
		return getCompilerConfig().getInt(ConfigType.BLOCK_SIZE);
	}
	
	public static int getNumReducers() {
		return getDMLConfig().getIntValue(DMLConfig.NUM_REDUCERS);
	}
	
	public static boolean isDynamicRecompilation() {
		return getCompilerConfigFlag(ConfigType.ALLOW_DYN_RECOMPILATION);
	}
	
	public static boolean isParallelMatrixOperations() {
		return getCompilerConfigFlag(ConfigType.PARALLEL_CP_MATRIX_OPERATIONS);
	}
	
	public static boolean isParallelParFor() {
		return getCompilerConfigFlag(ConfigType.PARALLEL_LOCAL_OR_REMOTE_PARFOR);
	}
	
	public static boolean isCodegenEnabled() {
		return getDMLConfig().getBooleanValue(DMLConfig.CODEGEN)
			|| getCompilerConfigFlag(ConfigType.CODEGEN_ENABLED);
	}
	
	
	///////////////////////////////////////
	// Thread-local classes
	
	private static class ThreadLocalDMLConfig extends ThreadLocal<DMLConfig> {
		@Override 
		protected DMLConfig initialValue() { 
			//currently initialize by reference to avoid unnecessary deep copy via clone.
			if( _dmlconf != null )
				return _dmlconf; 
			return null;
		}
	}
	
	private static class ThreadLocalCompilerConfig extends ThreadLocal<CompilerConfig> {
		@Override 
		protected CompilerConfig initialValue() { 
			if( _cconf != null )
				return _cconf.clone();
			return null;
		}
	}
}

@@ -877,16 +877,55 @@
 obConf;%0A
+import org.apache.sysml.api.DMLScript;%0A
 import o
@@ -6004,32 +6004,33 @@
 ed() %7B%0A%09%09return 
+(
 getDMLConfig().g
@@ -6118,22 +6118,237 @@
 ENABLED)
-;%0A%09%7D%0A%09
+)%0A%09%09%09&& !DMLScript.USE_ACCELERATOR;%0A%09%09//note: until codegen is supported for the GPU backend, we globally%0A%09%09//disable codegen if operations are forced to the GPU to avoid%0A%09%09//a counter-productive impact on performance.%0A%09%7D
 %0A%09%0A%09////

Disable codegen for config w/ forced gpu operations