/*-
 * ~~~~~~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.artifact.capabilities;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import ru.entaxy.platform.base.support.CommonUtils;
import ru.entaxy.platform.core.artifact.ArtifactManifest;

public class ManifestCapabilityHelper {

	protected ArtifactManifest manifest;

	protected Map<String, CapabilityDescriptorImpl> requiredCapabilities = new HashMap<>();
	protected Map<String, CapabilityDescriptorImpl> providedCapabilities = new HashMap<>();
	
	public ManifestCapabilityHelper(ArtifactManifest manifest) {
		super();
		this.manifest = manifest;
		this.load();
	}

	protected void load() {
		String existing = this.manifest.getCustomAttributes().get(CapabilityDescriptor.HEADER_PROVIDE_CAPABILITY);
		if (CommonUtils.isValid(existing)) {
			List<CapabilityDescriptorImpl> list = parse(existing);
			for (CapabilityDescriptorImpl c: list)
				addProvidedCapability(c);
		}
		existing = this.manifest.getCustomAttributes().get(CapabilityDescriptor.HEADER_REQUIRE_CAPABILITY);
		if (CommonUtils.isValid(existing)) {
			List<CapabilityDescriptorImpl> list = parse(existing);
			for (CapabilityDescriptorImpl c: list)
				addRequiredCapability(c);
		}
	}
	
	protected void addProvidedCapability(CapabilityDescriptorImpl capabilityDescriptorImpl) {
		if (capabilityDescriptorImpl == null)
			return;
		this.providedCapabilities.put(capabilityDescriptorImpl.getNamespace(), capabilityDescriptorImpl);
	}

	protected void addRequiredCapability(CapabilityDescriptorImpl capabilityDescriptorImpl) {
		if (capabilityDescriptorImpl == null)
			return;
		this.requiredCapabilities.put(capabilityDescriptorImpl.getNamespace(), capabilityDescriptorImpl);
	}
	
	protected List<CapabilityDescriptorImpl> parse(String capabilities) {
		List<CapabilityDescriptorImpl> result = new ArrayList<>();
		String[] caps = capabilities.split(",");
		for (int i=0; i< caps.length; i++)
			if (CommonUtils.isValid(caps[i])) {
				result.add(parseCapability(caps[i]));
			}
		return result;
	}
	
	protected CapabilityDescriptorImpl parseCapability(String capability) {
		String[] parsed = capability.split(";");
		CapabilityDescriptorImpl result = new CapabilityDescriptorImpl(parsed[0].trim());
		for (int i=1; i<parsed.length; i++) {
			result.parseAttribute(parsed[i]);
		}
		return result;
	}
	
	public List<CapabilityDescriptor> getProvidedCapabilities(){
		return this.providedCapabilities.values().stream()
				.map(c -> (CapabilityDescriptor)c)
				.collect(Collectors.toList());
	}

	public List<CapabilityDescriptor> getRequiredCapabilities(){
		return this.requiredCapabilities.values().stream()
				.map(c -> (CapabilityDescriptor)c)
				.collect(Collectors.toList());
	}
	
	public boolean isCapabilityProvided(String namespace) {
		return this.providedCapabilities.containsKey(namespace);
	}

	public boolean isCapabilityRequired(String namespace) {
		return this.requiredCapabilities.containsKey(namespace);
	}
	
	public CapabilityDescriptor provideCapability(String namespace) {
		if (!this.providedCapabilities.containsKey(namespace)) 
			this.providedCapabilities.put(namespace, new CapabilityDescriptorImpl(namespace));
		return this.providedCapabilities.get(namespace);
	}

	public CapabilityDescriptor requireCapability(String namespace) {
		if (!this.requiredCapabilities.containsKey(namespace)) 
			this.requiredCapabilities.put(namespace, new CapabilityDescriptorImpl(namespace));
		return this.requiredCapabilities.get(namespace);
	}
	
	public void save() {
		this.manifest.getCustomAttributes().put(CapabilityDescriptor.HEADER_PROVIDE_CAPABILITY, 
			this.providedCapabilities.values().stream()
				.map(
					cap -> (
						cap.getNamespace()
						+ ";"
						+ cap.getAttributesAsString()
					)
				)
				.collect(Collectors.joining(","))
				);
	}
	
}
