#!/usr/bin/env bash

# CUPS filter file for Ricoh DDST printers
# Author: madlynx (github.com/madlynx)
# Last change: 18.08.2020 by mishta-real (https://github.com/mishta-real)


# Debug mode: change to "yes" to enable (printer won't print)
DEBUG="no"


# CONSTANTS
# End-of-line for PJL (CRLF)
readonly EOL=$(printf \\r\\n)

# Command line parameters
readonly JOB_ID=$1          # Job ID
readonly USER_NAME=$2       # User who ran the job
readonly FILE_NAME=$3       # File to print
readonly COPIES_NUMBER=$4   # Number of copies to print
readonly OPTIONS=$5         # Job parameters

# Temporary directory, not world-readable/writable, with unpredictable name
readonly TMP_DIR="$(mktemp -d --suffix=$JOB_ID)"

# Date of printing
readonly PRINT_DATE=$(date "+%Y/%m/%d %H:%M:%S")

function log() {
  if [[ $DEBUG == "yes" ]]; then
    echo "$@" | logger -t "$0[$$]"
  fi
}

function stop() {
  log "Stop stop page"
  echo "stop" > "$TMP_DIR"/999999999-page.pbm
}

function flush_pjl_header() {
  log "Flushing PJL header ..."

  cat <<EOF
%-12345X@PJL$EOL
@PJL SET TIMESTAMP=$PRINT_DATE$EOL
@PJL SET FILENAME=$FILE_NAME$EOL
@PJL SET COMPRESS=JBIG$EOL
@PJL SET USERNAME=$USER_NAME$EOL
@PJL SET COVER=OFF$EOL
@PJL SET HOLD=OFF$EOL
EOF

  log "Flushed PJL header."
}

function flush_pjl_footer() {
  log "Flushing PJL footer ..."

  cat <<EOF
@PJL EOJ$EOL
%-12345X
EOF

  log "Flushed PJL footer."
}

function kill_tmpdir_process() {
  pid=$(pgrep -f "$TMP_DIR")

  if [[ -n $pid ]]; then
    log "Killing process $pid ..."
    kill "$pid"
    log "Killed process $pid."
  fi
}

function flush_page_header() {
  log "Flushing page header ..."

  cat <<EOF
@PJL SET PAGESTATUS=START$EOL
@PJL SET COPIES=$COPIES_NUMBER$EOL
@PJL SET MEDIASOURCE=$mediasource$EOL
@PJL SET MEDIATYPE=PLAINRECYCLE$EOL
@PJL SET PAPER=$pagesize$EOL
@PJL SET PAPERWIDTH=$width$EOL
@PJL SET PAPERLENGTH=$height$EOL
@PJL SET RESOLUTION=$resolution$EOL
@PJL SET IMAGELEN=$image_size$EOL
EOF

  log "Flushed page header."
}

function flush_page_footer() {
  log "Flushing page footer ..."

  cat <<EOF
@PJL SET DOTCOUNT=$dots$EOL
@PJL SET PAGESTATUS=END$EOL
EOF

  log "Flushed page footer."
}

function flush_image() {
  log "Flushing image $page ..."

  cat "$TMP_DIR"/raster.jbig

  log "Flushed image $page."
}

function convert_to_pbmraw() {
  log "Converting document to pages ..."

  # Converting from PostScript to PS-monochrome, then to PBM per page.
  gs -dQUIET -dBATCH -dNOPAUSE -dSAFER -r"$resolution" -sDEVICE=ps2write -o - - \
    | gs -dQUIET -dBATCH -dNOPAUSE -dSAFER -r"$resolution" -sDEVICE=pbmraw -o "$TMP_DIR/%03d-page.pbm" --permit-file-write="$TMP_DIR/*" -

  log "Conversion to pages is complete."
}

function convert_to_jbig() {
  log "Converting to JBIG ..."

  # Converting page to JBIG format
  # (parameters are very special for this printer!)
  pbmtojbg -p 72 -o 3 -m 0 -q < "$TMP_DIR"/"$page" > "$TMP_DIR"/raster.jbig

  log "Conversion to JBIG is complete."
}

function get_image_size() {
  log "Getting image size ..."

  image_size=$(wc -c < "$TMP_DIR"/raster.jbig)

  log "The size is $image_size"
}

function get_image_parameters() {
  log "Getting image parameters ..."

  width=$(identify -format "%w" "$TMP_DIR"/"$page")
  height=$(identify -format "%h" "$TMP_DIR"/"$page")

  # https://github.com/madlynx/ricoh-sp100/issues/45
  average_color=$(identify -format "%[fx:mean]" "$TMP_DIR"/"$page")
  dots=$(echo "($width * $height * (1 - $average_color)) / 1" | bc)
  dots=$(echo "$dots / 100" | bc)

  log "Width: $width"
  log "Height: $height"
  log "Dots: $dots"
}

function print_page() {
  log "Processing page $page ..."

  convert_to_jbig

  get_image_size
  get_image_parameters

  flush_page_header

  flush_image

  flush_page_footer

  log "Done page $page."
}

function remove_tmp_dir() {
  log "Removing $TMP_DIR ..."

  rm -rf "$TMP_DIR"

  log "Removed $TMP_DIR."
}

function main() {
  log "Called with command line: $0 $*"

  trap "stop && remove_tmp_dir && exit;" SIGINT SIGTERM SIGQUIT

  mkdir -p "$TMP_DIR"

  pagesize="A4"
  resolution="600"
  mediasource="TRAY1"

  # Parsing options from input
  for option in $OPTIONS; do
    case "$option" in
      PageSize=*)
        pagesize=$(echo "${option#PageSize=}" | tr '[:lower:]' '[:upper:]')
        ;;
      Resolution=*)
        resolution=${option#Resolution=}
        resolution=${resolution%dpi}
        ;;
      InputSlot=*)
        mediasource=${option#InputSlot=}
        ;;
    esac # case "$option" in
  done # for option in $OPTIONS; do

  if [[ $DEBUG == "yes" ]]; then
    exec > "$TMP_DIR"/output.stream
  fi

  if [[ -x $(which inotifywait) ]]; then
    log "Asynchronous variant."
    (
      stage="empty"

      inotifywait -rmqe close_write --format "%f" "$TMP_DIR" \
        | grep --line-buffered "page.pbm$" \
        | while read -r page; do
            log "Page submitted."

            if [[ $stage == "empty" ]]; then
              flush_pjl_header
              stage="printing"
            fi

	    if [[ $page == "999999999-page.pbm" ]]; then
              flush_pjl_footer
              kill_tmpdir_process
	      break
            fi

	    if [[ $stage == "printing" ]]; then
              print_page
            fi
          done # while read -r page; do
    ) &
    convert_to_pbmraw
    stop
    wait

  else # end of if [[ -x $(which inotifywait) ]]; then
    log "Synchronous variant."

    convert_to_pbmraw

    flush_pjl_header

    find "$TMP_DIR" -name "*-page.pbm" -printf "%f\\n" \
      | while read -r page; do
          print_page
        done

    flush_pjl_footer
  fi # end of else

  sleep 30
  [[ $DEBUG != "yes" ]] && remove_tmp_dir
} # function main()

main "$@"
exit 0
