/*
 * Copyright (C) 2020 - 2025 ScalAgent Distributed Technologies
 *
 * This 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 any later version.
 * 
 * This 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA.
 *
 * Initial developer(s): ScalAgent Distributed Technologies
 * Contributor(s): 
 */
package org.ow2.joram.tools.jmscheck;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import javax.naming.InitialContext;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

import fr.dyade.aaa.common.Debug;
import fr.dyade.aaa.util.management.MXWrapper;

final class JMSConnectorStatus implements JMSConnectorStatusMBean {
  private static final Logger logger = Debug.getLogger(JMSConnectorStatus.class.getName());
  
  private JMSConnectorCheck check;

  @Override
  public int getStatus() {
    return check.getStatus();
  }

  @Override
  public String getStatusInfo() {
    return check.getStatusInfo();
  }
  
  @Override
  public int getNbTry() {
    return check.getNbTry();
  }
  
  @Override
  public int getNbFailures() {
    return check.getNbFailures();
  }

  @Override
  public String getErrorMsg() {
    return check.getErrorMsg();
  }
  
  @Override
  public long getLatencyConnect() {
    return check.getLatencyConnect();
  }

  @Override
  public String getLastConnectTime() {
    return check.getLastConnectTime();
  }

  @Override
  public long getLatencyPubSub() {
    return check.getLatencyConnect();
  }

  /** The period of time between 2 checks (in seconds). */
  private int period = 60;

  @Override
  public int getPeriod() {
    return period;
  }

  @Override
  public void setPeriod(int period) {
    try {
      if (period < 5)
        period = 5;
      if (period < (2* check.getTimeOut()))
        period = 2* check.getTimeOut();
      this.period = period;
      schedule();
    } catch (Exception e) {
      logger.log(BasicLevel.WARN, "Cannot change timer period: " + e.getMessage());
    }
  }
  
  @Override
  public int getTimeOut() {
    return check.getTimeOut();
  }

  @Override
  public void setTimeOut(int timeOut) {
    check.setTimeOut(timeOut);
  }

  /** Root component */
  JMSStatus jmsStatus;
  
  @Override
  public String getName() {
    return check.getCFName();
  }
  
  ScheduledFuture<?> callableHandle;

  /**
   * Creates a JMS connectors healthcheck component.
   * 
   * @param jmsStatus Root component.
   * @param cfname    JNDI name of the ConnectionFactory to use.
   * @param ictx      JNDI context allowing to get the ConnectionFactory.
   * @param user      User name for authentication, if null uses the ConnectioNfactory default.
   * @param pass      Password for authentication, if null uses the ConnectioNfactory default.
   * @param qname     Name of the queue used to check the JMS behavior. It is an internal not a JNDI name, this destination is created by the
   *                  module.
   * @param period    Period (in seconds) between 2 attempts of check.
   * @param timeOut   Maximum amount of time to wait either the connection or the message.
   */
  JMSConnectorStatus(JMSStatus jmsStatus,
                            String cfname,
                            InitialContext ictx,
                            String user, String pass,
                            String qname,
                            int period, int timeOut) {
    this.jmsStatus = jmsStatus;
    
    this.check = new JMSConnectorCheck(cfname, ictx, user, pass, qname, timeOut);
    this.period = period;

    mbeanName = JMSStatus.mbeanName + ",cf=" + cfname;    
  }

  // --------------------------------------------------------------------------------
  // JMS Health-check
  // --------------------------------------------------------------------------------

  private void schedule() {
    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "JMSConnectorStatus(" + getName() + ").schedule: " + period);
    
    if (callableHandle != null && !callableHandle.isCancelled()) {
      callableHandle.cancel(true);
    }
    if (period > 0) {
      callableHandle = JMSStatus.scheduler.scheduleAtFixedRate(new Runnable() {
        public void run() {
          try {
            check.check();
            JMSStatus.checkDump(check.getCFName(), check.getStatus());
          } catch (Throwable t) {
            logger.log(BasicLevel.WARN, "JMSConnectorStatus(" + getName() + ").schedule", t);
          }
        }
      },  period, period, TimeUnit.SECONDS);
    }
  }
  
  // --------------------------------------------------------------------------------
  // Life cycle
  // --------------------------------------------------------------------------------

  void start() {
    schedule();
    registerMBean();
  }

  void stop() {
    unregisterMBean();
    if (callableHandle != null)
      callableHandle.cancel(true);
  }

  // --------------------------------------------------------------------------------
  // JMX handling
  // --------------------------------------------------------------------------------

  private String mbeanName;

  private void registerMBean() {
    try {
      MXWrapper.registerMBean(this, jmsStatus.getName(), mbeanName);
    } catch (Exception e) {
      logger.log(BasicLevel.WARN, "registerMBean: " + mbeanName, e);
    }
  }

  private void unregisterMBean() {
    try {
      MXWrapper.unregisterMBean(jmsStatus.getName(), mbeanName);
    } catch (Exception e) {
      logger.log(BasicLevel.WARN, "unregisterMBean: " + mbeanName, e);
    }
  }
}
