///////////////////////////////////////////////////////////////////////////////
///
//          STFSd_open
///
/// \brief  Opens an existing STFS file
///
/// \param const char                *pp_Path, 
/// \param int                        pv_OFlag, 
/// \param                            pv_OpenerNodeId,
/// \param                            pv_OpenerPID,
/// \param STFS_ExternalFileMetadata *&pp_Efm,
/// \param STFS_FragmentFileMetadata *&pp_Ffm,
/// \param STFS_OpenIdentifier       *&pp_OpenId)
/// 
///////////////////////////////////////////////////////////////////////////////
int
STFSd_open(const char                 *pp_Path, 
           int                         pv_OFlag, 
           int                         pv_OpenerNodeId,
           int                         pv_OpenerPID,
           STFS_ExternalFileMetadata *&pp_Efm,
           STFS_FragmentFileMetadata *&pp_Ffm,
           STFS_OpenIdentifier       *&pp_OpenId)
{
  const char     *WHERE = "STFSd_open";
  STFS_ScopeTrace lv_st(WHERE);
  STFS_Session *lp_Session = STFS_Session::GetSession();

  int  lv_Ret = 0;

  if (!pp_Path) {
    errno = EINVAL;
    char lp_ErrMess[] = "Error Path is NULL";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -1;
  }

  char lp_Path[STFS_PATH_MAX];
  strcpy(lp_Path, pp_Path);
  STFS_ExternalFileMetadata *lp_Efm = STFS_ExternalFileMetadata::GetFromContainer(lp_Path);
  if(!lp_Efm) {
    TRACE_PRINTF2(1,"%s\n", "Error getting lp_Efm");

    errno = EINVAL;
    char lp_ErrMess[] = "Error getting lp_Efm";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -2;
  }
  
  TRACE_PRINTF4(2,
                "FileName: %s, Opener Node Id: %d, Opener SQ PID: %d\n",
                lp_Efm->ExternalFileNameGet(),
                pv_OpenerNodeId,
                pv_OpenerPID);

  STFS_util::ValidateEFM(lp_Efm);

  if(!lp_Efm->FileAvailableGet()) {
    TRACE_PRINTF2(1, "File: %s is no longer available\n", pp_Path);
    errno = ENOENT;
    char lp_ErrMess[] = "Error file is no longer available";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -1;
  }

  int lv_FragmentOffset = 0;
  //If O_APPEND, last fragment will be set open,
  if((pv_OFlag & O_APPEND) == O_APPEND) {
    lv_FragmentOffset = lp_Efm->GetNumFragments();
    if(lv_FragmentOffset == 0) {
      TRACE_PRINTF2(1,"%s\n", "Error Number of Fragments returned is 0");
      errno = ENOENT;
      char lp_ErrMess[] = "Error number of fragments returned is 0";
      lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
      return -3;
    }
    lv_FragmentOffset -= 1;
  }

  STFS_FragmentFileMetadata *lp_Ffm = lp_Efm->GetFragment(lv_FragmentOffset);
  if(!lp_Ffm) {
    errno = ENOENT;
    char lp_ErrMess[] = "Error obtaining fragment";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -4;
  }

  STFS_ExternalFileHandle *lp_Efh = lp_Efm->Open(true);
  if (!lp_Efh) {
    // TBD cleanup
    errno = ENOENT;
    char lp_ErrMess[] = "Error allocating EFH";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -5;
  }

  lv_Ret = StoreOpenerInfo(lp_Efm,
                           pv_OpenerNodeId,
                           pv_OpenerPID,
                           pp_OpenId);
  if (lv_Ret < 0) {
    //TBD cleanup
    errno = ENOENT;
    char lp_ErrMess[] = "Error storing opener information";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -6;
  }

  pp_Efm = lp_Efm;
  pp_Ffm = lp_Ffm;
  
  //Build Success Reply
  return 0;
}
///////////////////////////////////////////////////////////////////////////////
///
//          STFSd_mkstemp
///
/// \brief  Processes an mkstemp request
///         - Generates an external file name
///         
/// \param int                        *pp_Ctemplate,
/// \param int                         pv_OpenerNodeId,
/// \param int                         pv_OpenerPID,
/// \param STFS_ExternalFileMetadata *&pp_Efm,
/// \param STFS_OpenIdentifier       *&pp_OpenId)
///
/// 
///////////////////////////////////////////////////////////////////////////////
int
STFSd_mkstemp(char                       *pp_Ctemplate,
              int                         pv_OpenerNodeId,
              int                         pv_OpenerPID,
              STFS_ExternalFileMetadata *&pp_Efm,
              STFS_OpenIdentifier       *&pp_OpenId)
{

  /////////////////////////////////
  /// parameter checking and housekeeping
  /////////////////////////////////

  const char     *WHERE = "STFSd_mkstemp";
  STFS_ScopeTrace lv_st(WHERE);
  STFS_Session *lp_Session = STFS_Session::GetSession();

  int  lv_Ret = 0;

  if (!pp_Ctemplate) {
    errno = EFAULT;
    lp_Session->SetError(true, errno, 0, NULL, 0);
    return -1;
  }

  /// Generate the file name
  lv_Ret = STFS_util::GenerateExternalFilename(pp_Ctemplate);
  if (lv_Ret < 0) {
    errno = EINVAL;
    char lp_ErrMess[] = "Error generating external file name";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -2;
  }

  /////////////////////////////////
  /// Reserve the name
  /////////////////////////////////

  // We're the owning daemon process, so we need to reserve the name
  lv_Ret =  STFS_File::ReserveName (pp_Ctemplate);

  if (lv_Ret<0) {
    errno = EIO;

    char lp_ErrMess[] = "Error while reserving name";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    
    //name exists?  Couldn't talk to the disk?  WhatEVer...  Hope that
    //ReserveName packed the error correctly...
    return -6;

  }

  /////////////////////////////////
  /// Create the EFM for the file
  /////////////////////////////////

  STFS_ExternalFileMetadata *lp_Efm = new STFS_ExternalFileMetadata(pp_Ctemplate,
                                                                    STFS_util::GetMyNodeId());

  if (lp_Efm == NULL) {

    //Could not find/allocate EFM, probably doesn't exist
    errno = ENOENT;
    char lp_ErrMess[] = "Error allocating EFM";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));

    //UhOh, couldn't allocate an EFM!  Gotta free the directory we created
    STFS_File::ReleaseName (pp_Ctemplate); // 
    return -7;
  }

  TRACE_PRINTF4(2,
                "FileName: %s, Opener Node Id: %d, Opener SQ PID: %d\n",
                lp_Efm->ExternalFileNameGet(),
                pv_OpenerNodeId,
                pv_OpenerPID);

  /////////////////////////////////
  ///insert EFM in a global map
  /////////////////////////////////

  lv_Ret = STFS_ExternalFileMetadata::InsertIntoContainer(lp_Efm);
  if (lv_Ret < 0) {
    //TBD cleanup
    //Could not insert into EFM Container... 
    errno = ENOMEM;
    char lp_ErrMess[] = "Error Insertnig EFM into EFM Container";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -4;
  }

  /////////////////////////////////
  /// Store the opener info in the EFM
  /////////////////////////////////

  lv_Ret = StoreOpenerInfo(lp_Efm,
                           pv_OpenerNodeId,
                           pv_OpenerPID,
                           pp_OpenId);
  if (lv_Ret < 0) {
    //TBD cleanup
    //Could not store opener information
    errno = ENOMEM;
    char lp_ErrMess[] = "Error storing opener information";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -5;
  }

  /////////////////////////////////
  /// Create the fragment
  /////////////////////////////////

  if (STFSd_createFragment(lp_Efm,
                           pv_OpenerNodeId,
                           pv_OpenerPID,
                           0) < 0) {
    //Could not create fragment
    errno = EIO;
    char lp_ErrMess[] = "Error creating fragment";
    lp_Session->SetError(true, errno, 0, lp_ErrMess, strlen(lp_ErrMess));
    return -3;
  }


  STFS_util::ValidateEFM(lp_Efm);


  pp_Efm = lp_Efm;
  return 0;
}