/*-
 * ~~~~~~licensing~~~~~~
 * profile-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.base.management.core.utils;

import javax.management.AttributeChangeNotification;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;

import ru.entaxy.esb.platform.base.management.core.api.AnnotatedMBean;
import ru.entaxy.platform.base.support.osgi.tracker.BundleContextAware;

public class BundleAwareMBeanImpl<T extends BundleAwareManagedObject, I>
        extends AnnotatedMBean<I>
        implements NotificationBroadcaster, NotificationEmitter, BundleAwareMBean, BundleContextAware {

    protected T managedObject;

    protected BundleContext bundleContext;

    protected long sequenceNumber = 0;

    protected NotificationBroadcasterSupport emitter;

    public BundleAwareMBeanImpl(Class<I> clazz, T managedObject) throws NotCompliantMBeanException {
        super(clazz);
        this.managedObject = managedObject;
        this.emitter = new NotificationBroadcasterSupport(prepareNotificationInfo());
    }

    // BEGIN: notification stuff

    protected MBeanNotificationInfo[] prepareNotificationInfo() {
        String[] types = new String[] {
            AttributeChangeNotification.ATTRIBUTE_CHANGE
        };
        String name = AttributeChangeNotification.class.getName();
        String description = "An attribute of this MBean has changed";
        MBeanNotificationInfo info =
                new MBeanNotificationInfo(types, name, description);
        return new MBeanNotificationInfo[] {info};
    }

    @Override
    public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback)
            throws ListenerNotFoundException {
        this.emitter.removeNotificationListener(listener, filter, handback);
    }

    @Override
    public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback)
            throws IllegalArgumentException {
        this.emitter.addNotificationListener(listener, filter, handback);
    }

    @Override
    public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
        this.emitter.removeNotificationListener(listener);
    }

    @Override
    public MBeanNotificationInfo[] getNotificationInfo() {
        return this.emitter == null
                ? prepareNotificationInfo()
                : emitter.getNotificationInfo();
    }

    // END: notification stuff

    @Override
    public String getBundleState() {
        return managedObject.getBundleState();
    }

    @Override
    public long getBundleId() {
        return managedObject.getBundleId();
    }

    @Override
    public String getBundleSymbolicName() {
        return managedObject.getBundleSymbolicName();
    }

    @Override
    public BundleContext getBundleContext() {
        return bundleContext;
    }

    @Override
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }

    @Override
    public void refreshBundleInfo() {

        // track bundleState

        AttributeChangeTracker tracker = refreshBundleState();
        if (tracker.isChanged()) {
            // send notification
            Notification n = new AttributeChangeNotification(
                    this,
                    this.sequenceNumber++,
                    System.currentTimeMillis(),
                    "bundleState changed",
                    "bundleState",
                    "String",
                    tracker.oldValue,
                    tracker.newValue);
            this.emitter.sendNotification(n);
        }

    }

    protected AttributeChangeTracker refreshBundleState() {
        Bundle b = FrameworkUtil.getBundle(getClass()).getBundleContext().getBundle(getBundleId());

        AttributeChangeTracker tracker = new AttributeChangeTracker();
        tracker.oldValue(this.managedObject.getBundleState());
        this.managedObject.bundleState(b != null ? b.getState() : Bundle.UNINSTALLED);
        tracker.newValue(this.managedObject.getBundleState());

        return tracker;
    }



}
