#!/usr/bin/perl
# ----------------------------------------------------------------------------
# This software is Copyright (C) 2007, All Rights Reserved
# ----------------------------------------------------------------------------
# This program is protected by local and international copyright laws. Any
# use of this program is subject to the the terms of the license agreement
# included as part of this distribution archive. Any other uses are strictly
# prohibited without the written permission of the Vendor and all
# other rights are reserved.
# -----------------------------------------------------------------------------
# Warning : Modifying this program violates your license agreement!
# -----------------------------------------------------------------------------

package IT::App::Menu::Save;

# load modules
use strict;

use IT::Globals;

# module globals
use vars qw(%BUILTIN_FIELDS);

%BUILTIN_FIELDS = map { $_ => 1 } qw(num createdTime createdByUserNum lastUpdatedTime lastUpdatedByUserNum);

# ------------------------------------------------------------------------
# Function    : hasRecordBeenUpdatedDuringEditing
# Description : Check if a record has been updated since it was opened for
#               editing by __ANOTHER USER__ (ignore if it's by THIS user)
# Usage       : if (&IT::App::Menu::Save::hasRecordBeenUpdatedDuringEditing($FORM->{'lastUpdatedTime'}, $tableName, $recordNumber)) {
# ------------------------------------------------------------------------

sub hasRecordBeenUpdatedDuringEditing {
  my $lastUpdatedTimeWhenOpened = shift;
  my $originalRecord            = shift || die "no record value specified!";

  if ($FORM->{'_ignoreRevisionConflicts'}) { return 0; }

  # check if record has been updated
  my $isBySameUser           = $originalRecord->{'lastUpdatedByUserNum'} == $CURRENT_USER->{'num'};
  my $currentLastUpdatedTime = $originalRecord->{'lastUpdatedTime'};
  my $isUpdatedSinceOpened   = $currentLastUpdatedTime > $lastUpdatedTimeWhenOpened;

  if (!$isBySameUser && $isUpdatedSinceOpened) {
    return 1;
  }

  return 0;
}

# ------------------------------------------------------------------------
# Function    : revisionConflictWarning
# Description : Warn when the record has been updated since it was opened
#               for editing
# Note        : When adding handlers copy examples in list()
# ------------------------------------------------------------------------

sub revisionConflictWarning {
  my $menuName = shift || die "no menuName defined!";
  my $attr     = shift || die "no attributes defined!";

  # load record
  &IT::FileLock::getLock('shared');
  my $records = &IT::DB::select({
    'tableName'  => $attr->{'tableNameWithPrefix'},
    'whereQuery' => "num = '$attr->{'recordNum'}'",
    'limit'      => [0,1],
  });
  $attr->{'recordFields'} = $records->[0];
  &IT::FileLock::releaseLock();

  # error checking
  if (!$attr->{'recordFields'}) {
    my $error = "Couldn't find record #$attr->{'recordNum'}";
    &list($menuName, $error);
  }

  # get placeholders
  my $modifiedRecordFields = &IT::App::overrideRecordFieldsWithFormInput($attr->{'tableNameWithPrefix'}, $attr->{'recordFields'});
  $attr->{'placeholders'}  = &IT::App::getPlaceholdersFromRecordFields($attr->{'tableNameWithPrefix'}, $modifiedRecordFields);

  # create hidden fields for each form field
  my $hiddenFields;
  foreach my $name (sort keys %$FORM_ARRAYS) {
    if ($name eq 'action') { next; }
    my $encodedName  = &IT::Common::htmlEncode($name);
    foreach my $value (@{$FORM_ARRAYS->{$name}}) {
      my $encodedValue = &IT::Common::htmlEncode($value);
      $hiddenFields   .= qq|<input type="hidden" name="$encodedName" value="$encodedValue">\n|;
    }
  }


  ### Generate Output

  $attr->{'placeholders'}{'_hiddenFields'}           = $hiddenFields;
  $attr->{'placeholders'}{'_currentTime'}            = &IT::Template::createDatePlaceholder( &IT::App::Common::getTimeAdjustedToMatchGMT() );
  $attr->{'placeholders'}{'newLastUpdatedTime'}      = &IT::Template::createDatePlaceholder( $attr->{'recordFields'}{'lastUpdatedTime'} );
  $attr->{'placeholders'}{'newLastUpdatedByUserNum'} = $attr->{'recordFields'}{'lastUpdatedByUserNum'};

  # Display page
  $attr->{'menuTemplateCell'} = 'revisionConflict';
  &IT::App::displayInterface({
    'template'           => $attr->{'template'},
    'templatecell'       => $attr->{'menuTemplateCell'},
    'placeholders'       => $attr->{'placeholders'},
    'selectedMenuOption' => $attr->{'selectedMenuOption'},
  });

}


