/** @file
  The functions to add a user profile.
    
Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials 
are licensed and made available under the terms and conditions of the BSD License 
which accompanies this distribution.  The full text of the license may be found at 
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include "UserProfileManager.h"


/**
  Get user name from the popup windows.
  
  @param[in, out]  UserNameLen  On entry, point to UserName buffer lengh, in bytes.
                                On exit, point to input user name length, in bytes.
  @param[out]      UserName     The buffer to hold the input user name.
 
  @retval EFI_ABORTED           It is given up by pressing 'ESC' key.
  @retval EFI_NOT_READY         Not a valid input at all.
  @retval EFI_SUCCESS           Get a user name successfully.

**/
EFI_STATUS
GetUserNameInput (
  IN OUT  UINTN         *UserNameLen,
     OUT  CHAR16        *UserName
  )
{
  EFI_INPUT_KEY Key;
  UINTN         NameLen;
  CHAR16        Name[USER_NAME_LENGTH];

  NameLen = 0;
  while (TRUE) {
    Name[NameLen]     = L'_';
    Name[NameLen + 1] = L'\0';
    CreatePopUp (
      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
      &Key,
      L"Input User Name",
      L"---------------------",
      Name,
      NULL
      );
    //
    // Check key.
    //
    if (Key.ScanCode == SCAN_NULL) {
      if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
        //
        // Add the null terminator.
        //
        Name[NameLen] = 0;
        NameLen++;
        break;
      } else if ((Key.UnicodeChar == CHAR_NULL) ||
                 (Key.UnicodeChar == CHAR_TAB) ||
                 (Key.UnicodeChar == CHAR_LINEFEED)
                 ) {
        continue;
      } else {
        if (Key.UnicodeChar == CHAR_BACKSPACE) {
          if (NameLen > 0) {
            NameLen--;
          }
        } else {
          Name[NameLen] = Key.UnicodeChar;
          NameLen++;
          if (NameLen + 1 == USER_NAME_LENGTH) {
            //
            // Add the null terminator.
            //
            Name[NameLen] = 0;
            NameLen++;
            break;
          }
        }
      }
    }

    if (Key.ScanCode == SCAN_ESC) {
      return EFI_ABORTED;
    }
  }

  if (NameLen <= 1) {
    return EFI_NOT_READY;
  }

  if (*UserNameLen < NameLen * sizeof (CHAR16)) {
    return EFI_NOT_READY;
  }

  *UserNameLen = NameLen * sizeof (CHAR16);
  CopyMem (UserName, Name, *UserNameLen);
  
  return EFI_SUCCESS;
}

/**
  Set a user's username.

  @param[in]   User          Handle of a user profile .
  @param[in]   UserNameLen   The lengh of UserName.
  @param[in]   UserName      Point to the buffer of user name.

  @retval EFI_NOT_READY      The usernme in mAddUserName had been used.
  @retval EFI_SUCCESS        Change the user's username successfully with 
                             username in mAddUserName.

**/
EFI_STATUS
SetUserName (
  IN  EFI_USER_PROFILE_HANDLE    User,
  IN  UINTN                      UserNameLen,
  IN  CHAR16                     *UserName
  )
{
  EFI_STATUS              Status;
  EFI_USER_INFO_HANDLE    UserInfo;
  EFI_USER_PROFILE_HANDLE TempUser;
  EFI_USER_INFO           *NewUserInfo;
   
  NewUserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + UserNameLen);
  ASSERT (NewUserInfo != NULL);

  NewUserInfo->InfoType    = EFI_USER_INFO_NAME_RECORD;
  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | 
                             EFI_USER_INFO_PUBLIC | 
                             EFI_USER_INFO_EXCLUSIVE;
  NewUserInfo->InfoSize    = (UINT32) (sizeof (EFI_USER_INFO) + UserNameLen);
  CopyMem ((UINT8 *) (NewUserInfo + 1), UserName, UserNameLen);
  TempUser  = NULL;
  Status    = mUserManager->Find (
                              mUserManager,
                              &TempUser,
                              NULL,
                              NewUserInfo,
                              NewUserInfo->InfoSize
                              );
  if (!EFI_ERROR (Status)) {
    //
    // The user name had been used, return error.
    //
    FreePool (NewUserInfo);
    return EFI_NOT_READY;
  }

  UserInfo = NULL;
  mUserManager->SetInfo (
                  mUserManager,
                  User,
                  &UserInfo,
                  NewUserInfo,
                  NewUserInfo->InfoSize
                  );
  FreePool (NewUserInfo);
  return EFI_SUCCESS;
}


/**
  Set create date of the specified user.

  @param[in]  User               Handle of a user profile.

**/
VOID
SetCreateDate (
  IN        EFI_USER_PROFILE_HANDLE   User
  )
{
  EFI_STATUS                Status;
  EFI_USER_INFO_HANDLE      UserInfo;
  EFI_USER_INFO_CREATE_DATE Date;
  EFI_USER_INFO             *NewUserInfo;
  
  NewUserInfo = AllocateZeroPool (
                  sizeof (EFI_USER_INFO) +
                  sizeof (EFI_USER_INFO_CREATE_DATE)
                  );
  ASSERT (NewUserInfo != NULL);

  NewUserInfo->InfoType    = EFI_USER_INFO_CREATE_DATE_RECORD;
  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | 
                             EFI_USER_INFO_PUBLIC | 
                             EFI_USER_INFO_EXCLUSIVE;
  NewUserInfo->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);
  Status                   = gRT->GetTime (&Date, NULL);
  if (EFI_ERROR (Status)) {
    FreePool (NewUserInfo);
    return ;
  }

  CopyMem ((UINT8 *) (NewUserInfo + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE));
  UserInfo = NULL;
  mUserManager->SetInfo (
                  mUserManager,
                  User,
                  &UserInfo,
                  NewUserInfo,
                  NewUserInfo->InfoSize
                  );
  FreePool (NewUserInfo);
}


