// @(#)root/netx:$Id$
// Author: A. Peters, G. Ganis   7/2/2007

/*************************************************************************
 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TXNetFileStager                                                      //
//                                                                      //
// Interface to the 'XRD' staging capabilities.                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TError.h"
#include "TObjString.h"
#include "TUrl.h"
#include "TXNetFileStager.h"
#include "TXNetSystem.h"
#include "TFileCollection.h"
#include "TStopwatch.h"
#include "TFileInfo.h"

//_____________________________________________________________________________
TXNetFileStager::TXNetFileStager(const char *url) : TFileStager("xrd")
{
   // Constructor. Init a TXNetSystem instance to the XRD system.

   fSystem = 0;
   if (url && strlen(url) > 0) {
      GetPrefix(url, fPrefix);

      fSystem = new TXNetSystem(fPrefix);
   }
}

//_____________________________________________________________________________
TXNetFileStager::~TXNetFileStager()
{
   // Destructor

   if (fSystem)
      delete fSystem;
   fSystem = 0;
   fPrefix = "";
}

//_____________________________________________________________________________
Bool_t TXNetFileStager::IsStaged(const char *path)
{
   // Check if the file defined by 'path' is ready to be used.

   if (!IsValid()) {
      GetPrefix(path, fPrefix);
      fSystem = new TXNetSystem(path);
   }

   if (IsValid()) {
      TString p(path);
      if (!p.BeginsWith("root:"))
         p.Insert(0, fPrefix);
      return (fSystem->IsOnline(p));
   }

   // Failure
   Warning("IsStaged","TXNetSystem not initialized");
   return kFALSE;
}

//_____________________________________________________________________________
Bool_t TXNetFileStager::Stage(TCollection *paths, Option_t *opt)
{
   // Issue a stage request for file defined by 'path'. The string 'opt'
   // defines 'option' and 'priority' for 'Prepare': the format is
   //    opt = "option=o priority=p".

   if (IsValid()) {
      UChar_t o = 8;
      UChar_t p = 0;
      // Parse options, if any
      if (opt && strlen(opt) > 0) {
         TString xo(opt), io;
         Ssiz_t from = 0;
         while (xo.Tokenize(io, from, "[ ,|]")) {
            if (io.Contains("option=")) {
               io.ReplaceAll("option=","");
               if (io.IsDigit()) {
                  Int_t i = io.Atoi();
                  if (i >= 0 && i <= 255)
                     o = (UChar_t) i;
               }
            }
            if (io.Contains("priority=")) {
               io.ReplaceAll("priority=","");
               if (io.IsDigit()) {
                  Int_t i = io.Atoi();
                  if (i >= 0 && i <= 255)
                     p = (UChar_t) i;
               }
            }
         }
      }
      // Run prepare
      return fSystem->Prepare(paths, o, p);
   }

   // Failure
   Warning("Stage","TXNetSystem not initialized");
   return kFALSE;

}

//_____________________________________________________________________________
Bool_t TXNetFileStager::Stage(const char *path, Option_t *opt)
{
   // Issue a stage request for file defined by 'path'. The string 'opt'
   // defines 'option' and 'priority' for 'Prepare': the format is
   //                opt = "option=o priority=p".

   if (!IsValid()) {
      GetPrefix(path, fPrefix);
      fSystem = new TXNetSystem(path);
   }

   if (IsValid()) {
      UChar_t o = 8;  // XrdProtocol.hh
      UChar_t p = 0;
      // Parse options
      TString xo(opt), io;
      Ssiz_t from = 0;
      while (xo.Tokenize(io, from, "[ ,|]")) {
         if (io.Contains("option=")) {
            io.ReplaceAll("option=","");
            if (io.IsDigit()) {
               Int_t i = io.Atoi();
               if (i >= 0 && i <= 255)
                  o = (UChar_t) i;
            }
         }
         if (io.Contains("priority=")) {
            io.ReplaceAll("priority=","");
            if (io.IsDigit()) {
               Int_t i = io.Atoi();
               if (i >= 0 && i <= 255)
                  p = (UChar_t) i;
            }
         }
      }
      // Make user the full path is used
      TString pp(path);
      if (!pp.BeginsWith("root:"))
         pp.Insert(0, fPrefix);
      return fSystem->Prepare(pp, o, p);
   }

   // Failure
   Warning("Stage","TXNetSystem not initialized");
   return kFALSE;
}

//_____________________________________________________________________________
void TXNetFileStager::GetPrefix(const char *url, TString &pfx)
{
   // Isolate prefix in url

   if (gDebug > 1)
      ::Info("TXNetFileStager::GetPrefix", "enter: %s", url);

   TUrl u(url);
   pfx = Form("%s://", u.GetProtocol());
   if (strlen(u.GetUser()) > 0)
      pfx += Form("%s@", u.GetUser());
   pfx += u.GetHost();
   if (u.GetPort() != TUrl("root://host").GetPort())
      pfx += Form(":%d", u.GetPort());
   pfx += "/";

   if (gDebug > 1)
      ::Info("TXNetFileStager::GetPrefix", "found prefix: %s", pfx.Data());
}

//_____________________________________________________________________________
void TXNetFileStager::Print(Option_t *) const
{
   // Print basic info about this stager

   Printf("+++ stager: %s  %s", GetName(), fPrefix.Data());
}

//______________________________________________________________________________
Int_t TXNetFileStager::Locate(const char *path, TString &eurl)
{
   // Get actual end-point url for a path
   // Returns 0 in case of success and 1 if any error occured

   if (!IsValid()) {
      GetPrefix(path, fPrefix);
      fSystem = new TXNetSystem(path);
   }

   if (IsValid())
      return fSystem->Locate(path, eurl);

   // Unable to initialize TXNetSystem
   return -1;
}

//_____________________________________________________________________________
Int_t TXNetFileStager::LocateCollection(TFileCollection *fc,
   Bool_t addDummyUrl)
{
   // Bulk locate request for a collection of files. A noop prepare command is
   // issued beforehand to fill redirector's cache, then Locate() is issued on
   // each file. Results are saved back to the input collection: when a file is
   // found, the staged bit is set to on, and its endpoint URL is added, if
   // different from the redirector's URL. If a file is not found, the staged
   // bit is set to off.
   // If addDummyUrl is kTRUE, in case file is not staged or redirector is
   // identical to endpoint URL, a dummy URL is prepended, respectively:
   // "noop://redir" and "noop://none".
   // If the collection contains URLs with "anchors" (i.e., #fileName.root),
   // they are ignored by xrootd.
   // The Locate() command preserves anchors, but needs single paths to be full
   // URLs beginning with root://.
   // Returns < 0 in case of errors, and the number of files processed in case
   // of success.

   if (!fc) {
      Error("Locate", "No input collection given!");
      return -1;
   }

   // Fill redirector's cache with an empty prepare request
   //Int_t TXNetSystem::Prepare(TCollection *paths,
   //   UChar_t opt, UChar_t prio, TString *bufout)

   Int_t count = 0;

   TStopwatch ts;
   Double_t timeTaken_s;
   TFileInfo *fi;

   Int_t rv = fSystem->Prepare(fc->GetList(), 0, 0, NULL);
   //                                         o  p

   TIter it(fc->GetList());

   timeTaken_s = ts.RealTime();
   if (gDebug > 0) {
      Info("Locate", "Bulk xprep done in %.1lfs (returned %d)",
        ts.RealTime(), rv);
   }

   ts.Start();
   TString surl, endp;

   while ((fi = dynamic_cast<TFileInfo *>(it.Next())) != NULL) {

      surl = fi->GetCurrentUrl()->GetUrl();

      if (!IsValid()) {
         GetPrefix(surl.Data(), fPrefix);
         if (gDebug > 0) {
            Info("Locate", "Stager non initialized, doing it now for %s",
               fPrefix.Data());
         }
         fSystem = new TXNetSystem(surl.Data());
      }

      // Locating (0=success, 1=error -- 1 includes when file is not staged)
      if (fSystem->Locate(surl.Data(), endp)) {
         // File not staged
         fi->ResetBit(TFileInfo::kStaged);

         if (addDummyUrl)
            fi->AddUrl("noop://none", kTRUE);

         if (gDebug > 1)
            Info("Locate", "Not found: %s", surl.Data());
      }
      else {
         // File staged. Returned endpoint contains the same anchor and options.
         // We just check if it is equal to one of our current URLs.

         fi->SetBit(TFileInfo::kStaged);
         if (surl != endp) {
            fi->AddUrl(endp.Data(), kTRUE);
         }
         else if (addDummyUrl) {
            // Returned URL identical to redirector's URL
            fi->AddUrl("noop://redir", kTRUE);
         }

         if (gDebug > 1)
            Info("Locate", "Found: %s --> %s", surl.Data(), endp.Data());
      }

      count++;
   }

   timeTaken_s += ts.RealTime();
   if (gDebug > 0) {
      Info("Locate", "All locates finished in %.1lfs", ts.RealTime());
      Info("Locate", "Mass prepare and locates took %.1lfs", timeTaken_s);
   }

   return count;
}

//______________________________________________________________________________
Bool_t TXNetFileStager::Matches(const char *s)
{
   // Returns kTRUE if stager 's' is compatible with current stager.
   // Avoids multiple instantiations of the potentially the same TXNetSystem.

   if (IsValid()) {
      TString pfx;
      GetPrefix(s, pfx);
      return ((fPrefix == pfx) ? kTRUE : kFALSE);
   }

   // Not valid
   return kFALSE;
}
 TXNetFileStager.cxx:1
 TXNetFileStager.cxx:2
 TXNetFileStager.cxx:3
 TXNetFileStager.cxx:4
 TXNetFileStager.cxx:5
 TXNetFileStager.cxx:6
 TXNetFileStager.cxx:7
 TXNetFileStager.cxx:8
 TXNetFileStager.cxx:9
 TXNetFileStager.cxx:10
 TXNetFileStager.cxx:11
 TXNetFileStager.cxx:12
 TXNetFileStager.cxx:13
 TXNetFileStager.cxx:14
 TXNetFileStager.cxx:15
 TXNetFileStager.cxx:16
 TXNetFileStager.cxx:17
 TXNetFileStager.cxx:18
 TXNetFileStager.cxx:19
 TXNetFileStager.cxx:20
 TXNetFileStager.cxx:21
 TXNetFileStager.cxx:22
 TXNetFileStager.cxx:23
 TXNetFileStager.cxx:24
 TXNetFileStager.cxx:25
 TXNetFileStager.cxx:26
 TXNetFileStager.cxx:27
 TXNetFileStager.cxx:28
 TXNetFileStager.cxx:29
 TXNetFileStager.cxx:30
 TXNetFileStager.cxx:31
 TXNetFileStager.cxx:32
 TXNetFileStager.cxx:33
 TXNetFileStager.cxx:34
 TXNetFileStager.cxx:35
 TXNetFileStager.cxx:36
 TXNetFileStager.cxx:37
 TXNetFileStager.cxx:38
 TXNetFileStager.cxx:39
 TXNetFileStager.cxx:40
 TXNetFileStager.cxx:41
 TXNetFileStager.cxx:42
 TXNetFileStager.cxx:43
 TXNetFileStager.cxx:44
 TXNetFileStager.cxx:45
 TXNetFileStager.cxx:46
 TXNetFileStager.cxx:47
 TXNetFileStager.cxx:48
 TXNetFileStager.cxx:49
 TXNetFileStager.cxx:50
 TXNetFileStager.cxx:51
 TXNetFileStager.cxx:52
 TXNetFileStager.cxx:53
 TXNetFileStager.cxx:54
 TXNetFileStager.cxx:55
 TXNetFileStager.cxx:56
 TXNetFileStager.cxx:57
 TXNetFileStager.cxx:58
 TXNetFileStager.cxx:59
 TXNetFileStager.cxx:60
 TXNetFileStager.cxx:61
 TXNetFileStager.cxx:62
 TXNetFileStager.cxx:63
 TXNetFileStager.cxx:64
 TXNetFileStager.cxx:65
 TXNetFileStager.cxx:66
 TXNetFileStager.cxx:67
 TXNetFileStager.cxx:68
 TXNetFileStager.cxx:69
 TXNetFileStager.cxx:70
 TXNetFileStager.cxx:71
 TXNetFileStager.cxx:72
 TXNetFileStager.cxx:73
 TXNetFileStager.cxx:74
 TXNetFileStager.cxx:75
 TXNetFileStager.cxx:76
 TXNetFileStager.cxx:77
 TXNetFileStager.cxx:78
 TXNetFileStager.cxx:79
 TXNetFileStager.cxx:80
 TXNetFileStager.cxx:81
 TXNetFileStager.cxx:82
 TXNetFileStager.cxx:83
 TXNetFileStager.cxx:84
 TXNetFileStager.cxx:85
 TXNetFileStager.cxx:86
 TXNetFileStager.cxx:87
 TXNetFileStager.cxx:88
 TXNetFileStager.cxx:89
 TXNetFileStager.cxx:90
 TXNetFileStager.cxx:91
 TXNetFileStager.cxx:92
 TXNetFileStager.cxx:93
 TXNetFileStager.cxx:94
 TXNetFileStager.cxx:95
 TXNetFileStager.cxx:96
 TXNetFileStager.cxx:97
 TXNetFileStager.cxx:98
 TXNetFileStager.cxx:99
 TXNetFileStager.cxx:100
 TXNetFileStager.cxx:101
 TXNetFileStager.cxx:102
 TXNetFileStager.cxx:103
 TXNetFileStager.cxx:104
 TXNetFileStager.cxx:105
 TXNetFileStager.cxx:106
 TXNetFileStager.cxx:107
 TXNetFileStager.cxx:108
 TXNetFileStager.cxx:109
 TXNetFileStager.cxx:110
 TXNetFileStager.cxx:111
 TXNetFileStager.cxx:112
 TXNetFileStager.cxx:113
 TXNetFileStager.cxx:114
 TXNetFileStager.cxx:115
 TXNetFileStager.cxx:116
 TXNetFileStager.cxx:117
 TXNetFileStager.cxx:118
 TXNetFileStager.cxx:119
 TXNetFileStager.cxx:120
 TXNetFileStager.cxx:121
 TXNetFileStager.cxx:122
 TXNetFileStager.cxx:123
 TXNetFileStager.cxx:124
 TXNetFileStager.cxx:125
 TXNetFileStager.cxx:126
 TXNetFileStager.cxx:127
 TXNetFileStager.cxx:128
 TXNetFileStager.cxx:129
 TXNetFileStager.cxx:130
 TXNetFileStager.cxx:131
 TXNetFileStager.cxx:132
 TXNetFileStager.cxx:133
 TXNetFileStager.cxx:134
 TXNetFileStager.cxx:135
 TXNetFileStager.cxx:136
 TXNetFileStager.cxx:137
 TXNetFileStager.cxx:138
 TXNetFileStager.cxx:139
 TXNetFileStager.cxx:140
 TXNetFileStager.cxx:141
 TXNetFileStager.cxx:142
 TXNetFileStager.cxx:143
 TXNetFileStager.cxx:144
 TXNetFileStager.cxx:145
 TXNetFileStager.cxx:146
 TXNetFileStager.cxx:147
 TXNetFileStager.cxx:148
 TXNetFileStager.cxx:149
 TXNetFileStager.cxx:150
 TXNetFileStager.cxx:151
 TXNetFileStager.cxx:152
 TXNetFileStager.cxx:153
 TXNetFileStager.cxx:154
 TXNetFileStager.cxx:155
 TXNetFileStager.cxx:156
 TXNetFileStager.cxx:157
 TXNetFileStager.cxx:158
 TXNetFileStager.cxx:159
 TXNetFileStager.cxx:160
 TXNetFileStager.cxx:161
 TXNetFileStager.cxx:162
 TXNetFileStager.cxx:163
 TXNetFileStager.cxx:164
 TXNetFileStager.cxx:165
 TXNetFileStager.cxx:166
 TXNetFileStager.cxx:167
 TXNetFileStager.cxx:168
 TXNetFileStager.cxx:169
 TXNetFileStager.cxx:170
 TXNetFileStager.cxx:171
 TXNetFileStager.cxx:172
 TXNetFileStager.cxx:173
 TXNetFileStager.cxx:174
 TXNetFileStager.cxx:175
 TXNetFileStager.cxx:176
 TXNetFileStager.cxx:177
 TXNetFileStager.cxx:178
 TXNetFileStager.cxx:179
 TXNetFileStager.cxx:180
 TXNetFileStager.cxx:181
 TXNetFileStager.cxx:182
 TXNetFileStager.cxx:183
 TXNetFileStager.cxx:184
 TXNetFileStager.cxx:185
 TXNetFileStager.cxx:186
 TXNetFileStager.cxx:187
 TXNetFileStager.cxx:188
 TXNetFileStager.cxx:189
 TXNetFileStager.cxx:190
 TXNetFileStager.cxx:191
 TXNetFileStager.cxx:192
 TXNetFileStager.cxx:193
 TXNetFileStager.cxx:194
 TXNetFileStager.cxx:195
 TXNetFileStager.cxx:196
 TXNetFileStager.cxx:197
 TXNetFileStager.cxx:198
 TXNetFileStager.cxx:199
 TXNetFileStager.cxx:200
 TXNetFileStager.cxx:201
 TXNetFileStager.cxx:202
 TXNetFileStager.cxx:203
 TXNetFileStager.cxx:204
 TXNetFileStager.cxx:205
 TXNetFileStager.cxx:206
 TXNetFileStager.cxx:207
 TXNetFileStager.cxx:208
 TXNetFileStager.cxx:209
 TXNetFileStager.cxx:210
 TXNetFileStager.cxx:211
 TXNetFileStager.cxx:212
 TXNetFileStager.cxx:213
 TXNetFileStager.cxx:214
 TXNetFileStager.cxx:215
 TXNetFileStager.cxx:216
 TXNetFileStager.cxx:217
 TXNetFileStager.cxx:218
 TXNetFileStager.cxx:219
 TXNetFileStager.cxx:220
 TXNetFileStager.cxx:221
 TXNetFileStager.cxx:222
 TXNetFileStager.cxx:223
 TXNetFileStager.cxx:224
 TXNetFileStager.cxx:225
 TXNetFileStager.cxx:226
 TXNetFileStager.cxx:227
 TXNetFileStager.cxx:228
 TXNetFileStager.cxx:229
 TXNetFileStager.cxx:230
 TXNetFileStager.cxx:231
 TXNetFileStager.cxx:232
 TXNetFileStager.cxx:233
 TXNetFileStager.cxx:234
 TXNetFileStager.cxx:235
 TXNetFileStager.cxx:236
 TXNetFileStager.cxx:237
 TXNetFileStager.cxx:238
 TXNetFileStager.cxx:239
 TXNetFileStager.cxx:240
 TXNetFileStager.cxx:241
 TXNetFileStager.cxx:242
 TXNetFileStager.cxx:243
 TXNetFileStager.cxx:244
 TXNetFileStager.cxx:245
 TXNetFileStager.cxx:246
 TXNetFileStager.cxx:247
 TXNetFileStager.cxx:248
 TXNetFileStager.cxx:249
 TXNetFileStager.cxx:250
 TXNetFileStager.cxx:251
 TXNetFileStager.cxx:252
 TXNetFileStager.cxx:253
 TXNetFileStager.cxx:254
 TXNetFileStager.cxx:255
 TXNetFileStager.cxx:256
 TXNetFileStager.cxx:257
 TXNetFileStager.cxx:258
 TXNetFileStager.cxx:259
 TXNetFileStager.cxx:260
 TXNetFileStager.cxx:261
 TXNetFileStager.cxx:262
 TXNetFileStager.cxx:263
 TXNetFileStager.cxx:264
 TXNetFileStager.cxx:265
 TXNetFileStager.cxx:266
 TXNetFileStager.cxx:267
 TXNetFileStager.cxx:268
 TXNetFileStager.cxx:269
 TXNetFileStager.cxx:270
 TXNetFileStager.cxx:271
 TXNetFileStager.cxx:272
 TXNetFileStager.cxx:273
 TXNetFileStager.cxx:274
 TXNetFileStager.cxx:275
 TXNetFileStager.cxx:276
 TXNetFileStager.cxx:277
 TXNetFileStager.cxx:278
 TXNetFileStager.cxx:279
 TXNetFileStager.cxx:280
 TXNetFileStager.cxx:281
 TXNetFileStager.cxx:282
 TXNetFileStager.cxx:283
 TXNetFileStager.cxx:284
 TXNetFileStager.cxx:285
 TXNetFileStager.cxx:286
 TXNetFileStager.cxx:287
 TXNetFileStager.cxx:288
 TXNetFileStager.cxx:289
 TXNetFileStager.cxx:290
 TXNetFileStager.cxx:291
 TXNetFileStager.cxx:292
 TXNetFileStager.cxx:293
 TXNetFileStager.cxx:294
 TXNetFileStager.cxx:295
 TXNetFileStager.cxx:296
 TXNetFileStager.cxx:297
 TXNetFileStager.cxx:298
 TXNetFileStager.cxx:299
 TXNetFileStager.cxx:300
 TXNetFileStager.cxx:301
 TXNetFileStager.cxx:302
 TXNetFileStager.cxx:303
 TXNetFileStager.cxx:304
 TXNetFileStager.cxx:305
 TXNetFileStager.cxx:306
 TXNetFileStager.cxx:307
 TXNetFileStager.cxx:308
 TXNetFileStager.cxx:309
 TXNetFileStager.cxx:310
 TXNetFileStager.cxx:311
 TXNetFileStager.cxx:312
 TXNetFileStager.cxx:313
 TXNetFileStager.cxx:314
 TXNetFileStager.cxx:315
 TXNetFileStager.cxx:316
 TXNetFileStager.cxx:317
 TXNetFileStager.cxx:318
 TXNetFileStager.cxx:319
 TXNetFileStager.cxx:320
 TXNetFileStager.cxx:321
 TXNetFileStager.cxx:322
 TXNetFileStager.cxx:323
 TXNetFileStager.cxx:324
 TXNetFileStager.cxx:325
 TXNetFileStager.cxx:326
 TXNetFileStager.cxx:327
 TXNetFileStager.cxx:328
 TXNetFileStager.cxx:329