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