# ------------------------------------------------------------------------------
# Function    : adoptNewUploadsAndEraseRemovedUploads
# Description : Delete erased upload files, remove expiry on new uploads, return
#               record with erased uploads removed from image fields
# Usage       : &IT::App::Menu::Save::adoptNewUploadsAndEraseRemovedUploads($tableName, $fieldNamesAndValues);
# ------------------------------------------------------------------------------

sub adoptNewUploadsAndEraseRemovedUploads {
  my $tableName  = shift || die "no tablename specified!";
  my $record     = shift || die "no fieldNamesAndValues specified!";

  # get list of uploads
  my %uploadFilepaths;
  foreach my $fieldName (keys %$record) {
    my($appFieldType) = &IT::DB::Schema::getFieldAttributes($tableName, $fieldName, 'appFieldType');
    unless ($appFieldType eq 'upload') { next; }                        # skip all but upload fields
    my $listString = $record->{$fieldName} || next; # skip upload fields with nothing submitted
    my $listStruct = &IT::DhtmlFieldLists::convertListStringToStruct($listString);

    foreach my $uploadNum (keys %{$listStruct->{'rows'}}) {
      my $thisUpload = $listStruct->{'rows'}{$uploadNum};
      my $filepath   = "$SETTINGS->{'upload_dir'}/$thisUpload->{'pathFromUploadDir'}";
      $uploadFilepaths{ $filepath } = $thisUpload->{'_erased'};

      # remove erased images from upload field
      if ($thisUpload->{'_erased'}) { delete $listStruct->{'rows'}{$uploadNum} }
    }

    # update record with new upload data
    $record->{$fieldName} = &IT::DhtmlFieldLists::convertListStructToString($listStruct);
  }

  # adopt new uploads (remove expiry) and erased uploads flagged as deleted
  foreach my $uploadFilepath (keys %uploadFilepaths) {
    my $thumbnailPath = $uploadFilepath;
    $thumbnailPath =~ s/\.(\w+)$/$THUMBNAIL_PREFIX.$1/;

    # erase removed uploads
    my $toBeErased  = $uploadFilepaths{$uploadFilepath};  # 1 = to be erased, 0 = to be adopted or already existing
    if ($toBeErased && -f $uploadFilepath) { unlink($uploadFilepath) || die "unable to erase upload '$uploadFilepath'! $!"; }
    if ($toBeErased && -f $thumbnailPath)  { unlink($thumbnailPath)  || die "unable to erase upload '$thumbnailPath'! $!"; }

    # remove expiry counter on adopted uploads
    &IT::Upload::removeExpiryCounter($uploadFilepath);
  }

  return $record;
}

# ------------------------------------------------------------------------------
# Function    : getFieldValidationErrors
# Description : return validation errors on user submitted input (not db fields,
#               so we're expecting multipl fields for date, etc)
# Usage       : my $errors = &IT::App::Menu::Save::getFieldValidationErrors($attr);
# ------------------------------------------------------------------------------

