/*-
 * ~~~~~~licensing~~~~~~
 * profile-management
 * ==========
 * Copyright (C) 2020 - 2023 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.profile.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.CollectionType;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ServiceScope;
import org.osgi.util.tracker.BundleTracker;
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.profile.ConnectorMBean;
import ru.entaxy.esb.platform.core.management.profile.DefaultRouteMBean;
import ru.entaxy.esb.platform.core.management.profile.ProfileMBean;
import ru.entaxy.esb.platform.core.management.profile.ProfilesMBean;
import ru.entaxy.esb.platform.core.management.profile.impl.connector.DeployedConnectorCustomizer;
import ru.entaxy.esb.platform.core.management.profile.impl.connector.ManagedConnector;
import ru.entaxy.esb.platform.core.management.profile.impl.connector.ManagedConnectorsListener;
import ru.entaxy.esb.platform.core.management.profile.impl.helper.Helpers;
import ru.entaxy.esb.platform.core.management.profile.impl.route.DeployedDefaultRouteCustomizer;
import ru.entaxy.esb.platform.core.management.profile.impl.route.ManagedRoute;
import ru.entaxy.esb.platform.core.management.profile.impl.route.ManagedRoutesListener;
import ru.entaxy.platform.base.support.osgi.tracker.BundleTrackerUtils;
import ru.entaxy.platform.base.support.osgi.tracker.filter.BundleCapabilityFilter;

@Component(service = { ProfilesMBean.class, DynamicMBean.class, MBeanRegistration.class }, property = {
		ManagementCore.JMX_OBJECTNAME + "=" + ManagementCore.Q_RUNTIME_S + "," + ProfilesMBean.PROFILES_KEY + "="
				+ ProfilesMBean.PROFILES_KEY_VALUE }, scope = ServiceScope.SINGLETON, immediate = true)
public class ProfilesMBeanImpl extends AnnotatedMBean<ProfilesMBean>
		implements ProfilesMBean {

	private static final Logger log = LoggerFactory.getLogger(ProfilesMBeanImpl.class);

	protected BundleContext bundleContext;

	protected BundleTracker<List<ManagedProfile>> tracker;

	protected BundleTracker<List<ManagedRoute>> routeTracker;
	
	protected BundleTracker<List<ManagedConnector>> connectorTracker; 

	@Reference (cardinality = ReferenceCardinality.MANDATORY
			, service = Helpers.class
			, collectionType = CollectionType.SERVICE)
	Helpers helpers;
	
	public ProfilesMBeanImpl() throws NotCompliantMBeanException {
		super(ProfilesMBean.class);
	}

	protected static class ManagedProfileDescriptor {

		ManagedProfile profile;
		ServiceRegistration<ProfileMBean> registration;

	}

	protected Map<String, ManagedProfileDescriptor> managed = new HashMap<>();

	@Activate
	public void activate(ComponentContext componentContext) {
		this.bundleContext = componentContext.getBundleContext();

		//tracker = new DeployedProfileTrackerOld(bundleContext, this);
		tracker = BundleTrackerUtils.<List<ManagedProfile>>createBuilder()
				.customizer(
						(new DeployedProfileCustomizer())
						.listener(new ManagedProfilesListener(bundleContext, this.helpers))
					)
				.addFilter(
						(new BundleCapabilityFilter()).namespace(ProfileMBean.CAPABILITY_NAMESPACE)
					)
				.bundleContext(bundleContext)
				.bundleState(Bundle.ACTIVE | Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.STOPPING)
				.get();
		tracker.open();

		routeTracker = BundleTrackerUtils.<List<ManagedRoute>>createBuilder()
				.customizer(
						(new DeployedDefaultRouteCustomizer())
						.listener(new ManagedRoutesListener(bundleContext, helpers))
					)
				.addFilter(
						(new BundleCapabilityFilter()).namespace(DefaultRouteMBean.CAPABILITY_NAMESPACE)
					)
				.bundleContext(bundleContext)
				.bundleState(Bundle.ACTIVE | Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.STOPPING)
				.get();
		routeTracker.open();
		
		connectorTracker = BundleTrackerUtils.<List<ManagedConnector>>createBuilder()
				.customizer(
						(new DeployedConnectorCustomizer())
						.listener(new ManagedConnectorsListener(bundleContext, this.helpers))
					)
				.addFilter(
						(new BundleCapabilityFilter()).namespace(ConnectorMBean.CAPABILITY_NAMESPACE)
					)
				.bundleContext(bundleContext)
				.bundleState(Bundle.ACTIVE | Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.STOPPING)
				.get();
		connectorTracker.open();
	}

	@Deactivate
	public void deactivate() {
		tracker.close();
		routeTracker.close();
		connectorTracker.close();
	}

	/*
	 * ProfileManager implementation
	 */
	
	@Override
	public void createProfile(String id, String name, String description) throws Exception {
		this.helpers.profileHelper.createProfile(id, name, description);
	}

	@Override
	public String getProfileConfig(String idOrName) throws Exception {
		return this.helpers.entaxyObjectService.findObject(idOrName, "entaxy.runtime.profile").getConfiguration();
	}

	@Override
	public void startProfile(String idOrName) throws Exception {
		this.helpers.profileHelper.startProfile(idOrName);
	}

	@Override
	public void stopProfile(String idOrName) throws Exception {
		this.helpers.profileHelper.stopProfile(idOrName);
	}

	@Override
	public void uninstallProfile(String idOrName) throws Exception {
		this.helpers.profileHelper.uninstallProfile(idOrName);
	}
	
}
