/**
 * Copyright (c) 2007-2012 EBM WebSourcing, 2012-2024 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.bc.quartz;

import java.util.Properties;
import java.util.logging.Level;

import javax.jbi.JBIException;

import org.ow2.petals.component.framework.api.exception.PEtALSCDKException;
import org.ow2.petals.component.framework.bc.AbstractBindingComponent;
import org.ow2.petals.component.framework.bc.BindingComponentServiceUnitManager;
import org.ow2.petals.component.framework.listener.AbstractExternalListener;
import org.ow2.petals.component.framework.su.AbstractServiceUnitManager;
import org.ow2.petals.component.framework.su.ServiceUnitDataHandler;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.simpl.SimpleThreadPool;

/**
 * 
 * Apparently the Quartz SE is actually a BC...
 * 
 * @author Adrien LOUIS - EBM WebSourcing
 */
public class QuartzBc extends AbstractBindingComponent {

    /**
     * The Quartz scheduler.
     */
    private Scheduler quartzScheduler;

    /**
     * @return the Quartz scheduler
     */
    public Scheduler getQuartzScheduler() {
        return this.quartzScheduler;
    }

    @Override
    public void doInit() throws JBIException {
        try {
            final Properties schedulerCfg = new Properties();
            schedulerCfg.put(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, "Petals BC Quartz Scheduler");
            schedulerCfg.put(StdSchedulerFactory.PROP_SCHED_JMX_EXPORT, String.valueOf(true));
            schedulerCfg.put(StdSchedulerFactory.PROP_SCHED_JMX_EXPORT, String.valueOf(true));
            schedulerCfg.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, SimpleThreadPool.class.getName());
            schedulerCfg.put(StdSchedulerFactory.PROP_THREAD_POOL_PREFIX + ".threadCount", "10");

            final StdSchedulerFactory schedulerFactory = new StdSchedulerFactory(schedulerCfg);
            this.quartzScheduler = schedulerFactory.getScheduler();

        } catch (final SchedulerException e) {
            throw new JBIException("An error occurred while creating the Quartz scheduler.", e);
        }
    }

    @Override
    public void doStart() throws JBIException {
        try {
            this.quartzScheduler.start();

        } catch (final SchedulerException e) {
            throw new JBIException("An error occurred while starting the Quartz scheduler.", e);
        }
    }

    @Override
    public void doStop() throws JBIException {
        try {
            this.quartzScheduler.standby();

        } catch (final SchedulerException e) {
            throw new JBIException("An error occurred while stopping the Quartz scheduler.", e);
        }
    }

    @Override
    public void doShutdown() throws JBIException {
        try {
            if (this.quartzScheduler != null) {
                this.quartzScheduler.shutdown(false);
            }

        } catch (final SchedulerException e) {
            throw new JBIException("An error occurred while shutdowning the Quartz scheduler.", e);
        }
    }

    @Override
    protected AbstractServiceUnitManager createServiceUnitManager() {
        return new BindingComponentServiceUnitManager(this) {
            @Override
            protected AbstractExternalListener createExternalListener() {
                return new QuartzExternalListener();
            }

            @Override
            protected void onPlaceHolderValuesReloaded() {
                super.onPlaceHolderValuesReloaded();

                // TODO: Should be improved to:
                // - avoid to stop/start to have a continous processing
                // - update cron expression only if updated
                for (final ServiceUnitDataHandler sudh : this.getServiceUnitDataHandlers()) {
                    try {
                        getLogger().log(Level.CONFIG, "Reloading configuration of service unit ''{0}''", sudh.getName());
                        // Stop cron configuration for this su
                        this.stopInternal(sudh);
                        // start new cron configuration for this su, with new placeholder
                        this.startInternal(sudh);
                        getLogger().log(Level.CONFIG, "Configuration of service unit ''{0}'' reloaded", sudh.getName());
                    } catch (PEtALSCDKException e) {
                        // Error on reloading
                        getLogger().log(Level.WARNING, e,
                                () -> "Unexpected error on reloading place holder of " + sudh.getName());
                    }
                }
            }
        };
    }
}
