]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/AliSurveyObj.cxx
Changed class inheritance (TObject->TTask) and fixed bug
[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 "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 = %x; 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("%d bytes read!\n", file->GetBytesRead()));
200   
201   ParseBuffer(buf);
202
203   file->Close();
204   delete[] buf;
205   return kTRUE;
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   dets->Delete();
228   dets = 0;
229
230   if (!found) return kFALSE;
231   else return kTRUE;
232 }
233
234
235 //_____________________________________________________________________________
236 TString AliSurveyObj::RealFolderName(TString detector) const {
237   // Returns the actual folder name for a given detector 
238   // Some "detectors" don't have a folder of their own
239
240   detector.ToUpper();
241   TString folderName = detector;
242
243   TObjArray *dets = fgkGRPDetectors.Tokenize(',');
244   if (dets->FindObject(detector)) folderName = "GRP";
245   dets->Delete();
246   dets = 0;
247
248   dets = fgkMUONDetectors.Tokenize(',');
249   if (dets->FindObject(detector)) folderName = "MUON";
250   dets->Delete();  
251  
252
253
254   dets = 0;
255
256   return folderName;
257 }
258
259 //_____________________________________________________________________________
260 Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber,
261                           TString username) {
262   // Fills the object from a file in the default storage location in AliEn.
263   // The highest version available is selected.
264
265   return Fill(detector, reportNumber, -1, username);
266 }
267
268 //_____________________________________________________________________________
269 Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber,
270                           Int_t reportVersion, TString username) {
271   // Fills the object from a file in the default storage location in AliEn.
272   // A specific version is selected.
273
274   detector.ToUpper();
275   
276   // Check if <detector> is valid
277   if (!IsValidDetector(detector)) {
278     AliWarning(Form("Detector '%s' is not a valid detector/structure!", detector.Data()));
279     return kFALSE;
280   }
281
282   // Some "detectors" don't have a folder of their own
283   // TString detectorFolder = RealFolderName(detector);
284
285   // Check if <year>, <reportNumber> and <reportVersion> are valid (roughly)
286   if ((reportNumber < 1) || (reportVersion < -1) || (0 == reportVersion)) {
287     AliError("Invalid parameter values for AliSurveyObj::Fill. (Report Number or Report Version)");
288     return kFALSE;
289   }
290
291   // Check if the fGridUser is set, or specified
292   if (username.Length() > 0) SetGridUser(username);
293   else if (0 == fGridUser.Length()) {
294     AliError("GRID username not specified and not previously set!");
295     return kFALSE;
296   }
297
298   // Query AliEn for the available reports
299   TGridResult *res = QueryReports(detector, -1, reportNumber, reportVersion);
300   if (!res) AliError(Form("Error querying AliEn for detector '%s', \
301                            report number '%d' and report version '%d'.",
302                           detector.Data(), reportNumber, reportVersion));
303   Int_t numberEntries = res->GetEntries();
304   if (0 == numberEntries) {
305     AliError(Form("No report found for detector '%s', report number '%d' and report version '%d'",
306                   detector.Data(), reportNumber, reportVersion));
307     return kFALSE;
308   }
309
310   TString fileNamePath = "";
311   if (1 == numberEntries) fileNamePath = res->GetFileNamePath(0);
312   else if (numberEntries > 1) {
313     TString higherVerFNP = res->GetFileNamePath(0);
314     Int_t lastYear = FileNamePathToReportYear(higherVerFNP);
315     for (Int_t i = 1; i < numberEntries; ++i) {
316       TString currFNP = res->GetFileNamePath(i);
317       if (FileNamePathToReportVersion(currFNP) >
318           FileNamePathToReportVersion(higherVerFNP)) higherVerFNP = currFNP;
319       if (lastYear != FileNamePathToReportYear(currFNP))
320         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.");
321     }
322     fileNamePath = higherVerFNP;
323   }
324
325   TString fullOpenString = "alien://" + fileNamePath + "?filetype=raw";
326   /*
327   // Finally composes the full string
328   TString fullOpenString = "alien://" + fgkBaseFolder + "/" + detectorFolder + "/RawSurvey/";
329   fullOpenString += Form("%d/%d_v%d.txt?filetype=raw", year, reportNumber, reportVersion);
330   */
331
332   return OpenFile(fullOpenString);
333 }
334
335
336 //_____________________________________________________________________________
337 TString AliSurveyObj::FileNamePathToDetector(TString filename) const {
338   // Get the report number from the complete path in the format:
339   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
340
341   TString ret = "";
342
343   if (filename.Length() > fgkBaseFolder.Length()) {
344     ret = filename.Remove(0, fgkBaseFolder.Length());
345     ret.Remove(TString::kLeading, '/');
346     ret = ret(0, ret.First('/'));
347     if (!IsValidDetector(ret)) ret = "";
348   } 
349   return ret;
350 }
351
352 ///alice/cern.ch/user/r/rsilva/TRD/RawSurvey/2007/.816582_v2.txt/v1.0
353
354 //_____________________________________________________________________________
355 Int_t AliSurveyObj::FileNamePathToReportYear(TString filename) const {
356   // Get the report year from the complete path in the format:
357   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
358
359   TString ret = "";
360
361   if (filename.Length() > fgkBaseFolder.Length()) {
362     ret = filename.Remove(0, fgkBaseFolder.Length());
363     ret.Remove(TString::kLeading, '/');
364     Int_t beg = ret.First('/') + TString("RawSurvey/").Length() + 1;
365     ret = ret(beg, ret.Last('/') - beg);
366     return ret.Atoi();
367   } 
368   return -1;
369 }
370
371
372 //_____________________________________________________________________________
373 Int_t AliSurveyObj::FileNamePathToReportNumber(TString filename) const {
374   // Get the report number from the complete path in the format:
375   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
376
377   TString ret = "";
378
379   if (filename.Length() > fgkBaseFolder.Length()) {
380     ret = filename.Remove(0, fgkBaseFolder.Length());
381     ret.Remove(TString::kLeading, '/');
382     if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) {
383       AliWarning("Error getting the Report Number from the filename path!");
384       return -1;
385     }
386     ret = ret(ret.Last('/') + 1 , ret.Last('_') - ret.Last('/') - 1);
387     return ret.Atoi();
388   } 
389   AliWarning("Error getting the Report Number from the filename path!");
390   return -1;
391 }
392
393
394 //_____________________________________________________________________________
395 Int_t AliSurveyObj::FileNamePathToReportVersion(TString filename) const {
396   // Get the report version from the complete path in the format:
397   // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
398
399   TString ret = "";
400
401   if (filename.Length() > fgkBaseFolder.Length()) {
402     ret = filename.Remove(0, fgkBaseFolder.Length());
403     ret.Remove(TString::kLeading, '/');
404     if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) {
405       AliWarning("Error getting the Report Version from the filename path!");
406       return -1;
407     }
408     ret = ret(ret.Last('_') + 1 + 1 , ret.Last('.') - ret.Last('_') - 1 - 1);
409     return ret.Atoi();
410   } 
411   AliWarning("Error getting the Report Version from the filename path!");
412   return -1;
413 }
414
415
416 //_____________________________________________________________________________
417 void AliSurveyObj::ListValidDetectors() {
418     // List the valid detector names
419     Printf("");
420     Printf("Listing all valid detectors:\n");
421     TObjArray *dets = fgkValidDetectors.Tokenize(',');
422     for (int i = 0; i < dets->GetEntries(); ++i) 
423         Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
424     dets->Delete();
425     dets = 0;
426     Printf("");
427     Printf("Some reports are stored in more general folders.\n"
428             "These reports can be opened using either name, the original or the\n"
429             "folder name. Example: 'SPACEFRAME' or 'GRP' are both valid when\n"
430             "opening a report for the Spaceframe.\n\n"
431             "Detectors stored in 'MUON' folder:");
432     dets = fgkMUONDetectors.Tokenize(',');
433     for (int i = 0; i < dets->GetEntries(); ++i) 
434         Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
435     dets->Delete();
436     dets = 0;
437     Printf("");
438     Printf("Detectors stored in 'GRP' folder:");
439     dets = fgkGRPDetectors.Tokenize(',');
440     for (int i = 0; i < dets->GetEntries(); ++i) 
441         Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
442     dets->Delete();
443     dets = 0;
444     return;
445 }
446
447
448 //_____________________________________________________________________________
449 TGridResult * AliSurveyObj::QueryReports(TString detector, Int_t year,
450                                          Int_t reportNumber,
451                                          Int_t reportVersion) {
452   // Queries AliEn for existing reports matching the specified conditions
453   TString lsArg = fgkBaseFolder;
454   
455   TString detectorFolder = "";
456   if (detector.Length() > 0) {
457     detector.ToUpper();
458     // Check if <detector> is valid
459     if (!IsValidDetector(detector)) {
460       AliError(Form("Detector '%s' is not a valid detector/structure!",
461                     detector.Data()));
462       return 0;
463     }
464     // Some "detectors" don't have a folder of their own
465     detectorFolder = "/" + RealFolderName(detector);
466   } else detectorFolder = "/*";
467
468   lsArg += detectorFolder + "/RawSurvey";
469
470   TString yearFolder = "";
471   if (year > 1950) yearFolder.Form("/%d", year);
472   else yearFolder = "/*";
473
474   TString reportFolder = "";
475   if (reportNumber > 0) reportFolder.Form("/%d", reportNumber);
476   else reportFolder = "/*";
477
478   TString versionFolder = "";
479   if (reportVersion > 0) versionFolder.Form("_v%d", reportVersion);
480   else versionFolder = "_v*";
481
482   lsArg += yearFolder + reportFolder + versionFolder + ".txt";
483
484   AliInfo(Form("\nLooking for:  %s \n", lsArg.Data()));
485   
486   // Check if fGridUser is set and Connect to AliEn
487   if (0 == fGridUser.Length()) {
488     AliError("To use this method it's necessary to call SetGridUser(...) in advance.");
489     return 0;
490   } else if (!Connect(fgkStorage.Data(), fGridUser.Data())) {
491     AliError(Form("Error connecting to GRID"));
492     return 0;
493   }
494   return gGrid->Ls(lsArg);
495 }
496
497
498 //_____________________________________________________________________________
499 Int_t AliSurveyObj::ListReports(TString detector, Int_t year, 
500                                 Int_t reportNumber,
501                                 Int_t reportVersion) {
502   // Lists all available reports matching the specified conditions
503   // Returns the number of reports found
504
505   TGridResult *res = QueryReports(detector, year, reportNumber, reportVersion);
506   
507   if (0 == res) {
508     AliError("Query failed.");
509     return 0;
510   }
511
512   TString fn = "";
513   Int_t numberEntries = res->GetEntries();
514
515   if (numberEntries > 0) {
516     Printf("");
517     Printf(Form("%d reports found:", numberEntries));
518     for (int i = 0; i < res->GetEntries(); ++i) {
519       fn = res->GetFileNamePath(i);
520       Printf(Form("Detector:%s\tYear:%d\tEDMS Report Number:%d\tVersion:%d",
521                   FileNamePathToDetector(fn).Data(),
522                   FileNamePathToReportYear(fn),
523                   FileNamePathToReportNumber(fn),
524                   FileNamePathToReportVersion(fn)));
525     }
526     delete res;
527     return numberEntries;
528   } else {
529     AliInfo("No results found for the requested query.");
530     delete res;
531     return 0;
532   }
533 }
534
535
536 //_____________________________________________________________________________
537 void AliSurveyObj::SetGridUser(TString username){
538   // Set the username used to connect to the GRID
539   fGridUser = username;
540   return;
541 }
542
543
544 //_____________________________________________________________________________
545 TString &AliSurveyObj::Sanitize(TString str) {
546   // Cleans up a line of new line and carriage return characters.
547   // (Specially usefull for files created in Windows.)
548
549   str.Remove(TString::kTrailing, '\r');
550   str.Remove(TString::kTrailing, '\n');
551   str.Remove(TString::kTrailing, '\r');
552
553   if (!str.IsAscii()) {
554     AliWarning("Warning: Non-ASCII characters!\n");
555     str = "";
556   }
557   return str.Remove(TString::kBoth, ' ');
558 }
559
560
561 //_____________________________________________________________________________
562 Bool_t AliSurveyObj::ParseBuffer(const Char_t* buf) {
563   // Parses a character buffer assuming the format defined with the TS/SU
564   // http://aliceinfo/Offline/Activities/Alignment/SurveyInformation.html
565
566   // If the object is already filled clean it up
567   if (fIsValid) Reset();
568
569   // Copy the buffer to a TString to use Tokenize
570   TString buffer = TString(buf);
571   TObjArray *linesRaw = buffer.Tokenize('\n');
572   // replace the array of lines with an array of sanitized lines
573   // in the process we remove empty lines, particularly disturbing
574   // in case of dos fileformat
575   TString oneLine = "";
576   TObjString* oneLineObj = 0;
577   TObjArray *lines = new TObjArray();
578   for(Int_t i=0; i<linesRaw->GetEntries(); i++)
579   {
580           oneLine = ((TObjString *)(linesRaw->At(i)))->GetString().Data();
581           oneLine = Sanitize(oneLine);
582           if (oneLine.Length() == 0) continue;
583           oneLineObj = new TObjString(oneLine);
584           lines->Add(oneLineObj);
585   }
586
587   linesRaw->Delete();
588   delete linesRaw;
589   linesRaw = NULL;
590
591   TObjArray *dataLine = NULL; // Used to Tokenize each point/line read
592   TObjArray *colLine = NULL; // Used to Tokenize the column names
593
594   // Some local variables declarations and initializations
595   const Int_t kFieldCheck = 10;
596   Bool_t check[kFieldCheck]; // used to check that mandatory column names are not missing
597   for (Int_t i = 0; i < kFieldCheck; ++i) check[i] = kFALSE;
598   TString tmpname = "";
599   Float_t tmpx = 0.0, tmpy = 0.0, tmpz = 0.0;
600   Float_t tmpprecX = -1., tmpprecY = -1., tmpprecZ = -1.;
601   Char_t tmptype = '\0';
602   Bool_t tmptarg = kTRUE;
603   AliSurveyPoint *dp = 0;
604   TString *orderedValues[9] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
605   TString value[9];
606
607   Int_t nrLines = lines->GetEntries();
608   Printf("Lines in file: %d\n", nrLines); 
609
610   // The main cycle, the buffer is parsed a line at a time
611   TString currLine = "", nextLine = "";
612   for (Int_t i = 0; i < nrLines; ++i) {
613
614     // Get the next line
615     currLine = ((TObjString *)(lines->At(i)))->GetString().Data();
616     nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
617     // Printf("%d: \"%s\"", i, currLine.Data());
618     // Printf("%d:  \"%s\"\n", i+1, nextLine.Data());
619     
620     // The line contains a keyword
621     if (currLine.BeginsWith(">") && !nextLine.BeginsWith(">")) {
622       currLine.Remove(TString::kLeading, '>');
623       currLine.Remove(TString::kTrailing, ':');
624       currLine.Remove(TString::kBoth, ' ');
625       nextLine.Remove(TString::kBoth, ' ');
626       AliDebug(2, Form(" -> field line: \"%s\"\n", currLine.Data()));
627       AliDebug(2, Form(" -> value line: \"%s\"\n", nextLine.Data()));
628       
629       if (currLine.BeginsWith("Title", TString::kIgnoreCase)) {
630         // Report Title
631         fTitle = nextLine;
632         ++i;
633       } else if (currLine.BeginsWith("Date", TString::kIgnoreCase)) {
634         // Report(measurement) Date
635         fDate = nextLine;
636         ++i;
637       } else if (currLine.BeginsWith("Subdetector", TString::kIgnoreCase)) {
638         // Subdetector or structure
639         fDetector = nextLine;
640         ++i;
641       } else if (currLine.BeginsWith("Report URL", TString::kIgnoreCase)) {
642         // Report URL in EDMS
643         if (nextLine.BeginsWith("http://edms.cern.ch/document/", TString::kIgnoreCase) ||
644             nextLine.BeginsWith("https://edms.cern.ch/document/", TString::kIgnoreCase)) {
645           fURL = nextLine;
646           nextLine.Remove(TString::kTrailing, '/');
647           nextLine = nextLine(nextLine.Last('/') + 1, nextLine.Length() - nextLine.Last('/') + 1);
648           
649           Int_t sscanftmp = 0;
650           if (1 != sscanf(nextLine.Data(), "%d", &sscanftmp)) {
651             AliError("Survey text file sintax error! (incorrectly formatted Report URL)");
652             lines->Delete();
653             delete lines; lines = NULL;
654             return kFALSE;
655           }
656           fReportNr = nextLine.Atoi();
657           //Printf(" $$ %d $$\n", fReportNr);
658           ++i;
659         } else { 
660           // URL incorrectly formatted
661           AliError("Survey text file sintax error! (incorrectly formatted Report URL)");
662           return kFALSE;
663         }
664       } else if (currLine.BeginsWith("Version", TString::kIgnoreCase)) {
665         // Report version
666         if (!nextLine.IsDigit()) {
667           lines->Delete();
668           delete lines; lines = NULL;
669           AliError("Survey text file sintax error! (incorrectly formatted Report Version)");
670           return kFALSE;
671         }
672         fVersion = nextLine.Atoi();
673         ++i;
674       } else if (currLine.BeginsWith("General Observations", TString::kIgnoreCase)) {
675         // Observations
676         fObs = "";
677         // Can be more than 1 line. Loop until another keyword is found
678         while (('>' != nextLine[0]) && (nextLine.Length() > 0) && (i < nrLines)) {      
679           fObs += (0 == fObs.Length()) ? nextLine : " / " + nextLine;
680           ++i;
681           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
682         }
683       } else if (currLine.BeginsWith("Coordinate System", TString::kIgnoreCase)) {
684         // Coordinate System
685         fCoordSys = nextLine;
686         ++i;
687       } else if (currLine.BeginsWith("Units", TString::kIgnoreCase)) {
688         // Measurement Unit
689         fUnits = nextLine;
690         ++i;
691       } else if (currLine.BeginsWith("Nr Columns", TString::kIgnoreCase)) {
692         // Number of columns in the "Data" section
693         if (!nextLine.IsDigit()) {
694           lines->Delete();
695           delete lines; lines = NULL;
696           AliError("Survey text file sintax error! (incorrectly formatted Number of Columns)");
697           return kFALSE;
698         }
699         fNrColumns = nextLine.Atoi();
700         ++i;
701       } else if (currLine.BeginsWith("Column Names", TString::kIgnoreCase)) {
702         // Column names separated by commas
703         fColNames = nextLine;
704         colLine = nextLine.Tokenize(',');
705         if (colLine->GetEntries() != fNrColumns) {
706           AliError("Survey text file sintax error! (Declared number of Columns doesn't match number of column names)");
707           colLine->Delete();
708           lines->Delete();
709           delete lines; lines = NULL;
710           return kFALSE;
711         }
712         ++i;
713         
714         // booleans to track if precision for 1 axis is defined in more than one column
715         Bool_t prX = kFALSE;
716         Bool_t prY = kFALSE;
717         Bool_t prZ = kFALSE;
718         
719         for (Int_t j = 0; j < fNrColumns; ++j) {
720           TString cn = ((TObjString *)(colLine->At(j)))->GetString();
721           if (cn.BeginsWith("Point Name", TString::kIgnoreCase)) {
722             orderedValues[0] = &value[j];
723             check[0] = kTRUE;
724           } else if (cn.BeginsWith("X", TString::kIgnoreCase)) {
725             orderedValues[1] = &value[j];
726             check[1] = kTRUE;
727           } else if (cn.BeginsWith("Y", TString::kIgnoreCase)) {
728             orderedValues[2] = &value[j];
729             check[2] = kTRUE;
730           } else if (cn.BeginsWith("Z", TString::kIgnoreCase)) {
731             orderedValues[3] = &value[j];
732             check[3] = kTRUE;
733           } else if (cn.BeginsWith("Precision", TString::kIgnoreCase)) {
734             TString tmpCN = cn(0, cn.First('('));
735             Int_t precLength = TString("Precision").Length();
736             if (precLength == tmpCN.Length()) {
737               if(!orderedValues[6]){
738                 orderedValues[6] = &value[j];
739                 check[6] = kTRUE;
740               }else{
741                 AliWarning("Global precision will not be used for X axis");
742               }
743               if(!orderedValues[7]){
744                 orderedValues[7] = &value[j];
745                 check[7] = kTRUE;
746               }else{
747                 AliWarning("Global precision will not be used for Y axis");
748               }
749               if(!orderedValues[8]){
750                 orderedValues[8] = &value[j];
751                 check[8] = kTRUE;
752               }else{
753                 AliWarning("Global precision will not be used for Z axis");
754               }
755             } else {
756               Bool_t orXYZ = kFALSE;
757               TString axis = cn(precLength, tmpCN.Length() - precLength);
758               if (axis.Contains('X', TString::kIgnoreCase)) {
759                 if(!prX){
760                   orderedValues[6] = &value[j];
761                   check[6] = kTRUE;
762                   orXYZ = kTRUE;
763                   prX = kTRUE;
764                 }else{
765                   AliError("Precision for X axis was already set!");
766                   return kFALSE;
767                 }
768               }
769               if (axis.Contains('Y', TString::kIgnoreCase)) {
770                 if(!prY){
771                   orderedValues[7] = &value[j];
772                   check[7] = kTRUE;
773                   orXYZ = kTRUE;
774                   prY = kTRUE;
775                 }else{
776                   AliError("Precision for Y axis was already set!");
777                   return kFALSE;
778                 }
779               }
780               if (axis.Contains('Z', TString::kIgnoreCase)) {
781                 if(!prZ){
782                   orderedValues[8] = &value[j];
783                   check[8] = kTRUE;
784                   orXYZ = kTRUE;
785                   prZ = kTRUE;
786                 }else{
787                   AliError("Precision for Z axis was already set!");
788                   return kFALSE;
789                 }
790               }
791               if(!orXYZ)
792               {
793                 AliError("Survey text file sintax error: precision column name does not refer to any axis!");
794                 return kFALSE;
795               }
796             }
797           } else if (cn.BeginsWith("Point Type", TString::kIgnoreCase)) {
798             orderedValues[4] = &value[j];
799             check[4] = kTRUE;
800           } else if (cn.BeginsWith("Target Used", TString::kIgnoreCase)) {
801             orderedValues[5] = &value[j];
802             check[5] = kTRUE;
803           }
804         }
805
806         // Check if all the mandatory fields exist in the line with column names
807         if(!check[0]){
808           AliError("Missing mandatory column \"Point Name\"!");
809           return kFALSE;
810         }
811         if(!(check[1]&&check[2]&&check[3])){
812           AliError("Missing one or more mandatory columns for coordinates \"X\",\"Y\",\"Z\"");
813           return kFALSE;
814         }
815         if(!check[4]){
816           AliError("Missing mandatory column \"Point Type\"!");
817           return kFALSE;
818         }
819         if(!(check[6]&&check[7]&&check[8])){
820           AliError("Missing one or more mandatory columns for precision along \"X\",\"Y\",\"Z\" axes");
821           return kFALSE;
822         }
823
824       } else if (currLine.BeginsWith("Data", TString::kIgnoreCase)) {
825         // Data section!
826         while ((nextLine.Length() > 0) && ('>' != nextLine[0])) {
827
828           // Printf("Data LINE: \"%s\": %d\n", nextLine.Data(), nextLine.Length());
829
830           // What is the separator used between fields?
831           // The allowed are: comma (','), tab ('\t'), and space (' ')
832           if (fNrColumns == nextLine.CountChar(',') + 1) dataLine = nextLine.Tokenize(',');
833           else if (fNrColumns == nextLine.CountChar('\t') + 1) dataLine = nextLine.Tokenize('\t');
834           else if (fNrColumns == nextLine.CountChar(' ') + 1) dataLine = nextLine.Tokenize(' ');
835           else {
836             // Error (No separator was found!)
837             AliError("Survey text file syntax error! Error processing data line!");
838             lines->Delete();
839             delete lines; lines = NULL;
840             return kFALSE;
841           }
842
843           if (dataLine->GetEntries() != fNrColumns) {
844             // The number of columns doesn't match the number specified in the header
845             AliError("Survey text file sintax error! (Number of entries in line is different from number of Columns)");
846             dataLine->Delete();
847             lines->Delete();
848             delete lines; lines = NULL;
849             return kFALSE;
850           }
851
852           // Process the data line using the column names as index
853           for (Int_t j = 0; j < dataLine->GetEntries(); ++j) {
854             value[j] = ((TObjString *)(dataLine->At(j)))->GetString();
855           }
856           tmpname = *orderedValues[0];
857           tmpx = orderedValues[1]->Atof();
858           tmpy = orderedValues[2]->Atof();
859           tmpz = orderedValues[3]->Atof();
860           tmpprecX = orderedValues[6]->Atof();
861           tmpprecY = orderedValues[7]->Atof();
862           tmpprecZ = orderedValues[8]->Atof();
863           tmptype = orderedValues[4]->Data()[0];
864           if(orderedValues[5]) tmptarg = (orderedValues[5]->Data()[0] == 'Y') ? kTRUE : kFALSE;
865
866           dp = new AliSurveyPoint(tmpname, tmpx, tmpy, tmpz, tmpprecX, tmpprecY, tmpprecZ, tmptype, tmptarg);
867           if(AliLog::GetDebugLevel("","AliSurveyObj")>1) dp->PrintPoint();
868           AddPoint(dp);
869
870           dataLine->Delete();
871           dataLine = NULL;
872           ++i;
873           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
874         }
875       }
876     } else {
877       AliError("Survey text file sintax error!");
878       lines->Delete();
879       delete lines; lines = NULL;
880       return kFALSE;
881     }
882   }
883   lines->Delete();
884   delete lines; lines = NULL;
885   fIsValid = kTRUE;
886   return kTRUE;
887 }
888
889 //_____________________________________________________________________________
890 void AliSurveyObj::Reset() {
891   // Resets the AliSurveyObj to a clean object.
892   // Used if the same object is filled more than once
893   
894   if (fDataPoints) {
895     fDataPoints->Delete();
896     fDataPoints = 0;
897   }
898   fTitle = "";
899   fDate = "";
900   fDetector = "";
901   fURL = "http://edms.cern.ch/";
902   fReportNr = -1;
903   fVersion = -1;
904   fObs = "";
905   fCoordSys = "";
906   fUnits = "";
907   fNrColumns = -1;
908   fColNames = "";
909   fIsValid = kFALSE;
910   fDataPoints = new TObjArray(1);
911   fDataPoints->SetOwner(kTRUE);
912   return;
913 }
914