sub getFieldValidationErrors {
  my $attr = shift || die "no attributes specified!";
  my @errors;

  # get field list
  my @sortedFieldNames;
  if ($attr->{'limitUpdatableFields'}) { @sortedFieldNames = sort @{$attr->{'limitUpdatableFields'}}; }
  else                                 { @sortedFieldNames = &IT::App::getUserSortedFieldNames($attr->{'tableNameWithPrefix'}); }

  # check each field
  my $recordNum        = $attr->{'recordNum'};
  foreach my $fieldName (@sortedFieldNames) {
    if ($BUILTIN_FIELDS{$fieldName}) { next; }  # skip builtin required fields like num and createdTime
    my($appFieldType, $fieldLabel, $appFieldValidationRules, $appFieldOptions) = &IT::DB::Schema::getFieldAttributes($attr->{'tableNameWithPrefix'}, $fieldName, 'appFieldType', 'appFieldLabel', 'appFieldValidationRules', 'appFieldOptions');

    my $rules      = $appFieldValidationRules;
    my $fieldValue = $FORM->{$fieldName};
    my $tableName  = $attr->{'tableNameWithPrefix'};
    my $fieldLabelOrName = $fieldLabel || $fieldName;

    # none
    if ($appFieldType eq 'none') {}

    # blank
    elsif ($appFieldType eq '') { die "field '$fieldName' doesn't have a field type defined!"; }

    # textfield
    elsif ($appFieldType eq 'textfield') {
      push @errors, &IT::App::Menu::Save::getDbValueSizeAndTypeErrors($rules, $fieldLabelOrName, $fieldValue, $fieldName, $tableName);
      push @errors, &IT::App::Menu::Save::getRequiredFieldErrors($rules, $fieldLabelOrName, $fieldValue);
      push @errors, &IT::App::Menu::Save::getUniqueFieldErrors($rules, $fieldLabelOrName, $fieldValue, $fieldName, $tableName, $recordNum);
      push @errors, &IT::App::Menu::Save::getMinLengthErrors($rules, $fieldLabelOrName, $fieldValue);
      push @errors, &IT::App::Menu::Save::getMaxLengthErrors($rules, $fieldLabelOrName, $fieldValue);
      push @errors, &IT::App::Menu::Save::getCustomValidationRuleErrors($appFieldValidationRules, $fieldLabelOrName, $fieldValue);

    }

    # textbox
    elsif ($appFieldType eq 'textbox') {
      push @errors, &IT::App::Menu::Save::getDbValueSizeAndTypeErrors($rules, $fieldLabelOrName, $fieldValue, $fieldName, $tableName);
      push @errors, &IT::App::Menu::Save::getRequiredFieldErrors($rules, $fieldLabelOrName, $fieldValue);
      push @errors, &IT::App::Menu::Save::getUniqueFieldErrors($rules, $fieldLabelOrName, $fieldValue, $fieldName, $tableName, $recordNum);
      push @errors, &IT::App::Menu::Save::getMinLengthErrors($rules, $fieldLabelOrName, $fieldValue);
      push @errors, &IT::App::Menu::Save::getMaxLengthErrors($rules, $fieldLabelOrName, $fieldValue);
    }

    # date
    elsif ($appFieldType eq 'date')      {
      my $epochTime = &IT::App::getEpochTimeFromFormInputDateFields($fieldName);
      push @errors, &IT::App::Menu::Save::getDbValueSizeAndTypeErrors($rules, $fieldLabelOrName, $epochTime, $fieldName, $tableName);
      push @errors, &IT::App::Menu::Save::getUniqueFieldErrors($rules, $fieldLabelOrName, $epochTime, $fieldName, $tableName, $recordNum);
    }

    ## lists
    elsif ($appFieldType eq 'list')      {
      my $listValuesArray = $FORM_ARRAYS->{$fieldName} || [];
      my $listValues = join "\t", @$listValuesArray;  # multi-lists can submit multiple values

      push @errors, &IT::App::Menu::Save::getDbValueSizeAndTypeErrors($rules, $fieldLabelOrName, $listValues, $fieldName, $tableName);
      push @errors, &IT::App::Menu::Save::getRequiredFieldErrors($rules, $fieldLabelOrName, $listValues);
      push @errors, &IT::App::Menu::Save::getUniqueFieldErrors($rules, $fieldLabelOrName, $listValues, $fieldName, $tableName, $recordNum);

      # get list of valid list values
      my %validValues;
      foreach my $listOption (@{$appFieldOptions->{'list_options'}}) {
        $validValues{ $listOption->{'value'} } = 1;
      }

      # check if each submitted value is in list
      foreach my $submittedValue (@{$FORM_ARRAYS->{$fieldName}}) {
        if (!$validValues{ $submittedValue }) {
          if ($submittedValue ne '') { push @errors, "'$submittedValue' isn't a valid value for $fieldLabelOrName!"; }
        }
      }
    }

    # checkbox
    elsif ($appFieldType eq 'checkbox')  {
      push @errors, &IT::App::Menu::Save::getDbValueSizeAndTypeErrors($rules, $fieldLabelOrName, $fieldValue, $fieldName, $tableName);
      if ($fieldValue ne '1' && $fieldValue ne '0') { push @errors, "$fieldLabelOrName must have a value of 0 or 1, not '$fieldValue'!"; }
    }

    # upload
    elsif ($appFieldType eq 'upload') {
      ### Note: Upload specific restrictions are checked when files are uploaded

      # get actual value that will be stored in record for checking size constraints
      if ($fieldValue) {
        my $listStruct    = &IT::DhtmlFieldLists::getListStructFromFormData($fieldName);
        my $listString  = &IT::DhtmlFieldLists::convertListStructToString($listStruct);
        my $recordValue = $listString;
        push @errors, &IT::App::Menu::Save::getDbValueSizeAndTypeErrors($rules, $fieldLabelOrName, $recordValue, $fieldName, $tableName);
      }

      push @errors, &IT::App::Menu::Save::getRequiredFieldErrors($rules, $fieldLabelOrName, $fieldValue);
    }

    # custom
    elsif ($appFieldType eq 'custom') {
      my($appCustomFieldType)    = &IT::DB::Schema::getFieldAttributes($tableName, $fieldName, 'appCustomFieldType');
      my $customFieldAttributes  = &IT::App::Menu::getCustomFieldType($appCustomFieldType);

      push @errors, &{$customFieldAttributes->{'errorCheckingForUserInput'}}($fieldLabelOrName, $fieldValue, $fieldName, $tableName, $recordNum);
    }

    else {
      die "unknown field type '$appFieldType' for field '$fieldName'";
    }
  }

  my $errors = join "\n", @errors;
  return $errors;

}

