/*
 * This work is released into the Public Domain under the
 * terms of the Creative Commons CC0 1.0 Universal license.
 * https://creativecommons.org/publicdomain/zero/1.0/
 */
package pityoulish.jrmi.follow;

import java.io.IOException;

import pityoulish.cmdline.Command;
import pityoulish.cmdline.CommandHandlerBase;

import pityoulish.jrmi.api.MessageList;
import pityoulish.jrmi.api.RemoteMessageBoard;


/**
 * Command handler for the Follow-the-Board client.
 * The client supports only a single command.
 */
//@@@ implement a base class for single-command handlers
public class FollowTheBoardHandler
  extends CommandHandlerBase<FollowTheBoardHandler.OnlyCommand>
{
  protected final RegistryBackendHandler regBackend;

  protected final DataFormatter userOutput;


  /** The polling interval, in seconds. */
  protected int pollingSeconds;

  protected static final int DEFAULT_POLLING_SECONDS = 8;

  /** The marker from which to list subsequent messages. Initially null. */
  protected String listMarker;


  /**
   * List of the only command.
   * <ul>
   * <li><b>follow</b> the board messages</li>
   * </ul>
   */
  public enum OnlyCommand implements Command
  {
    FOLLOW;

    public final int getMinArgs() { return 0; }
    public final int getMaxArgs() { return 1; }
  }



  /**
   * Creates a new command dispatcher.
   *
   * @param rbh   the backend handler
   * @param df    the data formatter for printing messages
   */
  public FollowTheBoardHandler(RegistryBackendHandler rbh,
                               DataFormatter df)
  {
    super(OnlyCommand.class);

    if (rbh == null)
       throw new NullPointerException("RegistryBackendHandler");
    if (df == null)
       throw new NullPointerException("DataFormatter");

    regBackend = rbh;
    userOutput = df;
  }


  /**
   * Obtains the name of the only command.
   */
  public final String getCommandName()
  {
    return OnlyCommand.FOLLOW.name();
  }


  // non-javadoc, see interface CommandHandler
  public void describeUsage(Appendable app)
    throws IOException
  {
    app.append(Catalog.COMMAND_USAGE.lookup());
  }


  // non-javadoc, see base class
  protected int handleCommand(OnlyCommand cmd, String... args)
    throws Exception
  {
    if (args.length > 0)
     {
       int interval = parsePollingInterval(args[0]);
       if (interval > 0)
          pollingSeconds = interval;
       else
          return 2; // error status
     }
    else
     {
       pollingSeconds = DEFAULT_POLLING_SECONDS;
     }

    pollForMessages();
    // never reached

    return 0; // status OK
  }


  /**
   * Polls for messages, forever.
   * Actually, until an exception is thrown, for whatever reason.
   */
  protected void pollForMessages()
    throws Exception
  {
    while (true)
     {
       listAvailableMessages();

       try {
         Thread.sleep(pollingSeconds * 1000L);
       } catch (InterruptedException ix) {
         // ignore
       }
     }
  }


  /**
   * Lists as many messages as are available.
   * If {@link #listMarker} is set, messages are listed from there.
   * The marker is updated here, for subsequent calls.
   */
  protected void listAvailableMessages()
    throws Exception
  {
    RemoteMessageBoard rmb = regBackend.getRemoteMessageBoard();

    final int BATCH_SIZE = 127;

    boolean more = true;
    while (more)
     {
       MessageList msglist = rmb.listMessages(BATCH_SIZE, listMarker);
       userOutput.printMessageList(msglist);

       more = (msglist.getMessages().size() >= BATCH_SIZE);
       listMarker = msglist.getMarker();
     }
  }


  /**
   * Parses the polling interval.
   * In case of a problem, an error message is printed and 0 returned.
   *
   * @param arg   the string to parse
   *
   * @return   the polling interval in seconds, or 0 if invalid
   */
  protected int parsePollingInterval(String arg)
  {
    int interval = 0;

    try {
      interval = Integer.parseInt(arg);

      if (interval < 1)
       {
         System.err.println(Catalog.CMDLINE_BAD_INTERVAL_1.format(arg));
         interval = 0;
       }

    } catch (Exception x) {
      System.err.println(Catalog.CMDLINE_BAD_INTERVAL_1.format(arg));
      System.err.println(x);
      interval = 0;
    }

    return interval;
  }

}


@@ -291,24 +291,30 @@
 ish.cmdline.
+Single
 CommandHandl
@@ -321,16 +321,16 @@
 erBase;%0A
-
 %0Aimport 
@@ -521,65 +521,8 @@
  */%0A
-//@@@ implement a base class for single-command handlers%0A
 publ
@@ -551,18 +551,16 @@
 dHandler
-%0A 
  extends
@@ -560,16 +560,22 @@
 extends 
+Single
 CommandH
@@ -588,43 +588,8 @@
 Base
-%3CFollowTheBoardHandler.OnlyCommand%3E
 %0A%7B%0A 
@@ -935,284 +935,8 @@
 ;%0A%0A%0A
-  /**%0A   * List of the only command.%0A   * %3Cul%3E%0A   * %3Cli%3E%3Cb%3Efollow%3C/b%3E the board messages%3C/li%3E%0A   * %3C/ul%3E%0A   */%0A  public enum OnlyCommand implements Command%0A  %7B%0A    FOLLOW;%0A%0A    public final int getMinArgs() %7B return 0; %7D%0A    public final int getMaxArgs() %7B return 1; %7D%0A  %7D%0A%0A%0A%0A
   /*
@@ -968,16 +968,13 @@
 and 
-dispatch
+handl
 er.%0A
@@ -1207,27 +1207,34 @@
 per(
-OnlyCommand.class);
+0, 1); // minArgs, maxArgs
 %0A%0A  
@@ -1447,150 +1447,8 @@
 %7D%0A%0A%0A
-  /**%0A   * Obtains the name of the only command.%0A   */%0A  public final String getCommandName()%0A  %7B%0A    return OnlyCommand.FOLLOW.name();%0A  %7D%0A%0A%0A
   //
@@ -1648,16 +1648,16 @@
 e class%0A
+
   protec
@@ -1682,25 +1682,8 @@
 and(
-OnlyCommand cmd, 
 Stri

use SingleCommandHandlerBase in FtB client