/*-
 * ~~~~~~licensing~~~~~~
 * test-producers
 * ==========
 * 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.executor.commands;

import java.util.Map;

import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.entaxy.esb.platform.runtime.base.connecting.generator.Generated;
import ru.entaxy.platform.base.support.CommonUtils;
import ru.entaxy.platform.core.artifact.Artifact;
import ru.entaxy.platform.core.artifact.ArtifactManifest;
import ru.entaxy.platform.core.artifact.Artifacts;
import ru.entaxy.platform.core.artifact.Manifested;
import ru.entaxy.platform.core.artifact.capabilities.ManifestCapabilityHelper;
import ru.entaxy.platform.base.objects.EntaxyObject.FIELDS;
import ru.entaxy.platform.base.objects.EntaxyObject.HEADERS;
import ru.entaxy.platform.core.producer.api.EntaxyProducerService;
import ru.entaxy.platform.core.producer.api.ProducerResult;
import ru.entaxy.platform.core.producer.api.ProducerResult.CommandResult;
import ru.entaxy.platform.core.producer.executor.AbstractCommandExecutor;
import ru.entaxy.platform.core.producer.executor.CommandExecutor;
import ru.entaxy.platform.core.producer.executor.generationmodel.GeneratedHeaders;
import ru.entaxy.platform.core.producer.executor.generationmodel.GeneratedList;
import ru.entaxy.platform.core.producer.executor.support.ArtifactList;

@CommandExecutor(id = "build", predecessors = {"generate"})
public class Build extends AbstractCommandExecutor {

	private static final Logger log = LoggerFactory.getLogger(Build.class);
	
	public Build(EntaxyProducerService entaxyProducerService) {
		super(entaxyProducerService);
	}

	@Override
	protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
			Map<String, Object> instructions) throws Exception {
		printOutput("\n\t == BUILDING ==\n");
		GeneratedList generated = currentResult.findResultObject(GeneratedList.class);
		if (generated == null) {
			log.info("Nothing to generate");
			return true;
		}
		
		ArtifactList artifactList = new ArtifactList();
		
		for (Generated g: generated) {
			if (g == null)
				continue;
			Artifact artifact = Artifacts.fromGenerated(g);
			if ((artifact == null) || Artifact.ARTIFACT_CATEGORY_UNKNOWN.equals(artifact.getCategory()) 
					|| !CommonUtils.isValid(artifact.getCategory())) {
				log.info("Artifact is not buildable");
				continue;
			}
			log.info("Built artifact of category [{}]", artifact.getCategory());
			Map<String, String> headers = GeneratedHeaders.getHeaders(g.getProperties()).getAsStringMap();
			
			String mainObjectValue = headers.get(HEADERS.MAIN_OBJECT); 
			if (!CommonUtils.isValid(mainObjectValue))
				throw new Exception("Main object not found");
			String[] mainObjectData = mainObjectValue.split(":");
			if (mainObjectData.length<2)
				throw new Exception("Main object not complete: [" + mainObjectValue + "]");
			
			String versionPolicy = g.getProperties().getOrDefault(
					EntaxyProducerService.INSTRUCTIONS.ARTIFACT.VERSION_POLICY, 
					instructions.getOrDefault(
							EntaxyProducerService.INSTRUCTIONS.ARTIFACT.VERSION_POLICY
							, ""))
					.toString();
			String timestamp = g.getProperties().getOrDefault(
					EntaxyProducerService.INSTRUCTIONS.ARTIFACT.TIMESTAMP, 
					instructions.getOrDefault(
							EntaxyProducerService.INSTRUCTIONS.ARTIFACT.TIMESTAMP
							, ""))
					.toString();
			artifact.getCoordinates()
				.groupId(mainObjectData[1])
				.artifactId(mainObjectData[0])
				.version("1")
				.versionPolicy(versionPolicy)
				.timestamp(timestamp);
			
			if (artifact instanceof Manifested) {
				ArtifactManifest manifest = ((Manifested)artifact).getManifest();
				manifest.getCustomAttributes().putAll(headers);
				
				// Generate provided capabilities for every included object
				ManifestCapabilityHelper helper = new ManifestCapabilityHelper(manifest);
				
				String objectsValue = headers.getOrDefault(HEADERS.GENERATED_OBJECTS, "");
				if (CommonUtils.isValid(objectsValue)) {
					String[] objects = objectsValue.split(",");  
					
					for (int i=0; i<objects.length; i++) {
						String[] objectData = objects[i].split(":");
						if (objectData.length<2)
							continue;
						String objectId = objectData[0];
						String objectType = objectData[1];
						if (!CommonUtils.isValid(objectId) || !CommonUtils.isValid(objectType))
							continue;
						objectId = objectId.trim();
						objectType = objectType.trim();
						Map<String, Object> attributes = null;
						if (g.getProperties().containsKey(FIELDS.FIELDS_TO_PUBLISH)) {
							Object map = g.getProperties().get(FIELDS.FIELDS_TO_PUBLISH);
							if (map != null) {
								attributes = (Map<String, Object>)((Map<String, Object>)map).get(objectId);
							}
						}
						helper.provideCapability(objectType).attributes(attributes);
					}
					
					helper.save();
					
				}
			}
			artifact.getProperties().putAll(g.getProperties());
			// TODO get value from manifest
			// ArtifactManifest must be improved to provide read access to all attributes
			if (!artifact.getProperties().containsKey(Constants.BUNDLE_SYMBOLICNAME)) {
				artifact.getProperties().put(Constants.BUNDLE_SYMBOLICNAME
						, artifact.getCoordinates().getGroupId() 
							+ "." + artifact.getCoordinates().getArtifactId());
			}
			artifactList.add(artifact);
			printOutput("\n\t == " + artifact.getCoordinates().toString() + " ==\n");
			printOutput(new String(artifact.asByteArray()));
			printOutput("\n\t == \n");
		}
		
		commandResult.resultObject(artifactList);
		
		return true;
	}

}
