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

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.jar.Manifest;

import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class BlueprintManifest implements ArtifactManifest {

	private static final Logger log = LoggerFactory.getLogger(BlueprintManifest.class);
	
	protected Artifact artifact;
	
	protected Manifest manifest = new Manifest();
	
	boolean isLoaded = false;
	
	protected Map<String, String> customAttributes = new HashMap<>();
	
	public BlueprintManifest(Artifact artifact) {
		super();
		this.artifact = artifact;
	}
	
	public void load(Document document) {
		this.isLoaded = false;
		manifest = new Manifest();

		manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
		manifest.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
		manifest.getMainAttributes().putValue(Constants.DYNAMICIMPORT_PACKAGE, "*");
        
		manifest.getMainAttributes().putValue(HEADERS.ENTAXY_BUNDLE, "true");
		manifest.getMainAttributes().putValue(HEADERS.ENTAXY_RUNTIME, "true");
		
		NodeList l = document.getElementsByTagName("manifest");
        if (l != null) {
            for (int i = 0; i < l.getLength(); i++) {
                Element e = (Element) l.item(i);
                String text = e.getTextContent();
                Properties props = new Properties();
                try {
					props.load(new ByteArrayInputStream(text.trim().getBytes()));
				} catch (IOException e1) {
					log.error("Error loading manifest", e1);
				}
                Enumeration en = props.propertyNames();
                while (en.hasMoreElements()) {
                    String k = (String) en.nextElement();
                    String v = props.getProperty(k);
                    manifest.getMainAttributes().putValue(k, v);
                }
                e.getParentNode().removeChild(e);
            }
        }
        this.isLoaded = true;
	}
	
	protected void appendCustoms(Document document) {
		for (Entry<String, String> entry: this.customAttributes.entrySet())
			this.manifest.getMainAttributes().putValue(entry.getKey(), entry.getValue());
	}
	
	protected void beforeSave(Document document) {
	    this.manifest.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME
	    		, this.artifact.getCoordinates().getGroupId() + "." + this.artifact.getCoordinates().getArtifactId());
	    this.manifest.getMainAttributes().putValue(Constants.BUNDLE_NAME
	    		, this.artifact.getCoordinates().getGroupId() + "." + this.artifact.getCoordinates().getArtifactId());
	    this.manifest.getMainAttributes().putValue(Constants.BUNDLE_VERSION
	    		, this.artifact.getCoordinates().getVersion().replaceAll("-", "."));
	    appendCustoms(document);
	}
	
	public void save(Document document) {
		beforeSave(document);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        String manifestContent = "";
        try {
        	this.manifest.write(bos);
			manifestContent = bos.toString(StandardCharsets.ISO_8859_1);
			manifestContent = manifestContent.replaceAll("\r", "").replaceAll("\n ", "");
		} catch (IOException e) {
			log.error("Error saving manifest to document", e);
		}
        
        // remove old manifests
		NodeList l = document.getElementsByTagName("manifest");
        if (l != null)
            for (int i = 0; i < l.getLength(); i++) {
            	Element e = (Element) l.item(i);
            	e.getParentNode().removeChild(e);
            }

        
        Element manifest = document.createElementNS("http://karaf.apache.org/xmlns/deployer/blueprint/v1.0.0", "manifest");
        manifest.setTextContent(manifestContent);
        document.getDocumentElement().insertBefore(manifest
        		, document.getDocumentElement().getFirstChild());
		
	}
	
	@Override
	public Map<String, String> getCustomAttributes() {
		return this.customAttributes;
	}

	public boolean isLoaded() {
		return isLoaded;
	}
	
}