/**
  Set the default identity policy of the specified user.

  @param[in]  User               Handle of a user profile. 

**/
VOID
SetIdentityPolicy (
  IN        EFI_USER_PROFILE_HANDLE   User
  )
{
  EFI_USER_INFO_IDENTITY_POLICY *Policy;
  EFI_USER_INFO_HANDLE          UserInfo;
  EFI_USER_INFO                 *NewUserInfo;
  
  NewUserInfo = AllocateZeroPool (
                  sizeof (EFI_USER_INFO) + 
                  sizeof (EFI_USER_INFO_IDENTITY_POLICY)
                  );
  ASSERT (NewUserInfo != NULL);
  
  Policy                   = (EFI_USER_INFO_IDENTITY_POLICY *) (NewUserInfo + 1);
  Policy->Type             = EFI_USER_INFO_IDENTITY_TRUE;
  Policy->Length           = sizeof (EFI_USER_INFO_IDENTITY_POLICY);

  NewUserInfo->InfoType    = EFI_USER_INFO_IDENTITY_POLICY_RECORD;
  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | 
                             EFI_USER_INFO_PUBLIC | 
                             EFI_USER_INFO_EXCLUSIVE;
  NewUserInfo->InfoSize    = sizeof (EFI_USER_INFO) + Policy->Length;
  UserInfo                 = NULL;
  mUserManager->SetInfo (
                  mUserManager,
                  User,
                  &UserInfo,
                  NewUserInfo,
                  NewUserInfo->InfoSize
                  );
  FreePool (NewUserInfo);
}


/**
  Set the default access policy of the specified user.

  @param[in]  User               Handle of a user profile. 

**/
VOID
SetAccessPolicy (
  IN        EFI_USER_PROFILE_HANDLE   User
  )
{
  EFI_USER_INFO_ACCESS_CONTROL  *Control;
  EFI_USER_INFO_HANDLE          UserInfo;
  EFI_USER_INFO                 *NewUserInfo;
  
  NewUserInfo = AllocateZeroPool (
                  sizeof (EFI_USER_INFO) + 
                  sizeof (EFI_USER_INFO_ACCESS_CONTROL)
                  );
  ASSERT (NewUserInfo != NULL);
  
  Control                  = (EFI_USER_INFO_ACCESS_CONTROL *) (NewUserInfo + 1);
  Control->Type            = EFI_USER_INFO_ACCESS_ENROLL_SELF;
  Control->Size            = sizeof (EFI_USER_INFO_ACCESS_CONTROL);

  NewUserInfo->InfoType    = EFI_USER_INFO_ACCESS_POLICY_RECORD;
  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | 
                             EFI_USER_INFO_PUBLIC | 
                             EFI_USER_INFO_EXCLUSIVE;
  NewUserInfo->InfoSize    = sizeof (EFI_USER_INFO) + Control->Size;
  UserInfo                 = NULL;
  mUserManager->SetInfo (
                  mUserManager,
                  User,
                  &UserInfo,
                  NewUserInfo,
                  NewUserInfo->InfoSize
                  );
  FreePool (NewUserInfo);
}


/**
  Add a new user profile into the user profile database.

**/
VOID
CallAddUser (
  VOID
  )
{
  EFI_STATUS              Status;
  EFI_INPUT_KEY           Key;
  EFI_USER_PROFILE_HANDLE User;
  UINTN                   UserNameLen;
  CHAR16                  UserName[USER_NAME_LENGTH];
  CHAR16                  *QuestionStr;
  CHAR16                  *PromptStr;

  QuestionStr = NULL;
  PromptStr   = NULL;
  
  //
  // Get user name to add.
  //
  UserNameLen = sizeof (UserName);
  Status = GetUserNameInput (&UserNameLen, UserName);
  if (EFI_ERROR (Status)) {
    if (Status != EFI_ABORTED) {
      QuestionStr = GetStringById (STRING_TOKEN (STR_GET_USERNAME_FAILED));
      PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); 
      goto Done;
    }
    return ;
  }

  //
  // Create a new user profile.
  //
  User    = NULL;
  Status  = mUserManager->Create (mUserManager, &User);
  if (EFI_ERROR (Status)) {
    QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_FAILED));
    PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); 
  } else {
    //
    // Add default user information.
    //
    Status = SetUserName (User, UserNameLen, UserName);
    if (EFI_ERROR (Status)) {
      QuestionStr = GetStringById (STRING_TOKEN (STR_USER_ALREADY_EXISTED));
      PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); 
      goto Done;
    }

    SetCreateDate (User);
    SetIdentityPolicy (User);
    SetAccessPolicy (User);

    QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_SUCCESS));
    PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); 
  }

Done:
  CreatePopUp (
    EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    &Key,
    QuestionStr,
    L"",
    PromptStr,
    NULL
    );
  FreePool (QuestionStr);
  FreePool (PromptStr);
}