/*-
 * ~~~~~~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 ru.entaxy.platform.base.support.CommonUtils;
import ru.entaxy.platform.core.artifact.Blueprint;
import ru.entaxy.platform.core.artifact.DeployedArtifact;
import ru.entaxy.platform.core.artifact.installer.builder.ClusterInstaller;
import ru.entaxy.platform.core.artifact.installer.builder.InstallationResult;
import ru.entaxy.platform.core.artifact.installer.builder.Installer;
import ru.entaxy.platform.core.artifact.installer.builder.LocalInstaller;
import ru.entaxy.platform.core.artifact.installer.builder.typed.BlueprintInstaller;
import ru.entaxy.platform.core.artifact.service.ArtifactService;
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.CommandInstructions;
import ru.entaxy.platform.core.producer.executor.support.ArtifactsHelper;
import ru.entaxy.platform.core.producer.executor.support.DeployedArtifactList;
import ru.entaxy.platform.core.producer.executor.support.InstallationResultList;

@CommandExecutor(id = "install", predecessors = "deploy")
public class Install extends AbstractCommandExecutor {

	public static final String INSTALL_LOCAL_INSTRUCTION = "installLocal";
	public static final String UPDATE_INSTRUCTION = "update";
	public static final String INSTALL_ONLY_IF_MISSING_INSTRUCTION = "installOnlyIfMissing";

	public Install(EntaxyProducerService entaxyProducerService) {
		super(entaxyProducerService);
	}

	@Override
	protected boolean doExecute(ProducerResult currentResult, CommandResult commandResult,
			Map<String, Object> instructions) throws Exception {

		CommandInstructions commandInstructions = new CommandInstructions(instructions);
		
		boolean installLocal = 
				commandInstructions.has(INSTALL_LOCAL_INSTRUCTION)
				?commandInstructions.getBoolean(INSTALL_LOCAL_INSTRUCTION)
				:false;
		
		boolean installOnlyIfMissing =
				commandInstructions.has(INSTALL_ONLY_IF_MISSING_INSTRUCTION)
				?commandInstructions.getBoolean(INSTALL_ONLY_IF_MISSING_INSTRUCTION)
				:false;
		
		String update = 
				commandInstructions.has(UPDATE_INSTRUCTION)
				?commandInstructions.getString(UPDATE_INSTRUCTION)
				:null;
		
		Object installLocalValue = instructions.get(INSTALL_LOCAL_INSTRUCTION);
		if (installLocalValue != null)
			if (installLocalValue instanceof Boolean)
				installLocal = (Boolean)installLocalValue;
		
		DeployedArtifactList deployedArtifactList = currentResult.findResultObject(DeployedArtifactList.class);
		InstallationResultList installationResultList = new InstallationResultList();
		
		ArtifactService artifactService = ArtifactsHelper.getInstance().getArtifactService();
		
		for (DeployedArtifact da: deployedArtifactList) {
			
			InstallationResult result = null;
			
			Installer<?> installer = null;
			
			String artifactUpdate = update;
			
			printOutput("-> Installing artifact: [" + da.getArtifact().getCoordinates().toString() + "]");
			if (installLocal) {
				LocalInstaller localInstaller =  artifactService.installers().local()
						.artifact(da);
				installer = localInstaller;
				printOutput("-> Installing locally");
			} else {
				ClusterInstaller clusterInstaller = artifactService.installers().cluster()
					.artifact(da);
				installer = clusterInstaller;
				printOutput("-> Installing clustered");
			}

			// TODO add support for other types when they appear
			if (da.getArtifact().getCategory().equals(Blueprint.ARTIFACT_CATEGORY_BLUEPRINT)) {
				// we're installing blueprint
				printOutput("-> Installing: " + da.getArtifact().getCategory());
				BlueprintInstaller blueprintInstaller = installer.typed(BlueprintInstaller.class);
				if (installOnlyIfMissing)
					blueprintInstaller.installOnlyIfMissing();
				if (artifactUpdate != null) {
					if (!CommonUtils.isValid(artifactUpdate)) {
						artifactUpdate = da
	        					.getArtifact().getProperties()
	        					.getOrDefault(Constants.BUNDLE_SYMBOLICNAME, "")
	        					.toString();
					}
					blueprintInstaller.update(artifactUpdate);
				}
				result = blueprintInstaller.start().install();
			} else {
				printOutput("-> Unknown category: " + da.getArtifact().getCategory());
			}
			
			if (result != null) {
				for (String key: da.getArtifact().getProperties().keySet())
					result.getProperties().putIfAbsent(key, da.getArtifact().getProperties().get(key));
				// TODO imrove Coordinates: add "asMap" method
				result.getProperties().put("artifact.artifactId", da.getArtifact().getCoordinates().getArtifactId());
				result.getProperties().put("artifact.groupId", da.getArtifact().getCoordinates().getGroupId());
				result.getProperties().put("artifact.version", da.getArtifact().getCoordinates().getVersion());
				result.getProperties().put("artifact.type", da.getArtifact().getCoordinates().getType());
				result.getProperties().put("artifact.classifier", da.getArtifact().getCoordinates().getClassifier());
				installationResultList.add(result);
			}
		}
		
		commandResult.resultObject(installationResultList);
		
		return true;
	}

}
