<?PHP
#
#   FILE:  UserEditingUI.php
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2015 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

/**
* Class supplying standard methods that process changes to user
* entered via HTML forms.
*/
class UserEditingUI
{
    /**
    * Set up a new UserEditingUI.
    * @param CWUser $CWUser User to operate on.
    */
    public function __construct($CWUser)
    {
        $this->User = $CWUser;
    }

    /**
    * Save user attributes that aren't stored in User Schema fields.
    * @param array $FormValues From _POST to process.
    * @param bool $IsNewUser New User? (OPTIONAL, default FALSE).
    * @param bool $UpdateUserEmail Indicate whether user email should be updated
    *           (OPTIONAL, default FALSE)
    */
    public function UpdateUserAttributes(
        array $FormValues,
        $IsNewUser=FALSE,
        $UpdateUserEmail=FALSE)
    {
        # save other user information
        $UserFields = array(
            "WebSite",
            "AddressLineOne",
            "AddressLineTwo",
            "City",
            "State",
            "ZipCode",
            "Country",
            );

        if ($UpdateUserEmail)
        {
            $UserFields[] = "EMail";
        }
        foreach ($UserFields as $VarName)
        {
            $FormVarName = "F_".$VarName;
            if (isset($FormValues[$FormVarName]) && strlen($FormValues[$FormVarName]))
            {
                $this->User->Set($VarName, $FormValues[$FormVarName]);
            }
        }

        if (isset($FormValues["F_RealName"]))
        {
            # the real name is handled separately from the other settings
            $OldRealName = $this->User->Get("RealName");
            $NewRealName = GetArrayValue($_POST, "F_RealName", "");

            if (!$IsNewUser && $OldRealName != $NewRealName)
            {
                $this->User->Set("RealName", $NewRealName);

                # signal the real name change
                $GLOBALS["AF"]->SignalEvent(
                    "EVENT_USER_REAL_NAME_CHANGED",
                    array(
                        "UserId" => $this->User->Id(),
                        "OldRealName" => $OldRealName,
                        "NewRealName" => $NewRealName));
            }
        }
    }

