Added methods for finding a given module in the DDL map (F. Prino)
[u/mrichter/AliRoot.git] / STEER / AliSurveyObj.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /////////////////////////////////////////////////////////////////////
17 //                                                                 //
18 //  class AliSurveyObj                                             //
19 //  Retrieve and Convert survey data into ROOT Objects             //
20 //                                                                 //
21 /////////////////////////////////////////////////////////////////////
22
23 #include "AliSurveyObj.h"
24
25 //ROOT includes
26 //#include "TROOT.h"
27 //#include "Riostream.h"
28 #include "TObjArray.h"
29 #include "TGrid.h"
30 #include "TGridResult.h"
31 #include "TFile.h"
32 #include "TObjString.h"
33
34 //AliROOT includes
35 #include "AliLog.h"
36 #include "AliSurveyPoint.h"
37
38 ClassImp(AliSurveyObj)
39
40
41 const TString AliSurveyObj::fgkStorage = "alien://alice.cern.ch";  
42 const TString AliSurveyObj::fgkBaseFolder = "/alice/data/Reference";
43 const TString AliSurveyObj::fgkValidDetectors = "ACORDE,BABYFRAME,BACKFRAME,\
44 EMCAL,FMD,HMPID,ITS,L3 MAGNET,MUON,MUON ABSORBERS,MUON DIPOLE,PHOS,PMD,\
45 SPACEFRAME,SUPERSTRUCTURE,T0,TOF,TPC,TRD,V0,ZDC,GRP";
46 const TString AliSurveyObj::fgkGRPDetectors = "BABYFRAME,BACKFRAME,L3 MAGNET,\
47 SPACEFRAME,MUON DIPOLE,MUON ABSORBERS,GRP";
48 const TString AliSurveyObj::fgkMUONDetectors = "MUON,SUPERSTRUCTURE";
49
50   
51 //_____________________________________________________________________________
52 AliSurveyObj::AliSurveyObj():
53   TObject(),
54   fTitle(""),
55   fDate(""),
56   fDetector(""),
57   fURL("http://edms.cern.ch/"),
58   fReportNr(-1),
59   fVersion(-1),
60   fObs(""),
61   fCoordSys(""),
62   fUnits(""),
63   fNrColumns(-1),
64   fColNames(""),
65   fIsValid(kFALSE),
66   fGridUser(""),
67   fDataPoints(new TObjArray(1))
68 {
69   // constructor
70   fDataPoints->SetOwner(kTRUE);
71 }
72
73
74 //_____________________________________________________________________________
75 AliSurveyObj::~AliSurveyObj() {
76   //destructor
77   if (fDataPoints) {
78     fDataPoints->Delete();
79     fDataPoints = 0;
80   }
81 }
82
83
84 //_____________________________________________________________________________
85 AliSurveyObj::AliSurveyObj(const AliSurveyObj& surveyObj):
86   TObject(),
87   fTitle(surveyObj.fTitle),
88   fDate(surveyObj.fDate),
89   fDetector(surveyObj.fDetector),
90   fURL(surveyObj.fURL),
91   fReportNr(surveyObj.fReportNr),
92   fVersion(surveyObj.fVersion),
93   fObs(surveyObj.fObs),
94   fCoordSys(surveyObj.fCoordSys),
95   fUnits(surveyObj.fUnits),
96   fNrColumns(surveyObj.fNrColumns),
97   fColNames(surveyObj.fColNames),
98   fIsValid(surveyObj.fIsValid),
99   fGridUser(surveyObj.fGridUser),
100   fDataPoints(new TObjArray(1))
101 {
102   // copy constructor
103   TObject *curr = surveyObj.fDataPoints->First();
104   while (curr != 0) {
105     fDataPoints->Add(curr);
106     curr = surveyObj.fDataPoints->After(curr);
107   }
108 }
109
110
111 //_____________________________________________________________________________
112 AliSurveyObj& AliSurveyObj::operator=(const AliSurveyObj& surveyObj)
113 {
114   // assignment operator
115   if (this != &surveyObj) {
116     fTitle = surveyObj.fTitle;
117     fDate = surveyObj.fDate;
118     fDetector = surveyObj.fDetector;
119     fURL = surveyObj.fURL;
120     fReportNr = surveyObj.fReportNr;
121     fVersion = surveyObj.fVersion;
122     fObs = surveyObj.fObs;
123     fCoordSys = surveyObj.fCoordSys;
124     fUnits = surveyObj.fUnits;
125     fNrColumns = surveyObj.fNrColumns;
126     fColNames = surveyObj.fColNames;
127     fIsValid = surveyObj.fIsValid;
128     fGridUser = surveyObj.fGridUser;
129     TObject *curr = surveyObj.fDataPoints->First();
130     while (curr != 0) {
131       fDataPoints->Add(curr);
132       curr = surveyObj.fDataPoints->After(curr);
133     }
134   }
135   return *this;
136 }
137
138
139 //_____________________________________________________________________________
140 void AliSurveyObj::AddPoint(AliSurveyPoint* point) {
141   // Adds a point to the TObjArray which containst the list of points
142   fDataPoints->Add(point);
143   return;
144 }
145
146
147 //_____________________________________________________________________________
148 Bool_t AliSurveyObj::Connect(const char *gridUrl, const char *user) {
149   // Connects to the grid
150
151   // If the same "Grid" is alreay active, skip connection
152   if (!gGrid || gridUrl != gGrid->GridUrl() ||
153       (( user != "" ) && ( user != gGrid->GetUser() )) ) {
154     // connection to the Grid
155     AliInfo("\nConnecting to the Grid...");
156     if (gGrid) {
157       AliInfo(Form("gGrid = %x; GridUrl = %s; gGrid->GridUrl() = %s", 
158                    gGrid, gridUrl, gGrid->GridUrl()));
159       AliInfo(Form("User = %s; gGrid->GetUser() = %s",
160                    user, gGrid->GetUser()));
161     }
162     TGrid::Connect(gridUrl,user);
163   }
164         
165   if(!gGrid) {
166     AliError("Connection failed!");
167     return kFALSE;
168   }
169   return kTRUE;
170 }
171
172
173 //_____________________________________________________________________________
174 Bool_t AliSurveyObj::OpenFile(TString openString) {
175   // Opens the file and reads it to a buffer
176
177   Printf("Open string: \n -> \"%s\"\n", openString.Data());
178
179   if (openString.BeginsWith("alien://"))
180     if (!Connect(fgkStorage.Data(), fGridUser.Data())) {
181       AliError(Form("Error connecting to GRID"));
182       return kFALSE;
183     }
184
185   TFile *file = TFile::Open(openString.Data(), "READ");
186   if ( !file ) {
187     AliError(Form("Error opening file \"%s\"", openString.Data()));
188     return kFALSE;
189   }
190
191   Int_t size = file->GetSize();
192
193   char *buf = new Char_t[size + 1];
194   memset(buf, '\0', size + 1);
195
196   file->Seek(0);  
197   if ( file->ReadBuffer(buf, size) ) {
198     AliError("Error reading file contents to buffer!");
199     return kFALSE;
200   }
201   Printf("%d bytes read!\n", file->GetBytesRead());
202   
203   ParseBuffer(buf);
204
205   file->Close();
206   delete[] buf;
207   return kTRUE;
208 }
209
210
211 //_____________________________________________________________________________
212 Bool_t AliSurveyObj::FillFromLocalFile(const Char_t* filename) {
213   // Fills the object from a file in a local filesystem
214
215   TString fullOpenString = "file://" + TString(filename) + "?filetype=raw";
216
217   return OpenFile(fullOpenString);
218 }
219
220
221 //_____________________________________________________________________________
222 Bool_t AliSurveyObj::IsValidDetector(TString detector) const {
223   // Checks if the detector name is valid
224
225   detector.ToUpper();
226
227   TObjArray *dets = fgkValidDetectors.Tokenize(',');
228   TObject *found = dets->FindObject(detector);
229   dets->Delete();
230   dets = 0;
231
232   if (!found) return kFALSE;
233   else return kTRUE;
234 }
235
236
237 //_____________________________________________________________________________
238 TString AliSurveyObj::RealFolderName(TString detector) const {
239   // Returns the actual folder name for a given detector 
240   // Some "detectors" don't have a folder of their own
241
242   detector.ToUpper();
243   TString folderName = detector;
244
245   TObjArray *dets = fgkGRPDetectors.Tokenize(',');
246   if (dets->FindObject(detector)) folderName = "GRP";
247   dets->Delete();
248   dets = 0;
249
250   dets = fgkMUONDetectors.Tokenize(',');
251   if (dets->FindObject(detector)) folderName = "MUON";
252   dets->Delete();  
253  
254
255
256   dets = 0;
257
258   return folderName;
259 }
260
261 //_____________________________________________________________________________
262 Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber,
263                           TString username) {
264   // Fills the object from a file in the default storage location in AliEn.
265   // The highest version available is selected.
266
267   return Fill(detector, reportNumber, -1, username);
268 }
269
270 //_____________________________________________________________________________
271 Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber,
272                           Int_t reportVersion, TString username) {
273   // Fills the object from a file in the default storage location in AliEn.
274   // A specific version is selected.
275
276   detector.ToUpper();
277   
278   // Check if <detector> is valid
279   if (!IsValidDetector(detector)) {
280     AliWarning(Form("Detector '%s' is not a valid detector/structure!", detector.Data()));
281     return kFALSE;
282   }
283
284   // Some "detectors" don't have a folder of their own
285   // TString detectorFolder = RealFolderName(detector);
286
287   // Check if <year>, <reportNumber> and <reportVersion> are valid (roughly)
288   if ((reportNumber < 1) || (reportVersion < -1) || (0 == reportVersion)) {
289     AliError("Invalid parameter values for AliSurveyObj::Fill. (Report Number or Report Version)");
290     return kFALSE;
291   }
292
293   // Check if the fGridUser is set, or specified
294   if (username.Length() > 0) SetGridUser(username);
295   else if (0 == fGridUser.Length()) {
296     AliError("GRID username not specified and not previously set!");
297     return kFALSE;
298   }
299
300   // Query AliEn for the available reports
301   TGridResult *res = QueryReports(detector, -1, reportNumber, reportVersion);
302   if (!res) AliError(Form("Error querying AliEn for detector '%s', \
303                            report number '%d' and report version '%d'.",
304                           detector.Data(), reportNumber, reportVersion));
305   Int_t numberEntries = res->GetEntries();
306   if (0 == numberEntries) {
307     AliError(Form("No report found for detector '%s', report number '%d' and report version '%d'",
308                   detector.Data(), reportNumber, reportVersion));
309     return kFALSE;
310   }
311
312   TString fileNamePath = "";
313   if (1 == numberEntries) fileNamePath = res->GetFileNamePath(0);
314   else if (numberEntries > 1) {
315     TString higherVerFNP = res->GetFileNamePath(0);
316     Int_t lastYear = FileNamePathToReportYear(higherVerFNP);
317     for (Int_t i = 1; i < numberEntries; ++i) {
318       TString currFNP = res->GetFileNamePath(i);
319       if (FileNamePathToReportVersion(currFNP) >
320           FileNamePathToReportVersion(higherVerFNP)) higherVerFNP = currFNP;
321       if (lastYear != FileNamePathToReportYear(currFNP))
322         AliWarning("Inconsistency detected, year differs for reports with the same report number! Please inform the responsible and check the report against the one in DCDB.");
323     }
324     fileNamePath = higherVerFNP;
325   }
326
327   TString fullOpenString = "alien://" + fileNamePath + "?filetype=raw";
328   /*
329   // Finally composes the full string
330   TString fullOpenString = "alien://" + fgkBaseFolder + "/" + detectorFolder + "/RawSurvey/";
331   fullOpenString += Form("%d/%d_v%d.txt?filetype=raw", year, reportNumber, reportVersion);
332   */
333
334   return OpenFile(fullOpenString);
335 }
336
337
338 //_____________________________________________________________________________
339 TString AliSurveyObj::FileNamePathToDetector(TString filename) const {
340   // Get the report number from the complete path in the format:
341   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
342
343   TString ret = "";
344
345   if (filename.Length() > fgkBaseFolder.Length()) {
346     ret = filename.Remove(0, fgkBaseFolder.Length());
347     ret.Remove(TString::kLeading, '/');
348     ret = ret(0, ret.First('/'));
349     if (!IsValidDetector(ret)) ret = "";
350   } 
351   return ret;
352 }
353
354 ///alice/cern.ch/user/r/rsilva/TRD/RawSurvey/2007/.816582_v2.txt/v1.0
355
356 //_____________________________________________________________________________
357 Int_t AliSurveyObj::FileNamePathToReportYear(TString filename) const {
358   // Get the report year from the complete path in the format:
359   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
360
361   TString ret = "";
362
363   if (filename.Length() > fgkBaseFolder.Length()) {
364     ret = filename.Remove(0, fgkBaseFolder.Length());
365     ret.Remove(TString::kLeading, '/');
366     Int_t beg = ret.First('/') + TString("RawSurvey/").Length() + 1;
367     ret = ret(beg, ret.Last('/') - beg);
368     return ret.Atoi();
369   } 
370   return -1;
371 }
372
373
374 //_____________________________________________________________________________
375 Int_t AliSurveyObj::FileNamePathToReportNumber(TString filename) const {
376   // Get the report number from the complete path in the format:
377   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
378
379   TString ret = "";
380
381   if (filename.Length() > fgkBaseFolder.Length()) {
382     ret = filename.Remove(0, fgkBaseFolder.Length());
383     ret.Remove(TString::kLeading, '/');
384     if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) {
385       AliWarning("Error getting the Report Number from the filename path!");
386       return -1;
387     }
388     ret = ret(ret.Last('/') + 1 , ret.Last('_') - ret.Last('/') - 1);
389     return ret.Atoi();
390   } 
391   AliWarning("Error getting the Report Number from the filename path!");
392   return -1;
393 }
394
395
396 //_____________________________________________________________________________
397 Int_t AliSurveyObj::FileNamePathToReportVersion(TString filename) const {
398   // Get the report version from the complete path in the format:
399   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
400
401   TString ret = "";
402
403   if (filename.Length() > fgkBaseFolder.Length()) {
404     ret = filename.Remove(0, fgkBaseFolder.Length());
405     ret.Remove(TString::kLeading, '/');
406     if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) {
407       AliWarning("Error getting the Report Version from the filename path!");
408       return -1;
409     }
410     ret = ret(ret.Last('_') + 1 + 1 , ret.Last('.') - ret.Last('_') - 1 - 1);
411     return ret.Atoi();
412   } 
413   AliWarning("Error getting the Report Version from the filename path!");
414   return -1;
415 }
416
417
418 //_____________________________________________________________________________
419 void AliSurveyObj::ListValidDetectors() {
420   // List the valid detector names
421   Printf("");
422   Printf("Listing all valid detectors:\n");
423   TObjArray *dets = fgkValidDetectors.Tokenize(',');
424   for (int i = 0; i < dets->GetEntries(); ++i) 
425     Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
426   dets->Delete();
427   dets = 0;
428   Printf("");
429   Printf("Some reports are stored in more general folders.");
430   Printf("These reports can be opened using either name, the original or the");
431   Printf("folder name. Example: 'SPACEFRAME' or 'GRP' are both valid when");
432   Printf("opening a report for the Spaceframe.");
433   Printf("");
434   Printf("Detectors stored in 'MUON' folder:");
435   dets = fgkMUONDetectors.Tokenize(',');
436   for (int i = 0; i < dets->GetEntries(); ++i) 
437     Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
438   dets->Delete();
439   dets = 0;
440   Printf("");
441   Printf("Detectors stored in 'GRP' folder:");
442   dets = fgkGRPDetectors.Tokenize(',');
443   for (int i = 0; i < dets->GetEntries(); ++i) 
444     Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
445   dets->Delete();
446   dets = 0;
447   return;
448 }
449
450
451 //_____________________________________________________________________________
452 TGridResult * AliSurveyObj::QueryReports(TString detector, Int_t year,
453                                          Int_t reportNumber,
454                                          Int_t reportVersion) {
455   // Queries AliEn for existing reports matching the specified conditions
456   TString lsArg = fgkBaseFolder;
457   
458   TString detectorFolder = "";
459   if (detector.Length() > 0) {
460     detector.ToUpper();
461     // Check if <detector> is valid
462     if (!IsValidDetector(detector)) {
463       AliError(Form("Detector '%s' is not a valid detector/structure!",
464                     detector.Data()));
465       return 0;
466     }
467     // Some "detectors" don't have a folder of their own
468     detectorFolder = "/" + RealFolderName(detector);
469   } else detectorFolder = "/*";
470
471   lsArg += detectorFolder + "/RawSurvey";
472
473   TString yearFolder = "";
474   if (year > 1950) yearFolder.Form("/%d", year);
475   else yearFolder = "/*";
476
477   TString reportFolder = "";
478   if (reportNumber > 0) reportFolder.Form("/%d", reportNumber);
479   else reportFolder = "/*";
480
481   TString versionFolder = "";
482   if (reportVersion > 0) versionFolder.Form("_v%d", reportVersion);
483   else versionFolder = "_v*";
484
485   lsArg += yearFolder + reportFolder + versionFolder + ".txt";
486
487   Printf("");
488   Printf(Form("Looking for:  %s \n", lsArg.Data()));
489   
490   // Check if fGridUser is set and Connect to AliEn
491   if (0 == fGridUser.Length()) {
492     AliError("To use this method it's necessary to call SetGridUser(...) in advance.");
493     return 0;
494   } else if (!Connect(fgkStorage.Data(), fGridUser.Data())) {
495     AliError(Form("Error connecting to GRID"));
496     return 0;
497   }
498   return gGrid->Ls(lsArg);
499 }
500
501
502 //_____________________________________________________________________________
503 Int_t AliSurveyObj::ListReports(TString detector, Int_t year, 
504                                 Int_t reportNumber,
505                                 Int_t reportVersion) {
506   // Lists all available reports matching the specified conditions
507   // Returns the number of reports found
508
509   TGridResult *res = QueryReports(detector, year, reportNumber, reportVersion);
510   
511   if (0 == res) {
512     AliError("Query failed.");
513     return 0;
514   }
515
516   TString fn = "";
517   Int_t numberEntries = res->GetEntries();
518
519   if (numberEntries > 0) {
520     Printf("");
521     Printf(Form("%d reports found:", numberEntries));
522     for (int i = 0; i < res->GetEntries(); ++i) {
523       fn = res->GetFileNamePath(i);
524       Printf(Form("Detector:%s\tYear:%d\tEDMS Report Number:%d\tVersion:%d",
525                   FileNamePathToDetector(fn).Data(),
526                   FileNamePathToReportYear(fn),
527                   FileNamePathToReportNumber(fn),
528                   FileNamePathToReportVersion(fn)));
529     }
530     delete res;
531     return numberEntries;
532   } else {
533     AliInfo("No results found for the requested query.");
534     delete res;
535     return 0;
536   }
537 }
538
539
540 //_____________________________________________________________________________
541 void AliSurveyObj::SetGridUser(TString username){
542   // Set the username used to connect to the GRID
543   fGridUser = username;
544   return;
545 }
546
547
548 //_____________________________________________________________________________
549 TString &AliSurveyObj::Sanitize(TString str) {
550   // Cleans up a line of new line and carriage return characters.
551   // (Specially usefull for files created in Windows.)
552
553   str.Remove(TString::kTrailing, '\r');
554   str.Remove(TString::kTrailing, '\n');
555   str.Remove(TString::kTrailing, '\r');
556   if (!str.IsAscii()) {
557     AliWarning("Warning: Non-ASCII characters!\n");
558     str = "";
559   }
560   return str.Remove(TString::kBoth, ' ');
561 }
562
563
564 //_____________________________________________________________________________
565 Bool_t AliSurveyObj::ParseBuffer(const Char_t* buf) {
566   // Parses a character buffer assuming the format defined with the TS/SU
567   // http://aliceinfo/Offline/Activities/Alignment/SurveyInformation.html
568
569   // If the object is already filled clean it up
570   if (fIsValid) Reset();
571
572   // Copy the buffer to a TString to use Tokenize
573   TString buffer = TString(buf);
574   TObjArray *lines = buffer.Tokenize('\n');
575   TObjArray *dataLine = NULL; // Used to Tokenize each point/line read
576   TObjArray *colLine = NULL; // Used to Tokenize the column names
577
578   // Some local variables declarations and initializations
579   const Int_t kFieldCheck = 10;
580   Bool_t check[kFieldCheck];
581   TString tmpname = "";
582   Float_t tmpx = 0.0, tmpy = 0.0, tmpz = 0.0;
583   Float_t tmpprecX = 0.0, tmpprecY = 0.0, tmpprecZ = 0.0;
584   Char_t tmptype = '\0';
585   Bool_t tmptarg = kTRUE;
586   AliSurveyPoint *dp = 0;
587   for (Int_t i = 0; i < kFieldCheck; ++i) check[i] = kFALSE;
588
589   Int_t nrLines = lines->GetEntries();
590   Printf("Lines in file: %d\n", nrLines); 
591
592   // The main cycle, the buffer is parsed a line at a time
593   TString currLine = "", nextLine = "";
594   for (Int_t i = 0; i < nrLines; ++i) {
595
596     // Get the next line
597     currLine = ((TObjString *)(lines->At(i)))->GetString().Data();
598     nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
599     currLine = Sanitize(currLine);
600     nextLine = Sanitize(nextLine);
601     // Printf("\n%d: \"\"%s\"\"\"\n", i + 1, currLine.Data());
602     
603     // Skip empty line
604     if (0 == currLine.Length()) Printf("Info: Empty line skipped\n\n");
605
606     // The line contains a keyword
607     else if (currLine.BeginsWith(">") && !nextLine.BeginsWith(">")) {
608       currLine.Remove(TString::kLeading, '>');
609       currLine.Remove(TString::kTrailing, ':');
610       currLine.Remove(TString::kBoth, ' ');
611       nextLine.Remove(TString::kBoth, ' ');
612       // Printf(" -> Field: \"%s\"\n", currLine.Data());
613       
614       if (currLine.BeginsWith("Title", TString::kIgnoreCase)) {
615         // Report Title
616         fTitle = nextLine;
617         ++i;
618       } else if (currLine.BeginsWith("Date", TString::kIgnoreCase)) {
619         // Report(measurement) Date
620         fDate = nextLine;
621         ++i;
622       } else if (currLine.BeginsWith("Subdetector", TString::kIgnoreCase)) {
623         // Subdetector or structure
624         fDetector = nextLine;
625         ++i;
626       } else if (currLine.BeginsWith("Report URL", TString::kIgnoreCase)) {
627         // Report URL in EDMS
628         if (nextLine.BeginsWith("http://edms.cern.ch/document/", TString::kIgnoreCase) ||
629             nextLine.BeginsWith("https://edms.cern.ch/document/", TString::kIgnoreCase)) {
630           fURL = nextLine;
631           nextLine.Remove(TString::kTrailing, '/');
632           nextLine = nextLine(nextLine.Last('/') + 1, nextLine.Length() - nextLine.Last('/') + 1);
633           
634           Int_t sscanftmp = 0;
635           if (1 != sscanf(nextLine.Data(), "%d", &sscanftmp)) {
636             AliError("Survey text file sintax error! (incorrectly formated Report URL)");
637             lines->Delete();
638             return kFALSE;
639           }
640           fReportNr = nextLine.Atoi();
641           //Printf(" $$ %d $$\n", fReportNr);
642           ++i;
643         } else { 
644           // URL incorrectly formated
645           AliError("Survey text file sintax error! (incorrectly formated Report URL)");
646           return kFALSE;
647         }
648       } else if (currLine.BeginsWith("Version", TString::kIgnoreCase)) {
649         // Report version
650         if (!nextLine.IsDigit()) {
651           lines->Delete();
652           AliError("Survey text file sintax error! (incorrectly formated Report Version)");
653           return kFALSE;
654         }
655         fVersion = nextLine.Atoi();
656         ++i;
657       } else if (currLine.BeginsWith("General Observations", TString::kIgnoreCase)) {
658         // Observations
659         fObs = "";
660         // Can be more than 1 line. Loop until another keyword is found
661         while (('>' != nextLine[0]) && (nextLine.Length() > 0) && (i < nrLines)) {      
662           fObs += (0 == fObs.Length()) ? nextLine : " / " + nextLine;
663           ++i;
664           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
665           nextLine = Sanitize(nextLine);
666         }
667       } else if (currLine.BeginsWith("Coordinate System", TString::kIgnoreCase)) {
668         // Coordinate System
669         fCoordSys = nextLine;
670         ++i;
671       } else if (currLine.BeginsWith("Units", TString::kIgnoreCase)) {
672         // Measurement Unit
673         fUnits = nextLine;
674         ++i;
675       } else if (currLine.BeginsWith("Nr Columns", TString::kIgnoreCase)) {
676         // Number of columns in the "Data" section
677         if (!nextLine.IsDigit()) {
678           lines->Delete();
679           AliError("Survey text file sintax error! (incorrectly formated Number of Columns)");
680           return kFALSE;
681         }
682         fNrColumns = nextLine.Atoi();
683         ++i;
684       } else if (currLine.BeginsWith("Column Names", TString::kIgnoreCase)) {
685         // Column names separated by commas
686         fColNames = nextLine;
687         colLine = nextLine.Tokenize(',');
688         if (colLine->GetEntries() != fNrColumns) {
689           AliError("Survey text file sintax error! (Declared number of Columns doesn't match number of column names)");
690           colLine->Delete();
691           lines->Delete();
692           return kFALSE;
693         }
694         ++i;
695       } else if (currLine.BeginsWith("Data", TString::kIgnoreCase)) {
696         // Data section!
697         while ((nextLine.Length() > 0) && ('>' != nextLine[0])) {
698
699           // Printf("Data LINE: \"%s\": %d\n", nextLine.Data(), nextLine.Length());
700
701           // What is the separator used between fields?
702           // The allowed are: comma (','), tab ('\t'), and space (' ')
703           if (fNrColumns == nextLine.CountChar(',') + 1) dataLine = nextLine.Tokenize(',');
704           else if (fNrColumns == nextLine.CountChar('\t') + 1) dataLine = nextLine.Tokenize('\t');
705           else if (fNrColumns == nextLine.CountChar(' ') + 1) dataLine = nextLine.Tokenize(' ');
706           else {
707             // Error (No separator was found!)
708             AliError("Survey text file syntax error! Error processing data line!");
709             lines->Delete();
710             return kFALSE;
711           }
712           
713           if (dataLine->GetEntries() != fNrColumns) {
714             // The number of columns doesn't match the number specified in the header
715             AliError("Survey text file sintax error! (Number of entries in line is different from declared Number of Columns)");
716             dataLine->Delete();
717             lines->Delete();
718             return kFALSE;
719           }
720
721           // Reset the bits used to check if all the required fields are present
722           for (Int_t t = 0; t < kFieldCheck; ++t) check[t] = 0;
723
724           // Process the data line using the column names as index
725           for (Int_t j = 0; j < dataLine->GetEntries(); ++j) {
726             TString cn = ((TObjString *)(colLine->At(j)))->GetString();
727             TString value = ((TObjString *)(dataLine->At(j)))->GetString();
728             if (cn.BeginsWith("Point Name", TString::kIgnoreCase)) {
729               tmpname = value;
730               check[0] = kTRUE;
731             } else if (cn.BeginsWith("X", TString::kIgnoreCase)) {
732               tmpx = value.Atof();
733               check[1] = kTRUE;
734             } else if (cn.BeginsWith("Y", TString::kIgnoreCase)) {
735               tmpy = value.Atof();
736               check[2] = kTRUE;
737             } else if (cn.BeginsWith("Z", TString::kIgnoreCase)) {
738               tmpz = value.Atof();
739               check[3] = kTRUE;
740             } else if (cn.BeginsWith("Precision", TString::kIgnoreCase)) {
741               TString tmpCN = cn(0, cn.First('('));
742               Int_t precLength = TString("Precision").Length();
743               //Printf(" ====== %d ======= %d ====== \n", precLength, tmpCN.Length());
744               //Printf(" ====== %s ======= \n", tmpCN.Data());
745               if (precLength == tmpCN.Length()) {
746                 tmpprecX = tmpprecY = tmpprecZ = value.Atof();
747                 check[6] = kTRUE;
748               } else {
749                 TString axis = cn(precLength, tmpCN.Length() - precLength);
750                 if (axis.Contains('X', TString::kIgnoreCase)) {
751                   tmpprecX = value.Atof();
752                   check[7] = kTRUE;
753                 } else if (axis.Contains('Y', TString::kIgnoreCase)) {
754                   tmpprecY = value.Atof();
755                   check[8] = kTRUE;
756                 } else if (axis.Contains('Z', TString::kIgnoreCase)) {
757                   tmpprecZ = value.Atof();
758                   check[9] = kTRUE;
759                 } else {
760                   AliError("Survey text file sintax error! (Precision column name invalid)");
761                   dataLine->Delete();
762                   lines->Delete();
763                   return kFALSE;
764                 }
765               }
766             } else if (cn.BeginsWith("Point Type", TString::kIgnoreCase)) {
767               tmptype = value.Data()[0];
768               check[4] = kTRUE;
769             } else if (cn.BeginsWith("Target Used", TString::kIgnoreCase)) {
770               tmptarg = (value.Data()[0] == 'Y') ? kTRUE : kFALSE;
771               check[5] = kTRUE;
772             }
773
774             //Printf("--> %s\n", ((TObjString *)(dataLine->At(j)))->GetString().Data());
775           }
776
777           // Check if all the mandatory fields exist
778           Bool_t res = kTRUE, precInd = kTRUE;
779
780           // Target
781           if (kFALSE == check[5]) {
782             tmptarg = kTRUE;
783             check[5] = kTRUE;
784           }
785           
786           // Individual axis precisions
787           for (Int_t t = 7; t < 10; ++t) precInd &= check[t];
788           if ((kFALSE == check[6]) && (kTRUE == precInd)) check[6] = kTRUE;
789
790           for (Int_t t = 0; t < kFieldCheck - 3; ++t) {
791             //Printf("RES(%d): %d\n", t, check[t]);
792             res &= check[t];
793           }
794           if (kTRUE == res) {
795             dp = new AliSurveyPoint(tmpname, tmpx, tmpy, tmpz, tmpprecX, tmpprecY, tmpprecZ, tmptype, tmptarg);
796             dp->PrintPoint();
797             AddPoint(dp);
798           } else {
799             AliError("Parsing error processing data line!");
800             dataLine->Delete();
801             lines->Delete();
802             return kFALSE;
803           }
804           
805           dataLine->Delete();
806           dataLine = NULL;
807           ++i;
808           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
809           nextLine = Sanitize(nextLine);
810         }
811       }
812     } else {
813       AliError("Survey text file sintax error!");
814       lines->Delete();
815       return kFALSE;
816     }
817   }
818   lines->Delete();
819   fIsValid = kTRUE;
820   return kTRUE;
821 }
822
823 //_____________________________________________________________________________
824 void AliSurveyObj::Reset() {
825   // Resets the AliSurveyObj to a clean object.
826   // Used if the same object is filled more than once
827   
828   if (fDataPoints) {
829     fDataPoints->Delete();
830     fDataPoints = 0;
831   }
832   fTitle = "";
833   fDate = "";
834   fDetector = "";
835   fURL = "http://edms.cern.ch/";
836   fReportNr = -1;
837   fVersion = -1;
838   fObs = "";
839   fCoordSys = "";
840   fUnits = "";
841   fNrColumns = -1;
842   fColNames = "";
843   fIsValid = kFALSE;
844   fDataPoints = new TObjArray(1);
845   fDataPoints->SetOwner(kTRUE);
846   return;
847 }
848