# ------------------------------------------------------------------------------
# Function    : getDbValueSizeAndTypeErrors
# Description :
# Usage       : push @errors, &IT::App::Menu::Save::getDbValueSizeAndTypeErrors($appFieldValidationRules, $appFieldLabel, $fieldValue, $fieldName);
# ------------------------------------------------------------------------------

sub getDbValueSizeAndTypeErrors {
  my($rules, $fieldLabelOrName, $fieldValue, $fieldName, $tableName) = @_;

  eval { &IT::DB::Common::dieOnValueSizeAndTypeErrors($tableName, $fieldName, $fieldValue); };
  if ($@) {
    my $errors = $@;

    # replace fieldname with fieldvalue
    $errors =~ s/'$fieldName'/'$fieldLabelOrName'/gs;

    # remove stacktrace from die
    $errors =~ s/\n.*?\) called \(.*?$//s;

    my @errors = split /\n/, $errors;
    return @errors;
  }

  return; # return empty list so nothing is added to errors array
}

# ------------------------------------------------------------------------------
# Function    : getRequiredFieldErrors
# Description :
# Usage       : push @errors, &IT::App::Menu::Save::getRequiredFieldErrors($appFieldValidationRules, $appFieldLabel, $fieldValue);
# ------------------------------------------------------------------------------

sub getRequiredFieldErrors {
  my($rules, $fieldLabelOrName, $fieldValue) = @_;
  if ($rules->{'valueIsRequired'} && $fieldValue eq '') { return "$fieldLabelOrName is required!"; }
  return; # return empty list so nothing is added to errors array
}

# ------------------------------------------------------------------------------
# Function    : getUniqueFieldErrors
# Description :
# Usage       : push @errors, &IT::App::Menu::Save::getUniqueFieldErrors($appFieldValidationRules, $appFieldLabel, $fieldValue, $fieldName);
# ------------------------------------------------------------------------------

sub getUniqueFieldErrors {
  my($rules, $fieldLabelOrName, $fieldValue, $fieldName, $tableName, $recordNum) = @_;

  if ($rules->{'valueMustBeUnique'}) {

    # get escaped field value (with meta and wild chars escaped
    my $escapedValue = $fieldValue;
    $escapedValue = &IT::DB::getEscapedValue($escapedValue);

    # get count of records with same value
    &IT::FileLock::getLock('shared');
    my $recordCount   = &IT::DB::count($tableName, "$fieldName = '$escapedValue' AND num != '$recordNum'");
    &IT::FileLock::releaseLock();
    my $isValueUnique = ($recordCount > 0) ? 0 : 1;

    # return error
    if (!$isValueUnique) { return "'$fieldLabelOrName' value must be unique. The selected value is already in use!"; }
  }

  return; # return empty list so nothing is added to errors array
}

# ------------------------------------------------------------------------------
# Function    : getMinLengthErrors
# Description :
# Usage       :
# ------------------------------------------------------------------------------

