/*-
 * ~~~~~~licensing~~~~~~
 * node-management
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
package ru.entaxy.esb.platform.core.management.node.impl;

import java.io.IOException;

import javax.management.DynamicMBean;
import javax.management.MBeanRegistration;
import javax.management.NotCompliantMBeanException;

import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.component.annotations.ServiceScope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.entaxy.esb.platform.base.management.core.ManagementCore;
import ru.entaxy.esb.platform.base.management.core.api.AnnotatedMBean;
import ru.entaxy.esb.platform.core.management.node.ClusterLocalNodeDataProvider;
import ru.entaxy.esb.platform.core.management.node.NodeDataProviderAware;
import ru.entaxy.esb.platform.core.management.node.LocalNodeMBean;
import ru.entaxy.esb.platform.core.management.node.NodeDataProvider;
import ru.entaxy.esb.platform.core.management.node.NodeMBean;
import ru.entaxy.platform.base.support.CommonUtils;

@Component(
		service = {DynamicMBean.class, MBeanRegistration.class, LocalNodeMBean.class, NodeDataProviderAware.class},
		property = {ManagementCore.JMX_OBJECTNAME + "=" + ManagementCore.Q_LOCAL_NODE_S},
		scope = ServiceScope.SINGLETON,
		immediate = true
		)
public class LocalNodeMBeanImpl extends AnnotatedMBean<LocalNodeMBean> implements LocalNodeMBean, NodeDataProviderAware {

	private static final Logger log = LoggerFactory.getLogger(LocalNodeMBeanImpl.class);
	
	public static final String ENTAXY_PLATFORM_FEATURE_NAME = "entaxy-platform";

	public static final String ENTAXY_UI_FEATURE_NAME = "entaxy-ui";
	
	@Reference(cardinality = ReferenceCardinality.MANDATORY)
	FeaturesService featuresService;

	@Reference(cardinality = ReferenceCardinality.MANDATORY)
	ConfigurationAdmin configurationAdmin;
	
	protected ClusterLocalNodeDataProvider clusterLocalNodeDataProvider = null;

	@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, 
			policyOption = ReferencePolicyOption.GREEDY, unbind = "unsetClusterLocalNodeDataProvider")
	public void setClusterLocalNodeDataProvider(ClusterLocalNodeDataProvider clusterCurrentNodeMBean) {
		this.clusterLocalNodeDataProvider = clusterCurrentNodeMBean;
	}
	public void unsetClusterLocalNodeDataProvider(ClusterLocalNodeDataProvider clusterCurrentNodeMBean) {
		this.clusterLocalNodeDataProvider = null;
	}
	
	
	protected LocalMBeanDataProvider dataProvider = new LocalMBeanDataProvider();
	
	public LocalNodeMBeanImpl() throws NotCompliantMBeanException {
		super(LocalNodeMBean.class);
	}

	protected String getInstalledFeatureVersion(String featureName) {
		String result = ""; 
		try {
			Feature[] features = this.featuresService.getFeatures(featureName);
			
			for (int i=0; i<features.length; i++) {
				if (this.featuresService.isInstalled(features[i])) {
					result = features[i].getVersion();
					break;
				}
			}
			
		} catch (Exception e) {
			log.error("Error getting feature: " + featureName, e);
		}
		return result;
	}
	
	protected String getConfigurationValue(String pid, String name) {
		String result = "";

		Configuration config;
		try {
			config = LocalNodeMBeanImpl.this.configurationAdmin.getConfiguration(pid);
		} catch (IOException e) {
			log.error("Error getting configuration: " + pid, e);
			return result;
		}
		if (config == null)
			return "";
		return (String) config.getProperties().get(name);
	}
	
	protected class LocalMBeanDataProvider implements NodeDataProvider {

		@Override
		public String getEntaxyPlatformVersion() {
			return LocalNodeMBeanImpl.this.getInstalledFeatureVersion(ENTAXY_PLATFORM_FEATURE_NAME);
		}

		@Override
		public String getHttpPort() {
			return LocalNodeMBeanImpl.this.getConfigurationValue("org.ops4j.pax.web", "org.osgi.service.http.port");
		}

		@Override
		public String getSshPort() {
			return LocalNodeMBeanImpl.this.getConfigurationValue("org.apache.karaf.shell", "sshPort");
		}

		@Override
		public boolean isUIEnabled() {
			return CommonUtils.isValid(LocalNodeMBeanImpl.this.getInstalledFeatureVersion(ENTAXY_UI_FEATURE_NAME));
		}

		@Override
		public boolean isClusterEnabled() {
			return false;
		}

		@Override
		public String getClusterIP() {
			return null;
		}

		@Override
		public String getClusterPort() {
			return null;
		}
		
		@Override
		public String getNodeId() {
			return null;
		}
		
		@Override
		public boolean isConsumerStarted() {
			return false;
		}

		@Override
		public boolean isProducerStarted() {
			return false;
		}
	}
	
	@Override
	public NodeDataProvider getDataProvider() {
		return this.dataProvider;
	}
	
	protected NodeDataProvider getActiveDataProvider() {
		if (this.clusterLocalNodeDataProvider == null)
			return this.dataProvider;
		return this.clusterLocalNodeDataProvider;
	}
	
	@Override
	public String getEntaxyPlatformVersion() {
		return getActiveDataProvider().getEntaxyPlatformVersion();
	}

	@Override
	public String getHttpPort() {
		return getActiveDataProvider().getHttpPort();
	}

	@Override
	public String getSshPort() {
		return getActiveDataProvider().getSshPort();
	}

	@Override
	public boolean isUIEnabled() {
		return getActiveDataProvider().isUIEnabled();
	}

	@Override
	public boolean isClusterEnabled() {
		return getActiveDataProvider().isClusterEnabled();
	}

	@Override
	public String getClusterIP() {
		return getActiveDataProvider().getClusterIP();
	}

	@Override
	public String getClusterPort() {
		return getActiveDataProvider().getClusterPort();
	}
	
	@Override
	public String getNodeId() {
		return getActiveDataProvider().getNodeId();
	}
	
	@Override
	public boolean isConsumerStarted() {
		return getActiveDataProvider().isConsumerStarted();
	}
	
	@Override
	public boolean isProducerStarted() {
		return getActiveDataProvider().isProducerStarted();
	}
}
