#!/bin/bash

set -eu -o pipefail

PCP_DIR="$(dirname "$0")/pcp"

if [ ! -d "${PCP_DIR}" ]; then
   echo Could not find PCP platform sources. >&2
   exit 1
fi

echo Scanning definitions in ${PCP_DIR} ...

PCP_COLUMNS="${PCP_DIR}/columns"
PCP_METERS="${PCP_DIR}/meters"
PCP_SCREENS="${PCP_DIR}/screens"

if [ ! -d "${PCP_COLUMNS}" ]; then
   echo Could not find PCP column definitions. >&2
   exit 1
fi

if [ ! -d "${PCP_METERS}" ]; then
   echo Could not find PCP meter definitions. >&2
   exit 1
fi

if [ ! -d "${PCP_SCREENS}" ]; then
   echo Could not find PCP screen definitions. >&2
   exit 1
fi

check_file() {
   f="$1"
   r="$2"

   echo "Processing $f ..."

   awk -v required_names_str="$2" '
      BEGIN {
         # Define the required names
         split(required_names_str, required_names)
         section = ""
      }

      # Skip comment lines
      /^#/ {
         next
      }

      # Detect section headers
      /^\[.*\]$/ {
         if (section != "") {
            check_section()
         }
         section = $0
         if (section in sections_seen) {
            print "Error: Duplicate section " section
            exit 1
         }
         sections_seen[section] = 1
         delete seen
         delete groups
         next
      }

      # Process name = value pairs with whitespace around the equals sign
      /^[^=]+ = .+$/ {
         npart = split($0, pair, " = ")

         name = trim(pair[1])
         value = trim(pair[2])
         for (i = 3; i <= npart; i++) {
            value = value " " trim(pair[i])
         }
         group = ""

         known = 0
         for (i in required_names) {
            rname = required_names[i]
            if (rname ~ /\?$/) {
               rname = substr(rname, 1, length(rname) - 1)
            }
            if (rname ~ /^\*\./) {
               rlname = substr(rname, 2, length(rname) - 1)
               if (substr(name, length(name) - length(rlname) + 1) == rlname) {
                  group = substr(name, 1, length(name) - length(rlname) + 1)
                  known = 1
                  break
               }
            }
            if (rname == name) {
               known = 1
               break
            }
         }
         if (!known) {
            print "Error: Unknown name " name " in section " section
            exit 1
         }

         if (name in seen) {
            print "Error: Duplicate name " name " in section " section
            exit 1
         }

         seen[name] = 1
         groups[group] = 1

         if (name ~ /(^|\.)width$/) {
            if (!(value ~ /^-?[0-9]{1,3}$/)) {
               print "Error: Specified width " value " for " name " in section " section " is not an integer or out of range (-999..999)."
               exit 1
            }
         }

         if (name ~ /(^|\.)type$/) {
            if (!(value ~ /^(bar|text|graph|led)$/)) {
               print "Error: Specified type " value " for " name " in section " section " is not recognized."
               exit 1
            }
         }

         if (name ~ /(^|\.)color$/) {
            if (!(value ~ /^(black|blue|green|red|cyan|magenta|yellow|(dark)?gray|white)$/)) {
               print "Error: Specified color " value " for " name " in section " section " is not recognized."
               exit 1
            }
         }

         next
      }

      # Function to trim whitespace
      function trim(s) {
         gsub(/^[ \t]+|[ \t]+$/, "", s)
         return s
      }

      # Function to check if all required names are present
      function check_section() {
         missing = ""
         for (i in required_names) {
            rname = required_names[i]
            if (rname ~ /\?$/) {
               continue
            }
            if (rname ~ /^\*\./) {
               rname = substr(rname, 3, length(rname) - 2)
               for (g in groups) {
                  if (g == "") {
                     continue
                  }
                  if (!(g rname in seen)) {
                     missing = missing g rname " "
                  }
               }
               continue
            }
            if (!(rname in seen)) {
               missing = missing rname " "
            }
         }
         if (missing != "") {
            print "Error: Missing " missing "in section " section
            exit 1
         }
      }

      # End of file processing
      END {
         if (section != "") {
            check_section()
         }

         # Ensure the file ends with a single newline
         if (NR > 0 && length($0) < 1) {
            print "Error: Whitespace at EOF."
            exit 1
         }
      }
   ' "$f"
}

error_occurred=0

for pcp_file in "${PCP_COLUMNS}"/*; do
   if ! check_file "$pcp_file" "heading caption? width metric description"; then
      echo "Error processing file: $pcp_file" >&2
      error_occurred=1
   fi
done

for pcp_file in "${PCP_METERS}"/*; do
   if ! check_file "$pcp_file" "caption description? type? *.metric *.color? *.label? *.suffix?"; then
      echo "Error processing file: $pcp_file" >&2
      error_occurred=1
   fi
done

for pcp_file in "${PCP_SCREENS}"/*; do
   if ! check_file "$pcp_file" "heading caption default? *.heading *.metric *.default? *.caption? *.format? *.instances? *.width?"; then
      echo "Error processing file: $pcp_file" >&2
      error_occurred=1
   fi
done

if [ $error_occurred -ne 0 ]; then
   echo "One or more files failed to process." >&2
   exit 1
else
   echo "All files processed successfully." >&2
fi
