/*-
 * ~~~~~~licensing~~~~~~
 * node-management
 * ==========
 * 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.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 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();
	}
	
}