    /**
    * Save updated values for fields from the User schema based on
    *   data supplised in HTML forms.
    * @param array $Fields The fields to save update.
    * @return array of MetadataField objects for each required field
    *     that was left empty.
    */
    public function UpdateUserFields(array $Fields)
    {
        global $AF;

        $Schema = new MetadataSchema(MetadataSchema::SCHEMAID_USER);
        $Resource = $this->User->GetResource();
        $EmptyFields = array();
        $RecordChanged = FALSE;

        # for each metadata field in the User schema
        foreach ($Fields as $Field)
        {
            # if user has permission to edit field
            if ($Resource->UserCanEditField($this->User, $Field))
            {
                $OldValue = $Resource->Get($Field);
                switch ($Field->Type())
                {
                    case MetadataSchema::MDFTYPE_TEXT:
                    case MetadataSchema::MDFTYPE_NUMBER:
                    case MetadataSchema::MDFTYPE_DATE:
                    case MetadataSchema::MDFTYPE_TIMESTAMP:
                    case MetadataSchema::MDFTYPE_PARAGRAPH:
                    case MetadataSchema::MDFTYPE_FLAG:
                    case MetadataSchema::MDFTYPE_URL:
                        # if we have a value from the form for this field
                        # (check necessary because user may push Save button
                        #       before form has finished loading)
                        if (isset($_POST["F_".$Field->DBFieldName()]))
                        {
                            # run value through any hooked filters
                            $NewValue = trim($_POST["F_".$Field->DBFieldName()]);
                            $SignalResult = $AF->SignalEvent(
                                "EVENT_POST_FIELD_EDIT_FILTER", array(
                                    "Field" => $Field,
                                    "Resource" => $Resource,
                                    "Value" => $NewValue));
                            $NewValue = $SignalResult["Value"];

                            # clean out xss threats
                            $NewValue = StripXSSThreats($NewValue);

                            # filter date field values for validity
                            if ($Field->Type() & (MetadataSchema::MDFTYPE_DATE
                                                  |MetadataSchema::MDFTYPE_TIMESTAMP))
                            {
                                $TestDate = new Date($NewValue);
                                if ($TestDate->Precision() == 0) {  $NewValue = "";  }
                            }

                            # filter url values for URI
                            if ($Field->Type() == MetadataSchema::MDFTYPE_URL
                                && strlen($NewValue)
                                && !preg_match('/^[a-zA-Z]+:\/\//', $NewValue))
                            {
                                $NewValue = "http://".$NewValue;
                            }

                            # filter HTML tags out of text values if appropriate
                            if ($Field->Type() & (MetadataSchema::MDFTYPE_TEXT
                                                  |MetadataSchema::MDFTYPE_PARAGRAPH))
                            {
                                if (!$Field->AllowHTML())
                                {
                                    $NewValue = strip_tags($NewValue);
                                }
                            }

                            # if value was supplied or field is not required
                            if (strlen($NewValue) || $Field->Optional())
                            {
                                # save field
                                $Resource->Set($Field, $NewValue);
                            }
                            else
                            {
                                # add field to error list
                                $EmptyFields[] = $Field;
                            }
                        }
                        break;

                    case MetadataSchema::MDFTYPE_POINT:
                        # if there are no values set
                        if (!isset($_POST["F_".$Field->DBFieldName()."X"])
                            || !isset($_POST["F_".$Field->DBFieldName()."Y"]))
                        {
                            # if the field isn't optional, add it to the error list
                            if (!$Field->Optional())
                            {
                                $EmptyFields[] = $Field;
                            }

                            # go to the next field
                            continue;
                        }

                        # run value through any hooked filters
                        $NewValue = array(
                            "X" => $_POST["F_".$Field->DBFieldName()."X"],
                                "Y" => $_POST["F_".$Field->DBFIeldName()."Y"]);
                        $SignalResult = $AF->SignalEvent(
                            "EVENT_POST_FIELD_EDIT_FILTER", array(
                            "Field" => $Field,
                                "Resource" => $Resource,
                                "Value" => $NewValue));
                        $NewValue = $SignalResult["Value"];

                        # if value looks valid
                        if (is_numeric($NewValue["X"])
                                && is_numeric($NewValue["Y"]))
                        {
                            # save new value
                            $Resource->Set($Field, $NewValue);
                        }

                        # the field is optional and the values are blank
                        else if ($Field->Optional()
                                && !strlen(trim($NewValue["X"]))
                                && !strlen(trim($NewValue["Y"])))
                        {
                            # save blank value
                            $Resource->Set($Field, array("X" => "", "Y" => ""));
                        }

                        # empty fields and field is required
                        else if (!$Field->Optional())
                        {
                            # flag field as empty
                            $EmptyFields[] = $Field;
                        }
                        break;

                    case MetadataSchema::MDFTYPE_TREE:
                    case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
                        # while there are form values for this field
                        $ValueCount = $Field->GetCountOfPossibleValues();
                        $InterfaceToggleThreshold = 250;
                        $Factory = $Field->GetFactory();
                        $ValuesToSet = array();
                        $InputValues = array();

                        # old way it was being set
                        $BaseFieldName = "D_".$Field->DBFieldName()."_";
                        $FieldIndex = 1;

                        # set values the old way
                        if (isset($_POST[$BaseFieldName.$FieldIndex]))
                        {
                            while (isset($_POST[$BaseFieldName.$FieldIndex]))
                            {
                                # retrieve value from form field
                                $InputValues[] = $_POST[$BaseFieldName.$FieldIndex];

                                # move to the next form value
                                $FieldIndex++;
                            }
                        }

                        # set values the new way
                        else if (isset($_POST["F_".$Field->DBFieldName()]))
                        {
                            $InputValues = $_POST["F_".$Field->DBFieldName()];
                        }

                        foreach ($InputValues as $Value)
                        {
                            # If we have a non-empty value
                            if (strlen($Value))
                            {
                                # Check to see if it was a name, and if so
                                # convert it to an index.  Otherwise,
                                # it was already an index and we should use it
                                # directly.
                                $Item = $Factory->GetItemByName($Value);
                                if ($Item)
                                {
                                    $Value = $Item->Id();
                                }

                                # it looks like it was being wrongly assumed that
                                # this would always be a number, but when there's
                                # an error, it won't find an item and display SQL
                                # errors later on. So, if the value isn't numeric,
                                # refuse to work with it
                                else if (!is_numeric($Value))
                                {
                                    $Value = -1;
                                }
                                else
                                {
                                    $Value = intval($Value);
                                }
                            }
                            else
                            {
                                $Value = -1;
                            }

                            # if form value appears valid
                            if ($Value >= 0)
                            {
                                # add value to list of those to be set
                                # (set method expects IDs to appear as indexes)
                                $ValuesToSet[$Value] = 1;
                            }
                        }

                        # if value found to set or field is not required
                        if (count($ValuesToSet) || $Field->Optional())
                        {
                            $OldKeys = array_keys($OldValue);
                            $NewKeys = array_keys($ValuesToSet);

                            sort($OldKeys);
                            sort($NewKeys);

                            if ($OldKeys != $NewKeys)
                            {
                                # clear any existing values for this field
                                $Resource->ClearByField($Field);

                                # if values found to set
                                if (count($ValuesToSet))
                                {
                                    # set values in resource
                                    $Resource->Set($Field, $ValuesToSet);
                                }
                            }
                        }
                        else
                        {
                            # add field to error list
                            $EmptyFields[] = $Field;
                        }
                        break;

                    case MetadataSchema::MDFTYPE_OPTION:
                        # if field allows multiple values
                        $ValuesToSet = array();
                        if ($Field->AllowMultiple())
                        {
                            # retrieve possible values for this field
                            $PossibleValues = $Field->GetPossibleValues();

                            # newer way to get the values
                            if (isset($_POST["F_".$Field->DBFieldName()]))
                            {
                                $GivenValues = $_POST["F_".$Field->DBFieldName()];

                                # for each possible value
                                foreach ($PossibleValues as $ValueId => $ValueName)
                                {
                                    # if form field is set for value
                                    if (in_array($ValueId, $GivenValues))
                                    {
                                        # add value to list of those to be set
                                        $ValuesToSet[$ValueId] = 1;
                                    }
                                }
                            }

                            # old way to get the values
                            else
                            {
                                # for each possible value
                                foreach ($PossibleValues as $ValueId => $ValueName)
                                {
                                    # if form field is set for value
                                    if (isset($_POST["D_".$Field->DBFieldName()
                                                     ."_".$ValueId]))
                                    {
                                        # add value to list of those to be set
                                        $ValuesToSet[$ValueId] = 1;
                                    }
                                }
                            }
                        }
                        else
                        {
                            # retrieve value for this field (if available)
                            if (isset($_POST["F_".$Field->DBFieldName()]))
                            {
                                $ValuesToSet[$_POST["F_".$Field->DBFieldName()]] = 1;
                            }
                        }

                        # if value found to set or field is not required
                        if (count($ValuesToSet) || $Field->Optional())
                        {
                            $OldKeys = array_keys($OldValue);
                            $NewKeys = array_keys($ValuesToSet);

                            sort($OldKeys);
                            sort($NewKeys);

                            if ($OldKeys != $NewKeys)
                            {
                                # clear any existing values for this field
                                $Resource->ClearByField($Field);

                                # if values found to set
                                if (count($ValuesToSet))
                                {
                                    # set values in resource
                                    $Resource->Set($Field, $ValuesToSet);
                                }
                            }
                        }
                        else
                        {
                            # add field to error list
                            $EmptyFields[] = $Field;
                        }
                        break;

                    case MetadataSchema::MDFTYPE_USER:
                        $NewValue = trim(GetArrayValue(
                                             $_POST,
                                             "F_".$Field->DBFieldName()));

                        if (strlen($NewValue))
                        {
                            $SignalResult = $AF->SignalEvent(
                                "EVENT_POST_FIELD_EDIT_FILTER", array(
                                    "Field" => $Field,
                                    "Resource" => $Resource,
                                    "Value" => $NewValue));

                            $NewValue = $SignalResult["Value"];
                            $Resource->Set($Field, $NewValue);
                        }

                        # allow the field to be unset if it's optional
                        else if ($Field->Optional())
                        {
                            $SignalResult = $AF->SignalEvent(
                                    "EVENT_POST_FIELD_EDIT_FILTER", array(
                                           "Field" => $Field,
                                           "Resource" => $Resource,
                                           "Value" => $NewValue));

                            $NewValue = $SignalResult["Value"];
                            $Resource->Set($Field, $NewValue);
                        }

                        break;

                    case MetadataSchema::MDFTYPE_REFERENCE:
                        # get the new value from the submitted form data
                        $NewValue = GetArrayValue(
                                $_POST,
                                "F_".$Field->DBFieldName(),
                                array());

                        foreach ($NewValue as $Key => $ReferenceId)
                        {
                            # remove any blank values
                            if (strlen(trim($ReferenceId)) < 1)
                            {
                                unset($NewValue[$Key]);
                            }

                            # remove any values that don't look right
                            if (!is_numeric($ReferenceId))
                            {
                                unset($NewValue[$Key]);
                            }
                        }

                        # set the new value
                        $Resource->Set($Field, $NewValue);
                        break;

                    case MetadataSchema::MDFTYPE_IMAGE:
                    case MetadataSchema::MDFTYPE_FILE:
                        # (these types handled via special upload mechanisms)
                        break;

                    default:
                        break;
                }
                # If anything changed, set the update flag.
                $RecordChanged |= ($OldValue
                                   != $Resource->Get($Field));
            }
        }

        # If the record was changed, modify the appropriate timestamp fields
        if ($RecordChanged)
        {
            $Resource->UpdateAutoupdateFields(
                MetadataField::UPDATEMETHOD_ONRECORDCHANGE,
                $GLOBALS["G_User"]);

            # update search and recommender DBs if configured to do so
            $Resource->QueueSearchAndRecommenderUpdate();

            # signal the modified event if the resource isn't a temp one
            if (!$Resource->IsTempResource())
            {
                $AF->SignalEvent("EVENT_RESOURCE_MODIFY", array("Resource" => $Resource));
            }
        }

        # return list of any empty required fields to caller
        return $EmptyFields;
    }

