/*
 * Copyright (C) 2001 - 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 fr.dyade.aaa.agent;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Enumeration;

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

import fr.dyade.aaa.common.Configuration;
import fr.dyade.aaa.common.Debug;
import fr.dyade.aaa.common.monitoring.DumpAttributes;

/**
 * JMX view of AgentServer.
 */
public class SCServer implements SCServerMBean {
  public static final Logger logger = Debug.getLogger(SCServer.class.getName());
  
  public SCServer() {
  }

  public short getServerId() {
    return AgentServer.getServerId();
  }

  public String getName() {
    return AgentServer.getName();
  }

  public void start() {
    try {
      AgentServer.start();
    } catch (Throwable exc) {
    }
  }

  public void stop() {
    AgentServer.stop(false);
  }

  public void shutdown() {
    AgentServer.shutdown();
  }

  public int getStatus() {
    return AgentServer.getStatus();
  }

  public String getStatusInfo() {
    return AgentServer.getStatusInfo();
  }

  public String[] getServers() {
    Enumeration<ServerDesc> e = AgentServer.elementsServerDesc();
    String[] servers = new String[AgentServer.getServerNb()];
    StringBuffer strBuf = new StringBuffer();
    for (int i=0; e.hasMoreElements(); i++) {
      ServerDesc server = e.nextElement();
      strBuf.append("sid=").append(server.sid);
      strBuf.append(",name=").append(server.name);
      if (server.gateway == -1) {
        strBuf.append(",gateway=").append(server.gateway);
      } else {
        strBuf.append(",host=").append(server.getHostname())
          .append(':').append(server.getPort());
        strBuf.append(",active=").append(server.active);
        strBuf.append(",last=").append(server.last);
      }
      servers[i] = strBuf.toString();
      strBuf.setLength(0);
    }
    return servers;
  }
  
  @Override
  public void dumpServerState(String path) {
    dumpServerState(path, null);
  }
  
  public static void dumpServerState(String path, String cause) {
    FileWriter writer = null;
    try {
      writer = new FileWriter(path, true);
      final StringBuilder strbuf = new StringBuilder();

      if (cause != null) {
        writer.write("\n===== Dump cause =====\n\n");
        writer.write(cause);
        writer.write("\n");
      }
      
      writer.write("\n===== MBean's attributes =====\n\n");
      DumpAttributes.dumpAttributes("*:*", strbuf);
      writer.write(strbuf.toString());
      writer.flush();
      strbuf.setLength(0);

      writer.write("\n===== Thread's stack traces =====\n\n");
      
      DumpAttributes.dumpAllStackTraces(strbuf);
      writer.write(strbuf.toString());
      writer.flush();
      strbuf.setLength(0);
    } catch (IOException exc) {
      logger.log(BasicLevel.ERROR,
                 "MqttCheckActivator.dumpServerState, cannot open dump file \"" + path + "\"", exc);
    } finally {
      if (writer != null)
        try {
          writer.close();
        } catch (IOException e) {}
    }
  }

  @Override
  public void dumpAttributes(String name, String path, boolean threaddump) {
    try (FileWriter writer = new FileWriter(path, true)) {
      StringBuilder strbuf = new StringBuilder();

      DumpAttributes.dumpAttributes(name, strbuf);
      if (threaddump)
        DumpAttributes.dumpAllStackTraces(strbuf);
      writer.write(strbuf.toString());
    } catch (IOException exc) {
      logger.log(BasicLevel.ERROR,
                 "SCServer.dumpAttributes, cannot open dump file \"" + path + "\"", exc);
    }
  }
  
  public String getConfigurationProperty(String name) {
    return Configuration.getProperty(name);
  }
  
  // ********************************************************************************
  // Allows to get heap informations from JMX
  
  @Override
  public long getHeapMaxMemory() {
    return Runtime.getRuntime().maxMemory();
  }
  
  @Override
  public long getHeapTotalMemory() {
    return Runtime.getRuntime().totalMemory();
  }
  
  @Override
  public long getHeapUsedMemory() {
    return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
  }
  
  @Override
  public long getHeapFreeMemory() {
    return Runtime.getRuntime().freeMemory();
  }
  
  // ********************************************************************************
  // Allows to modify logging configuration from JMX
      
  @Override
  public void debug(String classname) {
    Debug.setDebugLevel(classname);
  }
  
  @Override
  public void info(String classname) {
    Debug.setInfoLevel(classname);
  }
  
  @Override
  public void warn(String classname) {
    Debug.setWarnLevel(classname);
  }
  
  @Override
  public void error(String classname) {
    Debug.setErrorLevel(classname);
  }
  
  @Override
  public void fatal(String classname) {
    Debug.setFatalLevel(classname);
  }
  
  @Override
  public void setLoggerLevel(String classname, String level) {
    try {
      Debug.setLoggerLevel(classname, level);
    } catch (Exception exc) {
      logger.log(BasicLevel.WARN,
                 "SCServer.setLoggerLevel: " + exc.getMessage());
    }
  }
  
  @Override
  public void clearLoggerLevel(String classname) {
    Debug.clearLevel(classname);
  }

  /**
   * Backups the content of Transaction module.
   * Produces a generic Backup/Restore file containing all living objects.
   * 
   * @param path  Directory path to store the backup.
   * @return the name of created backup file.
   * @throws Exception An error occurs during backup.
   */
  @Override
  public String backup(String path) throws Exception {
    // TODO (AF): May be it should be done in an Agent reaction.
    if (AgentServer.getTransaction() != null)
      return AgentServer.getTransaction().backup(path);
    throw new IllegalStateException("Can't backup, Transaction module is not initialized.");
  }

//  @Override
//  public void freeze(long timeout) throws InterruptedException {
//    new Thread() {
//      public void run() {
//        try {
//          if (AgentServer.getTransaction() != null)
//            AgentServer.getTransaction().freeze(timeout);
//        } catch (InterruptedException exc) {}
//      }
//    }.start();
//  }
}