sub getMinLengthErrors {
  my($rules, $fieldLabelOrName, $fieldValue) = @_;

  my $fieldLength = length($fieldValue);

  if ($rules->{'checkMinLength'} && $rules->{'minLength'} > $fieldLength) {
    return "'$fieldLabelOrName' must be at least $rules->{'minLength'} characters! (currently $fieldLength characters)";
  }
  return; # return empty list so nothing is added to errors array
}

# ------------------------------------------------------------------------------
# Function    : getMaxLengthErrors
# Description : Check that submitted data doesn't exceed "max length" user validation rule
# Usage       :
# ------------------------------------------------------------------------------

sub getMaxLengthErrors {
  my($rules, $fieldLabelOrName, $fieldValue) = @_;

  my $fieldLength = length($fieldValue);

  if ($rules->{'checkMaxLength'} && $rules->{'maxLength'} < $fieldLength) {
    return "'$fieldLabelOrName' cannot be longer than $rules->{'maxLength'} characters! (currently $fieldLength characters)";
  }
  return; # return empty list so nothing is added to errors array
}

# ------------------------------------------------------------------------------
# Function    : getCustomValidationRuleErrors
# Description :
# Usage       : push @errors, &IT::App::Menu::Save::getCustomValidationRuleErrors($appFieldValidationRules, $appFieldLabel, $fieldValue);
# ------------------------------------------------------------------------------

sub getCustomValidationRuleErrors {
  my $rules      = shift;
  my $fieldLabelOrName = shift;
  my $fieldValue = shift;
  my $error;

  # if no rules, return
  if (!$rules) { return; }

  ### check custom rule

  # any content is valid
  if    ($rules->{'validationRuleType'} eq '')            {}
  elsif ($rules->{'validationRuleType'} eq 'none')        {}

  # looks like a valid...
  elsif ($rules->{'validationRuleType'} eq 'element')     {
    if ($fieldValue eq '') { next; }  # skip blank values
    if    ($rules->{'validationRule_validElementName'} eq 'email') {
      if (!&IT::Validation::isValidEmail($fieldValue)) {
        $error = "'$fieldLabelOrName' must be a valid email address (eg: user\@host.com)!";
      }
    }
    elsif ($rules->{'validationRule_validElementName'} eq 'url') {
      if (!&IT::Validation::isValidUrl($fieldValue)) {
        $error = "'$fieldLabelOrName' must be a valid url address (eg: http://www.example.com/)!";
      }
    }
    else {
      die "unknown validation rule '$rules->{'validationRule_validElementName'}'";
    }
  }

  # only allow characters
  elsif ($rules->{'validationRuleType'} eq 'allowChars')  {
    my $charsAllowed;
    $charsAllowed .= 'A-Za-z' if $rules->{'validationRule_allowCharsLetter'};
    $charsAllowed .= '0-9'    if $rules->{'validationRule_allowCharsNumber'};
    $charsAllowed .= quotemeta($rules->{'validationRule_allowCharsOtherValue'}) if $rules->{'validationRule_allowCharsOther'};

    if ($charsAllowed eq '' || $fieldValue =~ m/[^$charsAllowed]/) {
      my $unescapedCharsAllowed = $charsAllowed;
      $unescapedCharsAllowed    =~ s/\\(.)/$1/gs;
      $error = "'$fieldLabelOrName' only allows the following characters ($unescapedCharsAllowed)";
    }
  }

  # Disallow characters
  elsif ($rules->{'validationRuleType'} eq 'disallowChars') {
    my $charsDisallowed;
    $charsDisallowed .= 'A-Za-z' if $rules->{'validationRule_disallowCharsLetter'};
    $charsDisallowed .= '0-9'    if $rules->{'validationRule_disallowCharsNumber'};
    $charsDisallowed .= quotemeta($rules->{'validationRule_disallowCharsOtherValue'}) if $rules->{'validationRule_disallowCharsOther'};

    if ($charsDisallowed && $fieldValue =~ m/[$charsDisallowed]/) {
      my $unescapedCharsDisallowed = $charsDisallowed;
      $unescapedCharsDisallowed    =~ s/\\(.)/$1/gs;
      $error = "'$fieldLabelOrName' doesn't allow the following characters ($unescapedCharsDisallowed)";
    }
  }

  # Perl Regular Expression
  elsif ($rules->{'validationRuleType'} eq 'perlRegexp')  {
    if ($fieldValue !~ m/$rules->{'validationRule_perlRegexp'}/) {
      $error = "'$fieldLabelOrName' isn't in the right format (doesn't match regular expression)!";
    }
  }

  else { die "unknown validation rule type '$rules->{'validationRuleType'}'"; }

  ### Use custom error for validation Rule
  if ($rules->{'useCustomErrorForValidationRule'} && $error) {
    $error = $rules->{'customValidationRuleError'};
  }

  if ($error) { return $error; }
  else        { return; }

  return; # return empty list so nothing is added to errors array
}