    /**
    * Process file upload requests.
    * @param array $FormValues Values as from $_POST.
    * @param array $Files Files as from $_FILES.
    */
    public function UploadFiles($FormValues, $Files)
    {
        # for each metadata field that might have an uploaded image
        $Schema = new MetadataSchema(MetadataSchema::SCHEMAID_USER);
        $Resource = $this->User->GetResource();
        $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_FILE);
        foreach ($Fields as $Field)
        {
            $FormFieldName = "F_".$Field->DBFieldName();

            # if field is modifiable by specified user
            #       and we have an uploaded file for this field
            if ($Resource->UserCanEditField($this->User, $Field)
                && isset($Files[$FormFieldName]["tmp_name"])
                && is_uploaded_file($Files[$FormFieldName]["tmp_name"]))
            {
                # save uploaded file
                $TmpFileName = $Files[$FormFieldName]["tmp_name"];
                $NewFile = new File($TmpFileName, $Resource->Id(), $Field->Id(),
                                    $Files[$FormFieldName]["name"]);

                # if file save went fine
                if ($NewFile->Status() == File::FILESTAT_OK)
                {
                    $GLOBALS["AF"]->SignalEvent(
                        "EVENT_RESOURCE_FILE_ADD",
                        array(
                            "Field" => $Field,
                            "Resource" => $Resource,
                            "File" => $NewFile));
                }

                else
                {
                    # set error message and error out
                    switch ($NewFile->Status())
                    {
                        case File::FILESTAT_ZEROLENGTH:
                            $Error = ERR_ZEROLENGTH;
                            break;

                        default:
                            $Error = ERR_FILEUPLOADERROR;
                            break;
                    }
                    $ErrParamOne = $Files[$FormFieldName]['name'];
                    $ErrParamTwo = $NewFile->Status();
                }

                # remove temp file
                unlink($TmpFileName);
            }

            # delete images that have been selected for delete
            if (isset($FormValues[$FormFieldName."_Delete"]))
            {
                $DeletionIds = $FormValues[$FormFieldName."_Delete"];

                foreach ($DeletionIds as $DeletionId)
                {
                    $File = new File($DeletionId);

                    $GLOBALS["AF"]->SignalEvent(
                        "EVENT_RESOURCE_FILE_DELETE",
                        array(
                            "Field" => $Field,
                            "Resource" => $Resource,
                            "File" => $File));

                    $Resource->Clear($Field, $File->Id());
                }
            }
        }
    }


    /**
    * Process image upload requests for a user.
    * @param array $FormValues Values as from $_POST.
    * @param array $Files Files as from $_FILES.
    */
    public function UploadImages($FormValues, $Files)
    {
        # for each metadata field that might have an uploaded image
        $Schema = new MetadataSchema(MetadataSchema::SCHEMAID_USER);
        $Resource = $this->User->GetResource();
        $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_IMAGE);
        foreach ($Fields as $Field)
        {
            $FormFieldName = "F_".$Field->DBFieldName();

            # if field is modifiable by specified user
            #       and we have an uploaded file for this field
            if ($Resource->UserCanEditField($this->User, $Field)
                && isset($Files[$FormFieldName]["tmp_name"])
                && is_uploaded_file($Files[$FormFieldName]["tmp_name"]))
            {
                # create temp copy of file with correct name
                $TempFile = "tmp/".$Files[$FormFieldName]['name'];
                copy($Files[$FormFieldName]["tmp_name"], $TempFile);

                # create new Image object from uploaded file
                $Image = new SPTImage(
                    $TempFile,
                    $Field->MaxWidth(), $Field->MaxHeight(),
                    $Field->MaxPreviewWidth(), $Field->MaxPreviewHeight(),
                    $Field->MaxThumbnailWidth(), $Field->MaxThumbnailHeight());

                # if file save failed
                if ($Image->Status() != AI_OKAY)
                {
                    # set error message and error out
                    switch ($Image->Status())
                    {
                        case AI_UNKNOWNTYPE:
                        case AI_UNSUPPORTEDFORMAT:
                            $Error = ($Image->Status() == AI_UNSUPPORTEDFORMAT)
                                ? ERR_UNSUPPORTEDIMAGEFORMAT : ERR_UNKNOWNIMAGETYPE;
                            $ErrParamOne = $Files[$Field->DBFieldName()]['name'];
                            break;

                        default:
                            $Error = ERR_IMAGEUPLOADERROR;
                            $ErrParamOne = $Files[$FormFieldName]['name'];
                            $ErrParamTwo = $Image->Status();
                            break;
                    }
                }
                else
                {
                    # attach image to resource
                    $Resource->Set($Field, $Image->Id());
                }
            }

            # delete images that have been selected for delete
            if (isset($FormValues[$FormFieldName."_Delete"]))
            {
                $DeletionIds = $FormValues[$FormFieldName."_Delete"];

                foreach ($DeletionIds as $DeletionId)
                {
                    $Resource->Clear($Field, new SPTImage($DeletionId));
                }
            }
        }
    }

    /**
    * Determine if a user editing form has errors, setting error codes in the
    * correspnding FormTool.
    * @param FormTool $FTool FTool associated wit the user edting page.
    * @param array $UserErrorCodes Error codes encountered for this edit.
    * @return bool TRUE when the form has errors, FALSE otherwise.
    */
    public static function UserFormHasErrors(&$FTool, $UserErrorCodes)
    {
        global $AF;

        # if errors were found in incoming values
        if ($FTool->IncomingFieldValuesHaveErrors() || count($UserErrorCodes))
        {
            # make form fields based on error codes
            $CodeToFieldMap = array(
                U_DUPLICATEUSERNAME => "F_UserName",
                U_ILLEGALUSERNAME => "F_UserName",
                U_PASSWORDSDONTMATCH => array("F_Password", "F_PasswordAgain"),
                U_EMAILSDONTMATCH => array("F_EMail", "F_EMailAgain"),
                U_ILLEGALPASSWORD => "F_Password",
                U_ILLEGALPASSWORDAGAIN => "F_PasswordAgain",
                U_ILLEGALEMAIL => "F_EMail",
                U_ILLEGALEMAILAGAIN => "F_EMailAgain",
                U_EMPTYPASSWORD => "F_Password",
                U_EMPTYPASSWORDAGAIN => "F_PasswordAgain",
                U_EMPTYEMAIL => "F_EMail",
                U_EMPTYEMAILAGAIN => "F_EMailAgain",
                U_DUPLICATEEMAIL => array("F_EMail", "F_EMailAgain"),
                );

            foreach ($UserErrorCodes as $Code)
            {
                if (isset($CodeToFieldMap[$Code]))
                {
                    if (is_array(isset($CodeToFieldMap[$Code])))
                    {
                        foreach ($CodeToFieldMap[$Code] as $FieldName)
                        {
                            $FTool->SetAdditionalErrorFields($FieldName);
                        }
                    }
                    else
                    {
                        $FTool->SetAdditionalErrorFields($CodeToFieldMap[$Code]);
                    }
                }
            }

            $FTool->SetAdditionalErrorCodes($UserErrorCodes);

            return TRUE;
        }

        # return
        return FALSE;
    }

    /**
    * Retrieve the array of substitutions for new user activation mails.
    * @param CWUser $NewUser User that wants to be activated.
    * @return array of substitutions (keys are search strings, values
    *     their replacements).
    */
    public static function GetActivationEmailSubstitutions($NewUser)
    {
        $Protocol = isset($_SERVER["HTTPS"]) ? "https://" : "http://";

        $ActivationUrlParameters = "?UN=".urlencode($NewUser->Get("UserName"))
            ."&AC=".$NewUser->GetActivationCode();
        $ActivationUrl = $Protocol.$_SERVER["SERVER_NAME"]
            .dirname($_SERVER["SCRIPT_NAME"])
            ."/index.php".$ActivationUrlParameters."&P=ActivateAccount";
        $ManualActivationUrl = $Protocol.$_SERVER["SERVER_NAME"]
            .dirname($_SERVER["SCRIPT_NAME"])
            ."/index.php?P=ManuallyActivateAccount";

        return array(
            "X-PORTALNAME-X" => $GLOBALS["G_SysConfig"]->PortalName(),
            "X-ACTIVATIONURL-X" => $ActivationUrl,
            "X-ACTIVATIONPARAMETERS-X" => $ActivationUrlParameters,
            "X-MANUALACTIVATIONURL-X" => $ManualActivationUrl,
            );
    }

    /**
    * Get the list of account creation-related error messages.
    * @param string $Email Email for the password reminder link.
    * @return array mapping error codes to error messages.
    */
    public static function GetAdditionalErrorCodes($Email)
    {
        return array(
            U_PASSWORDSDONTMATCH   => "The two passwords you entered did not match.",
            U_EMAILSDONTMATCH   => "The two e-mail addresses you entered did not match.",
            U_DUPLICATEUSERNAME => "The user name you entered is already in use.",
            U_ILLEGALUSERNAME   => "The user name you entered is not valid."
                    ." User names must be made up of one word containing between 2 and 24"
                    ." letters and/or numbers.",
            U_MAILINGERROR      => "An error was encountered trying to send an"
                    ." e-mail message to activate your new account.  Please contact the"
                    ." administrator of this site and inform them of the problem.",
            U_EMPTYPASSWORD => "Please enter a password at least 6 characters long"
                    ." into both password fields below.",
            U_EMPTYPASSWORDAGAIN => "Please enter a password at least 6 characters long"
                    ." into both password fields below.",
            U_ILLEGALPASSWORD => "Please enter a password at least 6 characters long"
                    ." into both password fields below.",
            U_ILLEGALPASSWORDAGAIN => "Please enter a password at least 6 characters long"
                    ." into both password fields below.",
            U_DUPLICATEEMAIL => "The e-mail address you entered is already associated"
                    ." with an account.  If you have forgotten the account user name or"
                    ." password you can click"
                    ." <a href=\"index.php?P=ForgottenPasswordComplete&UN="
                    .urlencode($Email)."\">here</a>"
                    ." to send a reminder via e-mail.",
            U_ILLEGALEMAIL => "The e-mail address you entered is not valid",
            U_ILLEGALEMAILAGAIN => "The e-mail address you entered is not valid",
        );
    }

    /**
    * Check potential form values for a user including event signals.
    * @param array $FormValues Values as from $_POST.
    * @return array of error codes.
    */
    public static function TestUserValues($FormValues)
    {
        $UserFactory = new CWUserFactory();
        $UserErrorCodes = $UserFactory->TestNewUserValues($FormValues["F_UserName"],
                $FormValues["F_Password"], $FormValues["F_PasswordAgain"],
            $FormValues["F_EMail"], $FormValues["F_EMailAgain"]);

        $SignupStatus = $GLOBALS["AF"]->SignalEvent(
            "EVENT_USER_SIGNUP_VERIFY",
                array(
                    "UserName" => $FormValues["F_UserName"],
                    "Password" => $FormValues["F_Password"],
                    "EMail"    => $FormValues["F_EMail"],
                    "Status" => U_OKAY ));

        if ($SignupStatus["Status"] !== U_OKAY)
        {
            $UserErrorCodes[]= $SignupStatus["Status"];
        }

        return $UserErrorCodes;
    }

    # ---- PRIVATE INTERFACE -------------------------------------------------
    private $User;
}
