#!/bin/bash

# Log filename
OUTPUT_FILE="$1"

# File Maximum size before rotate in MB
FILE_SIZE_MAX="$2"

# Number of files rotated
MAX_ROTATION_FILES="$3"

# @brief: Function to print and log errors
function err_msg() {
  echo "$0 Error: $*"
  logger "$0 Error: $*"
}

# @brief This function call the logrotate with a custom made temporary configuration file.
function logrotate_wrap() {
  # logrotate script
  # param 1 ($1) - the rotation count
  # param 2 ($2) - log file name
  # param 3 ($3) - size
  local count_nr="$1"
  local filename="$2"
  local max_size="$3"

  # create a temporary file
  temp_file=$(mktemp)

  # set contents of the temporary configuration file
  echo -e "${filename} { \n  rotate ${count_nr}\n  size ${max_size}\n  copytruncate\n  missingok\n  compress" >> "$temp_file"
  echo -e "  lastaction" >> "$temp_file"
  echo -e "    if ! gunzip --test ${filename}.1.gz ; then" >> "$temp_file"
  echo -e "      logger -p local7.err \"Integrity of log file ${filename}.1.gz not ok\"" >> "$temp_file"
  echo -e "      rm -f ${filename}.1.gz" >> "$temp_file"
  echo -e "    fi" >> "$temp_file"
  echo -e "  endscript" >> "$temp_file"
  echo -e "}" >> "$temp_file"

  # rotate the log
  /usr/sbin/logrotate "$temp_file"

  # removes the temporary file
  rm -f "$temp_file"
}

# @brief This function moves the saved log that was not compress in logrotate <filename.log.1>, to the beginning of the current log file <filename.log>.
function append_saved_log() {
  # param 1 ($1) - the log file name
  local filename="$1"

  if [[ -f "$filename" ]]; then
    # create a temporary file
    temp_file=$(mktemp)

    # append saved log to the beginning of filename
    cat "$filename.1" "$filename" > "$temp_file"
    mv -f "$temp_file" "$filename"

    # removes the temporary file
    rm -f "$filename.1"
  else
    # just move the file
    mv -f "$filename.1" "$filename"
  fi
}

function check_and_rotate()
{
  local filesize="$1"
  local file_size_max_bytes="$2"

  if [[ $filesize -gt $file_size_max_bytes ]]; then
    # Call the logrotate wrapper function
    logrotate_wrap "$MAX_ROTATION_FILES" "$OUTPUT_FILE" "$file_size_max_bytes"
    # Drop the file caching
    sync; echo 3 > /proc/sys/vm/drop_caches >& /dev/null
    return 0
  fi

  return 1
}

############# MAIN #################

# Check if the number of arguments is correct
if [[ $# -ne 3 ]]; then
  echo "Usage: $0 <log filename> <log file maxsize in MB> <rotation files>"
  exit 1
fi

# Check if 2nd parameter is a number
re='^[0-9]+$'
if ! [[ $2 =~ $re ]] ; then
  err_msg "$2 is not a number"
  exit 1
else
  # convert to MB
  file_size_max_bytes=$((FILE_SIZE_MAX * 1024 * 1024))
fi

# Check if 3rd parameter is a number
if ! [[ $3 =~ $re ]] ; then
  err_msg "$3 is not a number"
  exit 1
fi

if [[ -f "$OUTPUT_FILE.1" ]]; then
  append_saved_log "$OUTPUT_FILE"
fi

# get the size of the log-file
if [[ -f "$OUTPUT_FILE" ]]; then
  filesize=$(stat -c%s "$OUTPUT_FILE")
  if check_and_rotate "$filesize" "$file_size_max_bytes" ; then
    filesize=0
  fi
else
  touch "$OUTPUT_FILE"
  filesize=0
fi

while IFS= read -r line ; do
  # Send mesage to the log-file
  echo "$line" >> "$OUTPUT_FILE"

  # get the size of the log-file
  linesize=${#line}
  # plus one for CR
  filesize=$((filesize + linesize + 1))

  if check_and_rotate "$filesize" "$file_size_max_bytes" ; then
    filesize=0
    if [[ -f "$OUTPUT_FILE.1" ]]; then
      append_saved_log "$OUTPUT_FILE"
      filesize=$(stat -c%s "$OUTPUT_FILE")
    fi
  fi

done

