
// Banner.java
// Andreas Deininger
// from https://picocli.info/quick-guide.html
// Modified by Andrew Davison, ad@coe.psu.ac.th, June 2023

/* Generates a large text banner either across 
   the terminal, or down it. Originally called ASCIIArt.

  Usage: Banner [-dhV] [-s=<style>] [-z=<fontSize>] [<text>...]
  Prints an ASCII banner.
      [<text>...]            Text to be displayed.
  -d, --down                 Print down the screen
  -h, --help                 Show this help message and exit.
  -s, --font-style=<style>   <style> values: plain, bold, italics
  -V, --version              Print version information and exit.
  -z, --font-size=<fontSize> Font size (default: 12)


  Picocli features:
    * named options and positional parameters
    * POSIX-style grouped short options 
    * automatic help and version options
    * default values
    * list of enum candidates
    * exit codes
    * conversion of command line arguments to data types


  Usage examples:
   > compile Banner.java

   > run Banner --help
   > run Banner -V
   > run Banner
   > run Banner -d

   > run Banner -z=30 "Hi"
   > run Banner -d -z=30 "Hello world"

   > run Banner -d -z=50 -s=bold "Hello world"
   > run Banner -z=30 -s=italics "Hi"
*/

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.concurrent.*;

import picocli.CommandLine;
import picocli.CommandLine.*;


@Command(name = "Banner", 
         mixinStandardHelpOptions = true,
         version = "Banner 1.0",
         description = "Prints an ASCII text banner.")
public class Banner implements Callable<Integer>
{
  @Option(names = { "-z", "--font-size" }, 
          description = "Font size (default: ${DEFAULT-VALUE})")
  private int fontSize = 12;   // conversion from string; default value

  @Option(names = { "-d", "--down" }, 
          description = "Print down the screen")
  private boolean isDownPage = false;

  @Option(names = {"-s", "--font-style"}, 
          description = "<style> values: ${COMPLETION-CANDIDATES}")
  private Styles style = Styles.plain;

  public enum Styles { plain, bold, italics }

  @Parameters(paramLabel = "<text>", 
              description = "Text to be displayed.")
  private String[] words = { "Hello,", "picocli" }; 


  public Integer call()
  { 
    Font font;
    if (style == Styles.plain)
      font = new Font("Dialog", Font.PLAIN, fontSize);
    else if (style == Styles.bold)
      font = new Font("Dialog", Font.BOLD, fontSize);
    else
      font = new Font("Dialog", Font.ITALIC, fontSize);

    BufferedImage im = drawText(String.join(" ", words), font);
    if (isDownPage)
      im = rotate90(im);
    printImage(im);

    return 0;
  } // end of call()


  private BufferedImage drawText(String msg, Font font)
  // draw the string in an image using the specified font
  {
    StringMetrics sm = new StringMetrics(font);
       // calculate the required image dimensions
    int textWidth = sm.getWidth(msg);
    int textHeight = sm.getHeight(msg);

    int width = (int) Math.round((double)textWidth*1.1);
    int height = (int) Math.round((double)textHeight*1.1);
                          // add a little extra space

    BufferedImage im =
        new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2d = im.createGraphics();
    g2d.setPaint(Color.WHITE);   // white background
    g2d.fillRect(0, 0, width, height);

    g2d.setPaint(Color.BLACK);
    g2d.setFont(font);
    FontMetrics fm = g2d.getFontMetrics(font);
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                         RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d.drawString(msg, (width-textWidth)/2, 
                        (height-textHeight)/2 + fm.getAscent());
    g2d.dispose();

    return im;
  }  // end of drawText()



  private BufferedImage rotate90(BufferedImage im)
  // rotate the image clockwise by 90 degrees
  {
    int width = im.getWidth();
    int height = im.getHeight();
    
    int rWidth = height;
    int rHeight = width;
    BufferedImage rotIm = new BufferedImage(
                                   rWidth, rHeight, im.getType());
    Graphics2D g2d = rotIm.createGraphics();
    g2d.setPaint(Color.WHITE);
    g2d.fillRect(0, 0, rWidth, rHeight);

    AffineTransform at =  AffineTransform.getRotateInstance(
                             Math.toRadians(90), rWidth/2, rHeight/2);
    int x = (rWidth-width)/2;
    int y = (rHeight-height)/2;
    at.translate(x, y);
    g2d.drawRenderedImage(im, at);
    g2d.dispose();

    return rotIm;
  }  // end of rotate90()


  private void printImage(BufferedImage im)
  // convert each image pixel to one of three characters
  {
    int width = im.getWidth();
    int height = im.getHeight();
    for (int y = 0; y < height; y++) {
      StringBuilder sb = new StringBuilder();
      for (int x = 0; x < width; x++)   // examine colors
        sb.append(im.getRGB(x, y) == 0xFFFFFFFF ? " " : 
                  im.getRGB(x, y) == 0xFF000000 ? "#" : "*");
      System.out.println(sb);
    }
  } // end of printImage()


  // ---------------------------------------------

  public static void main(String[] args)
  {
    int exitCode = new CommandLine(new Banner()).execute(args);
    System.exit(exitCode);
  }

}  // end of Banner class