# ------------------------------------------------------------------------------
# Function    : getUploadValidationErrors
# Description : If uploaded file doesn't meet the upload restrictions than return
#               a list of validation errors.  Otherwise return nothing.
# Usage       : my $validationErrors = &IT::App::Menu::Save::getUploadValidationErrors($tableName, $fieldName, $tempFilePath, $userFileName);
# ------------------------------------------------------------------------------

sub getUploadValidationErrors {
  my $tableName    = shift || die "no tablename specified!";
  my $fieldName    = shift || die "no fieldname specified!";
  my $tempFilePath = shift || die "no tempfilePath specified!";
  my $userFileName = shift || die "no user filename specified!";

  ### error checking
  unless (-e $tempFilePath) { die "tempFilePath '$tempFilePath' doesn't exist!"; }
  unless (-f $tempFilePath) { die "tempFilePath '$tempFilePath' isn't a file!"; }


  ### get validation rules
  my $fieldValidationRules = &IT::DB::Schema::getFieldAttributes($tableName, $fieldName, 'appFieldValidationRules');

  my $validUploadExtensions;
  if ($fieldValidationRules->{'uploadExtOverride'}) { $validUploadExtensions = $fieldValidationRules->{'uploadExtAllowed'}; }
  else                                              { $validUploadExtensions = $SETTINGS->{'accepted_upload_extensions'}; }
  my @validExtensions = split/\s*,\s*/, $validUploadExtensions;
  my %validExtensions = map { $_ => 1 } @validExtensions;

  my $maxUploadSizeK;
  if ($fieldValidationRules->{'uploadFileSizeOverride'}) { $maxUploadSizeK = $fieldValidationRules->{'uploadMaxFileSize'}; }
  elsif ($SETTINGS->{'check_upload_filesize'})           { $maxUploadSizeK = $SETTINGS->{'upload_filesize_max_kbytes'}; }

  ### Check Rules
  my $validationErrors;

  my $userFileExtension = ($userFileName =~ m/\.(\w+)$/)[0];
  $userFileExtension = lc $userFileExtension;
  if (!$validExtensions{$userFileExtension}) {
    $validationErrors .= "Invalid file extension on '$userFileName', valid file extensions are ($validUploadExtensions)\n";
    return $validationErrors;
  }

  my $userFileSizeK = int ((-s $tempFilePath) / 1024);
  if ($maxUploadSizeK && $userFileSizeK > $maxUploadSizeK) {
    $validationErrors .= "'$userFileName' is ${userFileSizeK}K (max size is ${maxUploadSizeK}K).\n";
    return $validationErrors;
  }


  # check if image is oversized (and auto-resizing not available)
  my($maxImageHeight, $maxImageWidth) = &IT::App::Menu::getMaxImageDimensionsForField($tableName, $fieldName);
  my $isImage              = &IT::Image::isImage($userFileName);
  my $isMaxImageDimensions = ($maxImageHeight > 0 || $maxImageWidth > 0);
  my $isResizingAvailable  = $SETTINGS->{'resize_oversize_images'} && &IT::Image::isResizeImageAvailable();

  if ($isImage && $isMaxImageDimensions && !$isResizingAvailable) {
    my($height, $width) = &IT::Image::getImageHeightAndWidth($tempFilePath, $userFileName);
    my $isOversized     = ($height > $maxImageHeight) || ($width > $maxImageWidth);

    if ($isOversized) {
      $validationErrors .= "'$userFileName' is $width wide by $height high.\n";
      $validationErrors .= "(Maximum size is $maxImageWidth wide by $maxImageHeight high)\n";
      if ($SETTINGS->{'resize_oversize_images'} && !&IT::Image::isResizeImageAvailable()) {
        $validationErrors .= "Auto resizing is enabled but no supported image modules were found.\n";
      }
    }
  }

  return $validationErrors;

}

# ----------------------------------------------------------------------------
# end of file
1;

