/*-
 * ~~~~~~licensing~~~~~~
 * object-producing-config-support
 * ==========
 * Copyright (C) 2020 - 2022 EmDev LLC
 * ==========
 * Licensed 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.
 * ~~~~~~/licensing~~~~~~
 */
package ru.entaxy.platform.core.producer.config;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.entaxy.platform.base.objects.EntaxyObject;
import ru.entaxy.platform.base.objects.factory.EntaxyFactory;
import ru.entaxy.platform.base.objects.factory.EntaxyFactory.FieldInfo;
import ru.entaxy.platform.core.producer.api.EntaxyWrappedFactory;

public class ObjectConfig {

	private static final Logger log = LoggerFactory.getLogger(ObjectConfig.class);
	
	public static final String CONFIG_OBJECT_TYPE = "entaxy.runtime.config";
	
	public static final String TARGET_FACTORY_FIELD_NAME = "targetObjectFactoryId";
	public static final String TARGET_TYPE_FIELD_NAME = "targetObjectType";
	public static final String TARGET_ID_FIELD_NAME = "targetObjectId";	
	public static final String TARGET_OUTPUT_FIELD_NAME = "targetObjectOutput";
	
	public static final String CONFIG_PROPERTIES_FIELD_NAME = "configuredProperties";
	public static final String CONFIG_FACTORY_FIELD_NAME = "configuredFactoryId";
	public static final String CONFIG_TYPE_FIELD_NAME = "configuredType";
	public static final String CONFIG_ID_FIELD_NAME = "configured";	
	public static final String CONFIG_OUTPUT_FIELD_NAME = "configuredOutput";

	public static final String CONFIG_PID_FIELD_NAME = "configurationPid";
	public static final String CONFIG_PLACEHOLDER_PREFIX_FIELD_NAME = "placeholderPrefix";
	
	
	public static final String CONFIG_FIELD_NAME = "##config";
	public static final String CONFIGURABLE_ATTRIBUTE_NAME = "configurable";
	public static final String PROPERTIES_BACKUP_FIELD = EntaxyObject.FIELDS.PROPERTIES + "_backup";

	public static final String DIRECT_VALUE_ONLY_ATTR_NAME = "directValueOnly";
	
	public static final String CONFIGURABLES_FIELD_NAME = "configurables";
	public static final String IMMUTABLES_FIELD_NAME = "immutables";
	
	public static final String HEADER_OBJECT_CONFIG_PID = "Entaxy-Generated-Object-Config-Pid";
	
	public static String getConfigurationPid(String objectId, String type) {
		return reduceType(type) + "." + objectId.replace("-", "_");
	}
	
	public static String reduceType(String type) {
		return type.replace(EntaxyObject.OBJECT_TYPES.ENTAXY_RUNTIME_TYPE_PREFIX, "e_r_").replace("-", "_");
	}
	
	public static String getConfigurationPrefix(String objectId, String type) {
		return "$" + getConfigurationPid(objectId, type) + "{";
	}
	
	public static boolean isConfigurable(EntaxyFactory factory, String outputType, String fieldName) {
		Optional<FieldInfo> fi = factory.getOutputByType(outputType).getFields().stream().filter(f -> f.getName().equals(fieldName)).findFirst();
		if (!fi.isPresent())
			return false;
		if (!fi.get().getJsonOrigin().has(CONFIGURABLE_ATTRIBUTE_NAME))
			return true;
		try {
			return fi.get().getJsonOrigin().get(CONFIGURABLE_ATTRIBUTE_NAME).getAsBoolean();
		} catch (Exception e) {
			return true;
		}
	}

	public static void backupProperties(Map<String, Object> parameters) {
		backupProperties(parameters, EntaxyObject.FIELDS.PROPERTIES);
	}
	@SuppressWarnings("unchecked")
	public static void backupProperties(Map<String, Object> parameters, String fieldName) {
		if (!parameters.containsKey(fieldName))
			return;
		Map<String, Object> backup = new HashMap<>();
		backup.putAll((Map<String, Object>)parameters.get(fieldName));
		parameters.put(ObjectConfig.PROPERTIES_BACKUP_FIELD, backup);
	}

	public static void restoreBackupProperties(Map<String, Object> parameters) {
		restoreBackupProperties(parameters, EntaxyObject.FIELDS.PROPERTIES);
	}
	public static void restoreBackupProperties(Map<String, Object> parameters, String fieldName) {
		if (!parameters.containsKey(ObjectConfig.PROPERTIES_BACKUP_FIELD))
			return;
		parameters.put(fieldName, parameters.get(ObjectConfig.PROPERTIES_BACKUP_FIELD));
	}

	public static void removeConfigData(Map<String, Object> parameters) {
		removeConfigData(parameters, EntaxyObject.FIELDS.PROPERTIES);
	}
	@SuppressWarnings("unchecked")
	public static void removeConfigData(Map<String, Object> parameters, String fieldName) {
		if (!parameters.containsKey(fieldName))
			return;
		((Map<String, Object>)parameters.get(fieldName)).remove(CONFIG_FIELD_NAME);
	}

	public static Map<String, Object> getTargetConfigMap(EntaxyFactory factory, String outputType, String fieldName
			, Map<String, Object> configurables, Map<String, Object> immutables){
		Optional<FieldInfo> fi = factory.getOutputByType(outputType).getFields().stream().filter(f -> f.getName().equals(fieldName)).findFirst();
		if (!fi.isPresent()) {
			log.debug("FIELD NOT FOUND: " + fieldName);
			return null;
		}
		FieldInfo field = fi.get();
		boolean isConfigurable = true;
		log.info("\n FIELDNAME:: " + fieldName + " -> " + field.getJsonOrigin());
		if (field.getJsonOrigin().has(CONFIGURABLE_ATTRIBUTE_NAME))
			try {
				isConfigurable =  field.getJsonOrigin().get(CONFIGURABLE_ATTRIBUTE_NAME).getAsBoolean();
			} catch (Exception e) {
				isConfigurable = true; 
			}
		if (!isConfigurable) {
			log.debug("FIELD NOT CONFIGURABLE: " + fieldName);
			return null;
		}
		if (field.isImmutable())
			return immutables;
		return configurables;
	}
}
