]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/AliSurveyObj.cxx
Changing handling of the errors according to discussion following
[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,VZERO,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       (( strcmp(user,"") ) && ( strcmp(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]; // used to check that mandatory column names are not missing
581   for (Int_t i = 0; i < kFieldCheck; ++i) check[i] = kFALSE;
582   TString tmpname = "";
583   Float_t tmpx = 0.0, tmpy = 0.0, tmpz = 0.0;
584   Float_t tmpprecX = -1., tmpprecY = -1., tmpprecZ = -1.;
585   Char_t tmptype = '\0';
586   Bool_t tmptarg = kTRUE;
587   AliSurveyPoint *dp = 0;
588   TString *orderedValues[9] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
589   TString value[9];
590
591   Int_t nrLines = lines->GetEntries();
592   Printf("Lines in file: %d\n", nrLines); 
593
594   // The main cycle, the buffer is parsed a line at a time
595   TString currLine = "", nextLine = "";
596   for (Int_t i = 0; i < nrLines; ++i) {
597
598     // Get the next line
599     currLine = ((TObjString *)(lines->At(i)))->GetString().Data();
600     nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
601     currLine = Sanitize(currLine);
602     nextLine = Sanitize(nextLine);
603     // Printf("\n%d: \"\"%s\"\"\"\n", i + 1, currLine.Data());
604     
605     // Skip empty line
606     if (0 == currLine.Length()) Printf("Info: Empty line skipped\n\n");
607
608     // The line contains a keyword
609     else if (currLine.BeginsWith(">") && !nextLine.BeginsWith(">")) {
610       currLine.Remove(TString::kLeading, '>');
611       currLine.Remove(TString::kTrailing, ':');
612       currLine.Remove(TString::kBoth, ' ');
613       nextLine.Remove(TString::kBoth, ' ');
614       AliDebug(2, Form(" -> field line: \"%s\"\n", currLine.Data()));
615       AliDebug(2, Form(" -> value line: \"%s\"\n", nextLine.Data()));
616       
617       if (currLine.BeginsWith("Title", TString::kIgnoreCase)) {
618         // Report Title
619         fTitle = nextLine;
620         ++i;
621       } else if (currLine.BeginsWith("Date", TString::kIgnoreCase)) {
622         // Report(measurement) Date
623         fDate = nextLine;
624         ++i;
625       } else if (currLine.BeginsWith("Subdetector", TString::kIgnoreCase)) {
626         // Subdetector or structure
627         fDetector = nextLine;
628         ++i;
629       } else if (currLine.BeginsWith("Report URL", TString::kIgnoreCase)) {
630         // Report URL in EDMS
631         if (nextLine.BeginsWith("http://edms.cern.ch/document/", TString::kIgnoreCase) ||
632             nextLine.BeginsWith("https://edms.cern.ch/document/", TString::kIgnoreCase)) {
633           fURL = nextLine;
634           nextLine.Remove(TString::kTrailing, '/');
635           nextLine = nextLine(nextLine.Last('/') + 1, nextLine.Length() - nextLine.Last('/') + 1);
636           
637           Int_t sscanftmp = 0;
638           if (1 != sscanf(nextLine.Data(), "%d", &sscanftmp)) {
639             AliError("Survey text file sintax error! (incorrectly formated Report URL)");
640             lines->Delete();
641             return kFALSE;
642           }
643           fReportNr = nextLine.Atoi();
644           //Printf(" $$ %d $$\n", fReportNr);
645           ++i;
646         } else { 
647           // URL incorrectly formated
648           AliError("Survey text file sintax error! (incorrectly formated 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           AliError("Survey text file sintax error! (incorrectly formated Report Version)");
656           return kFALSE;
657         }
658         fVersion = nextLine.Atoi();
659         ++i;
660       } else if (currLine.BeginsWith("General Observations", TString::kIgnoreCase)) {
661         // Observations
662         fObs = "";
663         // Can be more than 1 line. Loop until another keyword is found
664         while (('>' != nextLine[0]) && (nextLine.Length() > 0) && (i < nrLines)) {      
665           fObs += (0 == fObs.Length()) ? nextLine : " / " + nextLine;
666           ++i;
667           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
668           nextLine = Sanitize(nextLine);
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           AliError("Survey text file sintax error! (incorrectly formated Number of Columns)");
683           return kFALSE;
684         }
685         fNrColumns = nextLine.Atoi();
686         ++i;
687       } else if (currLine.BeginsWith("Column Names", TString::kIgnoreCase)) {
688         // Column names separated by commas
689         fColNames = nextLine;
690         colLine = nextLine.Tokenize(',');
691         if (colLine->GetEntries() != fNrColumns) {
692           AliError("Survey text file sintax error! (Declared number of Columns doesn't match number of column names)");
693           colLine->Delete();
694           lines->Delete();
695           return kFALSE;
696         }
697         ++i;
698         
699         // booleans to track if precision for 1 axis is defined in more than one column
700         Bool_t prX = kFALSE;
701         Bool_t prY = kFALSE;
702         Bool_t prZ = kFALSE;
703         
704         for (Int_t j = 0; j < fNrColumns; ++j) {
705           TString cn = ((TObjString *)(colLine->At(j)))->GetString();
706           if (cn.BeginsWith("Point Name", TString::kIgnoreCase)) {
707             orderedValues[0] = &value[j];
708             check[0] = kTRUE;
709           } else if (cn.BeginsWith("X", TString::kIgnoreCase)) {
710             orderedValues[1] = &value[j];
711             check[1] = kTRUE;
712           } else if (cn.BeginsWith("Y", TString::kIgnoreCase)) {
713             orderedValues[2] = &value[j];
714             check[2] = kTRUE;
715           } else if (cn.BeginsWith("Z", TString::kIgnoreCase)) {
716             orderedValues[3] = &value[j];
717             check[3] = kTRUE;
718           } else if (cn.BeginsWith("Precision", TString::kIgnoreCase)) {
719             TString tmpCN = cn(0, cn.First('('));
720             Int_t precLength = TString("Precision").Length();
721             if (precLength == tmpCN.Length()) {
722               if(!orderedValues[6]){
723                 orderedValues[6] = &value[j];
724                 check[6] = kTRUE;
725               }else{
726                 AliWarning("Global precision will not be used for X axis");
727               }
728               if(!orderedValues[7]){
729                 orderedValues[7] = &value[j];
730                 check[7] = kTRUE;
731               }else{
732                 AliWarning("Global precision will not be used for Y axis");
733               }
734               if(!orderedValues[8]){
735                 orderedValues[8] = &value[j];
736                 check[8] = kTRUE;
737               }else{
738                 AliWarning("Global precision will not be used for Z axis");
739               }
740             } else {
741               Bool_t orXYZ = kFALSE;
742               TString axis = cn(precLength, tmpCN.Length() - precLength);
743               if (axis.Contains('X', TString::kIgnoreCase)) {
744                 if(!prX){
745                   orderedValues[6] = &value[j];
746                   check[6] = kTRUE;
747                   orXYZ = kTRUE;
748                   prX = kTRUE;
749                 }else{
750                   AliError("Precision for X axis was already set!");
751                   return kFALSE;
752                 }
753               }
754               if (axis.Contains('Y', TString::kIgnoreCase)) {
755                 if(!prY){
756                   orderedValues[7] = &value[j];
757                   check[7] = kTRUE;
758                   orXYZ = kTRUE;
759                   prY = kTRUE;
760                 }else{
761                   AliError("Precision for Y axis was already set!");
762                   return kFALSE;
763                 }
764               }
765               if (axis.Contains('Z', TString::kIgnoreCase)) {
766                 if(!prZ){
767                   orderedValues[8] = &value[j];
768                   check[8] = kTRUE;
769                   orXYZ = kTRUE;
770                   prZ = kTRUE;
771                 }else{
772                   AliError("Precision for Z axis was already set!");
773                   return kFALSE;
774                 }
775               }
776               if(!orXYZ)
777               {
778                 AliError("Survey text file sintax error: precision column name does not refer to any axis!");
779                 return kFALSE;
780               }
781             }
782           } else if (cn.BeginsWith("Point Type", TString::kIgnoreCase)) {
783             orderedValues[4] = &value[j];
784             check[4] = kTRUE;
785           } else if (cn.BeginsWith("Target Used", TString::kIgnoreCase)) {
786             orderedValues[5] = &value[j];
787             check[5] = kTRUE;
788           }
789         }
790
791         // Check if all the mandatory fields exist in the line with column names
792         if(!check[0]){
793           Printf("Missing mandatory column \"Point Name\"!");
794           return kFALSE;
795         }
796         if(!(check[1]&&check[2]&&check[3])){
797           Printf("Missing one or more mandatory columns for coordinates \"X\",\"Y\",\"Z\"");
798           return kFALSE;
799         }
800         if(!check[4]){
801           Printf("Missing mandatory column \"Point Type\"!");
802           return kFALSE;
803         }
804         if(!(check[6]&&check[7]&&check[8])){
805           Printf("Missing one or more mandatory columns for precision along \"X\",\"Y\",\"Z\" axes");
806           return kFALSE;
807         }
808
809       } else if (currLine.BeginsWith("Data", TString::kIgnoreCase)) {
810         // Data section!
811         while ((nextLine.Length() > 0) && ('>' != nextLine[0])) {
812
813           // Printf("Data LINE: \"%s\": %d\n", nextLine.Data(), nextLine.Length());
814
815           // What is the separator used between fields?
816           // The allowed are: comma (','), tab ('\t'), and space (' ')
817           if (fNrColumns == nextLine.CountChar(',') + 1) dataLine = nextLine.Tokenize(',');
818           else if (fNrColumns == nextLine.CountChar('\t') + 1) dataLine = nextLine.Tokenize('\t');
819           else if (fNrColumns == nextLine.CountChar(' ') + 1) dataLine = nextLine.Tokenize(' ');
820           else {
821             // Error (No separator was found!)
822             AliError("Survey text file syntax error! Error processing data line!");
823             lines->Delete();
824             return kFALSE;
825           }
826
827           if (dataLine->GetEntries() != fNrColumns) {
828             // The number of columns doesn't match the number specified in the header
829             AliError("Survey text file sintax error! (Number of entries in line is different from number of Columns)");
830             dataLine->Delete();
831             lines->Delete();
832             return kFALSE;
833           }
834
835           // Process the data line using the column names as index
836           for (Int_t j = 0; j < dataLine->GetEntries(); ++j) {
837             value[j] = ((TObjString *)(dataLine->At(j)))->GetString();
838           }
839           tmpname = *orderedValues[0];
840           tmpx = orderedValues[1]->Atof();
841           tmpy = orderedValues[2]->Atof();
842           tmpz = orderedValues[3]->Atof();
843           tmpprecX = orderedValues[6]->Atof();
844           tmpprecY = orderedValues[7]->Atof();
845           tmpprecZ = orderedValues[8]->Atof();
846           tmptype = orderedValues[4]->Data()[0];
847           if(orderedValues[5]) tmptarg = (orderedValues[5]->Data()[0] == 'Y') ? kTRUE : kFALSE;
848
849           dp = new AliSurveyPoint(tmpname, tmpx, tmpy, tmpz, tmpprecX, tmpprecY, tmpprecZ, tmptype, tmptarg);
850           dp->PrintPoint();
851           AddPoint(dp);
852
853           dataLine->Delete();
854           dataLine = NULL;
855           ++i;
856           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
857           nextLine = Sanitize(nextLine);
858         }
859       }
860     } else {
861       AliError("Survey text file sintax error!");
862       lines->Delete();
863       return kFALSE;
864     }
865   }
866   lines->Delete();
867   fIsValid = kTRUE;
868   return kTRUE;
869 }
870
871 //_____________________________________________________________________________
872 void AliSurveyObj::Reset() {
873   // Resets the AliSurveyObj to a clean object.
874   // Used if the same object is filled more than once
875   
876   if (fDataPoints) {
877     fDataPoints->Delete();
878     fDataPoints = 0;
879   }
880   fTitle = "";
881   fDate = "";
882   fDetector = "";
883   fURL = "http://edms.cern.ch/";
884   fReportNr = -1;
885   fVersion = -1;
886   fObs = "";
887   fCoordSys = "";
888   fUnits = "";
889   fNrColumns = -1;
890   fColNames = "";
891   fIsValid = kFALSE;
892   fDataPoints = new TObjArray(1);
893   fDataPoints->SetOwner(kTRUE);
894   return;
895 }
896