/*-
 * ~~~~~~licensing~~~~~~
 * artifact-management
 * ==========
 * Copyright (C) 2020 - 2021 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;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.camel.tooling.model.Strings;

import ru.entaxy.platform.core.artifact.annotation.ArtifactSupport;
import ru.entaxy.platform.core.artifact.capabilities.CapabilityDescriptor;
import ru.entaxy.platform.core.artifact.impl.CapabilityDescriptorImpl;

public class DefaultArtifact implements Artifact {

	protected ArtifactCoordinates coordinates;

	protected ArtifactSupport artifactSupport = null;
	
	protected Object content = null;
	
	protected String category = Artifact.ARTIFACT_CATEGORY_UNKNOWN;
	
	protected Map<String, Object> properties = new HashMap<>(); 
	
	protected List<Class<?>> supportedContentClasses = new ArrayList<>();
	
	protected Map<String, CapabilityDescriptorImpl> requiredCapabilities = new HashMap<>();
	protected Map<String, CapabilityDescriptorImpl> providedCapabilities = new HashMap<>();
	
	public DefaultArtifact() {
		this.coordinates = new ArtifactCoordinates();
		this.artifactSupport = this.getClass().getAnnotation(ArtifactSupport.class);
		initArtifact();
	}
	
	protected void initArtifact() {
		if (artifactSupport != null) {
			this.coordinates.type(artifactSupport.defaultArtifactType());
			this.coordinates.classifier(artifactSupport.defaultArtifactClassifier());
			this.setCategory(artifactSupport.supportedCategory());
			if (this.artifactSupport.supportedContentClasses() != null)
				for (int i=0; i<this.artifactSupport.supportedContentClasses().length; i++)
					this.supportedContentClasses.add(this.artifactSupport.supportedContentClasses()[i]);
		}
	}
	
	@Override
	public ArtifactCoordinates getCoordinates() {
		return coordinates;
	}

	public Object getContent() {
		return content;
	}

	public void setContent(Object content) {
		if (content == null)
			setNullContent();
		else {
			if (artifactSupport != null) {
				checkSetContent(content);
			} else 
				this.content = content;
		}
	}
	
	protected void setNullContent() {
		this.content = null;
	}
	
	protected void checkSetContent(Object content) {
		// TODO throw exception if content suites none of the supported classes
		
		if (this.supportedContentClasses.contains(content.getClass()))
			this.content = content;
		
		/*
		 * Class<?>[] supportedContentTypes = Arrays.copyOf(
		 * this.artifactSupport.supportedContentClasses(),
		 * this.artifactSupport.supportedContentClasses().length); for (int i=0;
		 * i<supportedContentTypes.length; i++) { if
		 * (supportedContentTypes[i].isAssignableFrom(content.getClass())) this.content
		 * = content; break; }
		 */	}
	
	@Override
	public String getCategory() {
		return this.category;
	}

	public void setCategory(String category) {
		if (!Strings.isNullOrEmpty(category))
			this.category = category;
		else
			this.category = Artifact.ARTIFACT_CATEGORY_UNKNOWN;
	}
	
	@Override
	public void toFile(File destination) {
		if (this.content != null) {
			try {
				FileWriter writer = new FileWriter(destination);
				writer.write(this.content.toString());
				writer.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public byte[] asByteArray() {
		return null;
	}
	
	@Override
	public Map<String, Object> getProperties() {
		return properties;
	}

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

	@Override
	public CapabilityDescriptor requireCapability(String namespace) {
		if (!this.requiredCapabilities.containsKey(namespace)) 
			this.requiredCapabilities.put(namespace, new CapabilityDescriptorImpl(namespace));
		return this.requiredCapabilities.get(namespace);
	}
	
	protected String getRequiredCapabilitiesValue() {
		return getCapabilitiesValue(requiredCapabilities);
	}

	protected String getProvidedCapabilitiesValue() {
		return getCapabilitiesValue(providedCapabilities);
	}
	
	protected String getCapabilitiesValue(Map<String, CapabilityDescriptorImpl> data) {
		String result = "";
		for (Map.Entry<String, CapabilityDescriptorImpl> entry: data.entrySet()) {
			if (!result.isEmpty())
				result += ",";
			result += entry.getKey();
			String attributes = entry.getValue().getAttributesAsString();
			if (!attributes.isEmpty())
				result += ";" + attributes;
		}
		return result;
	}
}
