#include "TDocOutput.h"
#include "Riostream.h"
#include "TClassDocOutput.h"
#include "TDataMember.h"
#include "TDataType.h"
#include "TDocInfo.h"
#include "TDocParser.h"
#include "TEnv.h"
#include "TGlobal.h"
#include "THtml.h"
#include "TMethod.h"
#include "TROOT.h"
#include "TSystem.h"
#include <vector>
#include <list>
#include <set>
#include <sstream>
namespace {
   typedef std::vector<std::string> Words_t;
   typedef Words_t::const_iterator SectionStart_t;
   class TSectionInfo {
   public:
      TSectionInfo(SectionStart_t start, size_t chars, size_t size):
         fStart(start), fChars(chars), fSize(size) {};
         SectionStart_t fStart;
         size_t fChars;
         size_t fSize;
   };
   typedef std::list<TSectionInfo> SectionStarts_t;
   static void Sections_BuildIndex(SectionStarts_t& sectionStarts,
      SectionStart_t begin, SectionStart_t end, 
      size_t maxPerSection) 
   {
      
      
      SectionStart_t cursor = begin;
      if (sectionStarts.empty() || sectionStarts.back().fStart != cursor)
         sectionStarts.push_back(TSectionInfo(cursor, 1, 0));
      SectionStarts_t::iterator prevSection = sectionStarts.end();
      --prevSection;
      while (cursor != end) {
         size_t numLeft = end - cursor;
         size_t assumedNumSections = (numLeft + maxPerSection - 1 ) / maxPerSection;
         size_t step = ((numLeft + assumedNumSections - 1) / assumedNumSections);
         if (!step || step >= numLeft) return;
         cursor += step;
         if (cursor == end) break;
         SectionStart_t addWhichOne = prevSection->fStart;
         size_t selectionChar=1;
         for (; selectionChar <= cursor->length() && addWhichOne == prevSection->fStart; 
            ++selectionChar) {
            SectionStart_t checkPrev = cursor;
            while (--checkPrev != prevSection->fStart 
               && !strncasecmp(checkPrev->c_str(), cursor->c_str(), selectionChar));
            SectionStart_t checkNext = cursor;
            while (++checkNext != end
               && !strncasecmp(checkNext->c_str(), cursor->c_str(), selectionChar));
            
            if (checkPrev != prevSection->fStart)
               if ((cursor - checkPrev) <= (checkNext - cursor))
                  addWhichOne = ++checkPrev;
               else if (checkNext != end
                  && (size_t)(checkNext - cursor) < maxPerSection) {
                  addWhichOne = checkNext;
               }
         }
         if (addWhichOne == prevSection->fStart)
            addWhichOne = cursor;
         selectionChar = 1;
         while (selectionChar <= prevSection->fStart->length() 
            && selectionChar <= addWhichOne->length() 
            && !strncasecmp(prevSection->fStart->c_str(), addWhichOne->c_str(), selectionChar))
            ++selectionChar;
         sectionStarts.push_back(TSectionInfo(addWhichOne, selectionChar, 0));
         cursor = addWhichOne;
         ++prevSection;
      } 
   }
   static void Sections_SetSize(SectionStarts_t& sectionStarts, const Words_t &words)
   {
      
      for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
         iSectionStart != sectionStarts.end(); ++iSectionStart) {
         SectionStarts_t::iterator next = iSectionStart;
         ++next;
         if (next == sectionStarts.end()) {
            iSectionStart->fSize = (words.end() - iSectionStart->fStart);
            break;
         }
         iSectionStart->fSize = (next->fStart - iSectionStart->fStart);
      }
   }
   static void Sections_PostMerge(SectionStarts_t& sectionStarts, const size_t maxPerSection)
   {
      
      for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
         iSectionStart != sectionStarts.end();) {
         SectionStarts_t::iterator iNextSectionStart = iSectionStart;
         ++iNextSectionStart;
         if (iNextSectionStart == sectionStarts.end()) break;
         if (iNextSectionStart->fSize + iSectionStart->fSize < maxPerSection) {
            iSectionStart->fSize += iNextSectionStart->fSize;
            sectionStarts.erase(iNextSectionStart);
         } else ++iSectionStart;
      }
   }
   static void GetIndexChars(const Words_t& words, UInt_t numSectionsIn, 
      std::vector<std::string> §ionMarkersOut)
   {
      
      
      
      
      const size_t maxPerSection = (words.size() + numSectionsIn - 1)/ numSectionsIn;
      SectionStarts_t sectionStarts;
      Sections_BuildIndex(sectionStarts, words.begin(), words.end(), maxPerSection);
      Sections_SetSize(sectionStarts, words);
      Sections_PostMerge(sectionStarts, maxPerSection);
      
      sectionMarkersOut.clear();
      sectionMarkersOut.resize(sectionStarts.size());
      size_t idx = 0;
      for (SectionStarts_t::iterator iSectionStart = sectionStarts.begin();
         iSectionStart != sectionStarts.end(); ++iSectionStart)
         sectionMarkersOut[idx++] = 
            iSectionStart->fStart->substr(0, iSectionStart->fChars);
   }
   static void GetIndexChars(const std::list<std::string>& wordsIn, UInt_t numSectionsIn, 
      std::vector<std::string> §ionMarkersOut)
   {
      
      Words_t words(wordsIn.size());
      size_t idx = 0;
      for (std::list<std::string>::const_iterator iWord = wordsIn.begin(); iWord != wordsIn.end(); ++iWord)
         words[idx++] = *iWord;
      GetIndexChars(words, numSectionsIn, sectionMarkersOut);
   }
}
namespace {
   
   static int CaseInsensitiveSort(const void *name1, const void *name2)
   {
   
   
   
   
   
   
   
   
   
   
   
   
      return (strcasecmp(*((char **) name1), *((char **) name2)));
   }
   
   static void sort_strlist_stricmp(std::list<std::string>& l)
   {
      
      struct posList {
         const char* str;
         std::list<std::string>::const_iterator pos;
      };
      posList* carr = new posList[l.size()];
      size_t idx = 0;
      for (std::list<std::string>::const_iterator iS = l.begin(); iS != l.end(); ++iS) {
         carr[idx].pos = iS;
         carr[idx++].str = iS->c_str();
      }
      qsort(&carr[0].str, idx, sizeof(posList), CaseInsensitiveSort);
      std::list<std::string> lsort;
      for (idx = 0; idx < l.size(); ++idx) {
         lsort.push_back(*carr[idx].pos);
      }
      delete [] carr;
      l.swap(lsort);
   }
}
ClassImp(TDocOutput);
TDocOutput::TDocOutput(THtml& html): fHtml(&html)
{}
TDocOutput::~TDocOutput()
{}
void TDocOutput::AddLink(TSubString& str, TString& link, const char* comment)
{
   
   
   
   if (ReferenceIsRelative(link) && !link.BeginsWith("./"))
      link.Prepend("./");
   link.Prepend("<a href=\"");
   link += "\"";
   if (comment && strlen(comment)) {
      link += " title=\"";
      TString description(comment);
      ReplaceSpecialChars(description);
      description.ReplaceAll("\"", """);
      link += description;
      link += "\"";
   }
   link += ">";
   str.String().Insert(str.Start() + str.Length(), "</a>");
   str.String().Insert(str.Start(), link);
   TString &strString = str.String();
   TSubString update = strString(str.Start(), str.Length() + link.Length() + 4);
   str = update;
}
void TDocOutput::AdjustSourcePath(TString& line, const char* relpath )
{
   
   
   TString replWithRelPath("=\"");
   replWithRelPath += relpath;
   line.ReplaceAll("=\"./", replWithRelPath);
}
void TDocOutput::Convert(std::istream& in, const char* outfilename, const char *title,
                         const char *relpath )
{
   
   
   
   
   TString htmlFilename(outfilename);
   htmlFilename += ".html";
   std::ofstream out(htmlFilename);
   if (!out.good()) {
      Error("Convert", "Can't open file '%s' !", htmlFilename.Data());
      return;
   }
   Printf("Convert: %s", htmlFilename.Data());
   
   WriteHtmlHeader(out, title, relpath);
   out << "<h1>" << title << "</h1>" << endl;
   out << "<pre>" << endl;
   TDocParser parser(*this);
   parser.Convert(out, in, relpath);
   out << "</pre>" << endl;
   
   WriteHtmlFooter(out, relpath);
}
Bool_t TDocOutput::CopyHtmlFile(const char *sourceName, const char *destName)
{
   
   char *tmp1 = gSystem->Which(fHtml->GetSourceDir(), sourceName, kReadPermission);
   if (!tmp1) {
      Error("Copy", "Can't copy file '%s' to '%s/%s' - can't find source file!", sourceName,
            fHtml->GetOutputDir().Data(), destName);
      return kFALSE;
   }
   TString sourceFile(tmp1);
   delete[]tmp1;
   if (!sourceFile.Length()) {
      Error("Copy", "Can't copy file '%s' to '%s' directory - source file name invalid!", sourceName,
            fHtml->GetOutputDir().Data());
      return kFALSE;
   }
   
   TString destFile;
   if (!destName || !*destName)
      destFile = fHtml->GetFileName(sourceFile);
   else
      destFile = fHtml->GetFileName(destName);
   gSystem->PrependPathName(fHtml->GetOutputDir(), destFile);
   
   Long64_t size;
   Long_t id, flags, sModtime, dModtime;
   sModtime = 0;
   dModtime = 0;
   if (gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)
      || gSystem->GetPathInfo(destFile, &id, &size, &flags, &dModtime)
      || sModtime > dModtime)
      gSystem->CopyFile(sourceFile, destFile, kTRUE);
   return kTRUE;
}
void TDocOutput::CreateHierarchy()
{
   
   TString filename("ClassHierarchy.html");
   gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
   
   std::ofstream out(filename);
   if (!out.good()) {
      Error("CreateHierarchy", "Can't open file '%s' !", filename.Data());
      return;
   }
   Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
   
   WriteHtmlHeader(out, "Class Hierarchy");
   out << "<h1>Class Hierarchy</h1>" << endl;
   WriteSearch(out);
   
   TClassDocInfo* cdi = 0;
   TIter iClass(fHtml->GetListOfClasses());
   while ((cdi = (TClassDocInfo*)iClass())) {
      if (!cdi->HaveSource())
         continue;
      
      TClass *basePtr = cdi->GetClass();
      if (basePtr == 0) {
         Warning("THtml::CreateHierarchy", "skipping class %s\n", cdi->GetName());
         continue;
      }
      TClassDocOutput cdo(*fHtml, basePtr);
      cdo.CreateClassHierarchy(out, cdi->GetHtmlFileName());
   }
   
   WriteHtmlFooter(out);
}
void TDocOutput::CreateClassIndex()
{
   
   fHtml->CreateAuxiliaryFiles();
   TString filename("ClassIndex.html");
   gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
   
   std::ofstream indexFile(filename.Data());
   if (!indexFile.good()) {
      Error("CreateClassIndex", "Can't open file '%s' !", filename.Data());
      return;
   }
   Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
   
   WriteHtmlHeader(indexFile, "Class Index");
   indexFile << "<h1>Index</h1>" << endl;
   WriteModuleLinks(indexFile);
   std::vector<std::string> indexChars;
   if (fHtml->GetListOfClasses()->GetSize() > 10) {
      std::vector<std::string> classNames;
      {
         TIter iClass(fHtml->GetListOfClasses());
         TClassDocInfo* cdi = 0;
         while ((cdi = (TClassDocInfo*)iClass()))
            if (cdi->IsSelected() && cdi->HaveSource())
               classNames.push_back(cdi->GetName());
      }
      if (classNames.size() > 10) {
         indexFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
         
         GetIndexChars(classNames, 50 , indexChars);
         for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
            indexFile << "<a href=\"#idx" << iIdxEntry << "\">";
            ReplaceSpecialChars(indexFile, indexChars[iIdxEntry].c_str());
            indexFile << "</a>" << endl;
         }
         indexFile << "</div><br />" << endl;
      }
   }
   WriteSearch(indexFile);
   indexFile << "<ul id=\"indx\">" << endl;
   
   UInt_t currentIndexEntry = 0;
   TIter iClass(fHtml->GetListOfClasses());
   TClassDocInfo* cdi = 0;
   Int_t i = 0;
   while ((cdi = (TClassDocInfo*)iClass())) {
      if (!cdi->IsSelected() || !cdi->HaveSource())
         continue;
      
      TClass* currentClass = cdi->GetClass();
      if (!currentClass) {
         Warning("THtml::CreateClassIndex", "skipping class %s\n", cdi->GetName());
         continue;
      }
      indexFile << "<li class=\"idxl" << (i++)%2 << "\">";
      if (currentIndexEntry < indexChars.size()
         && !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(), 
                     indexChars[currentIndexEntry].length()))
         indexFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
      TString htmlFile(cdi->GetHtmlFileName());
      if (htmlFile.Length()) {
         indexFile << "<a href=\"";
         indexFile << htmlFile;
         indexFile << "\"><span class=\"typename\">";
         ReplaceSpecialChars(indexFile, cdi->GetName());
         indexFile << "</span></a> ";
      } else {
         indexFile << "<span class=\"typename\">";
         ReplaceSpecialChars(indexFile, cdi->GetName());
         indexFile << "</span> ";
      }
      
      ReplaceSpecialChars(indexFile, currentClass->GetTitle());
      indexFile << "</li>" << endl;
   }
   indexFile << "</ul>" << endl;
   
   WriteHtmlFooter(indexFile);
}
void TDocOutput::CreateModuleIndex()
{
   
   
   
   
   const char* title = "LibraryDependencies";
   TString filename(title);
   gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
   std::ofstream libDepDotFile(filename + ".dot");
   libDepDotFile << "strict digraph G {" << endl
                 << "ratio=auto;" << endl
                 << "rankdir=RL;" << endl
                 << "compound=true;" << endl
                 << "constraint=false;" << endl
                 << "ranksep=3;" << endl
                 << "nodesep=0.1;" << endl
                 << "ratio=compress;" << endl
                 << "node [fontsize=10];" << endl
                 << "size=\"16,20\";" << endl;
   TModuleDocInfo* module = 0;
   TIter iModule(fHtml->GetListOfModules());
   std::stringstream sstrCluster;
   std::stringstream sstrDeps;
   while ((module = (TModuleDocInfo*)iModule())) {
      if (!module->IsSelected())
         continue;
      std::vector<std::string> indexChars;
      TString filename(module->GetName());
      filename += "_Index.html";
      gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
      std::ofstream outputFile(filename.Data());
      if (!outputFile.good()) {
         Error("MakeIndex", "Can't open file '%s' !", filename.Data());
         continue;
      }
      Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), filename.Data());
      TString htmltitle("Index of ");
      htmltitle += module->GetName();
      htmltitle += " classes";
      WriteHtmlHeader(outputFile, htmltitle);
      outputFile << "<h2>" << htmltitle << "</h2>" << endl;
      
      if (GetHtml()->GetModuleDocPath().Length()) {
         TString outdir(module->GetName());
         gSystem->PrependPathName(GetHtml()->GetOutputDir(), outdir);
         TString moduleDocDir(GetHtml()->GetModuleDocPath());
         if (!gSystem->IsAbsoluteFileName(moduleDocDir))
            gSystem->PrependPathName(module->GetSourceDir(), moduleDocDir);
         ProcessDocInDir(outputFile, moduleDocDir, outdir, module->GetName());
      }
      std::list<std::string> classNames;
      {
         TIter iClass(module->GetClasses());
         TClassDocInfo* cdi = 0;
         while ((cdi = (TClassDocInfo*) iClass())) {
            if (!cdi->IsSelected() || !cdi->HaveSource())
               continue;
            classNames.push_back(cdi->GetName());
            if (classNames.size() > 1) continue;
            TString libs(cdi->GetClass()->GetSharedLibs());
            Ssiz_t posDepLibs = libs.Index(' ');
            TString thisLib(libs);
            if (posDepLibs != kNPOS)
               thisLib.Remove(posDepLibs, thisLib.Length());
            Ssiz_t posExt = thisLib.First('.');
            if (posExt != kNPOS)
               thisLib.Remove(posExt, thisLib.Length());
            if (!thisLib.Length())
               continue;
            
            std::set<std::string>& setDep = fHtml->GetLibraryDependencies()[thisLib.Data()][module->GetName()];
            if (posDepLibs != kNPOS) {
               std::string lib;
               for(Ssiz_t pos = posDepLibs + 1; libs[pos]; ++pos) {
                  if (libs[pos] == ' ') {
                     if (thisLib.Length() && lib.length()) {
                        size_t posExt = lib.find('.');
                        if (posExt != std::string::npos)
                           lib.erase(posExt);
                        setDep.insert(lib);
                     }
                     lib.erase();
                  } else 
                     lib += libs[pos];
               }
               if (lib.length() && thisLib.Length()) {
                  size_t posExt = lib.find('.');
                  if (posExt != std::string::npos)
                     lib.erase(posExt);
                  setDep.insert(lib);
               }
            } 
         } 
      } 
      if (classNames.size() > 10) {
         outputFile << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
         UInt_t numSections = classNames.size() / 10;
         if (numSections < 10) numSections = 10;
         if (numSections > 50) numSections = 50;
         
         GetIndexChars(classNames, numSections, indexChars);
         for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
            outputFile << "<a href=\"#idx" << iIdxEntry << "\">";
            ReplaceSpecialChars(outputFile, indexChars[iIdxEntry].c_str());
            outputFile << "</a>" << endl;
         }
         outputFile << "</div><br />" << endl;
      }
      outputFile << "<ul id=\"indx\">" << endl;
      TIter iClass(module->GetClasses());
      TClassDocInfo* cdi = 0;
      UInt_t count = 0;
      UInt_t currentIndexEntry = 0;
      while ((cdi = (TClassDocInfo*) iClass())) {
         if (!cdi->IsSelected() || !cdi->HaveSource())
            continue;
         TClass *classPtr = cdi->GetClass();
         if (!classPtr) {
            Error("MakeIndex", "Unknown class '%s' !", cdi->GetName());
            continue;
         }
         
         outputFile << "<li class=\"idxl" << (count++)%2 << "\">";
         if (currentIndexEntry < indexChars.size()
            && !strncmp(indexChars[currentIndexEntry].c_str(), cdi->GetName(), 
                        indexChars[currentIndexEntry].length()))
            outputFile << "<a name=\"idx" << currentIndexEntry++ << "\"></a>";
         TString htmlFile(cdi->GetHtmlFileName());
         if (htmlFile.Length()) {
            outputFile << "<a href=\"";
            outputFile << htmlFile;
            outputFile << "\"><span class=\"typename\">";
            ReplaceSpecialChars(outputFile, classPtr->GetName());
            outputFile << "</span></a> ";
         } else {
            outputFile << "<span class=\"typename\">";
            ReplaceSpecialChars(outputFile, classPtr->GetName());
            outputFile << "</span> ";
         }
         
         ReplaceSpecialChars(outputFile, classPtr->GetTitle());
         outputFile << "</li>" << endl;
      }
      outputFile << "</ul>" << endl;
      
      WriteHtmlFooter(outputFile);
   } 
   
   
   
   for (THtml::LibDep_t::iterator iLibDep = fHtml->GetLibraryDependencies().begin();
      iLibDep != fHtml->GetLibraryDependencies().end(); ++iLibDep) {
      if (!iLibDep->first.length()) 
         continue;
      sstrCluster << "subgraph cluster" << iLibDep->first << " {" << endl
         << "style=filled;" << endl
         << "color=lightgray;" << endl
         << "label=\"";
      if (iLibDep->first == "libCore")
         sstrCluster << "Everything depends on ";
      sstrCluster << iLibDep->first << "\";" << endl;
      for (std::map<std::string, std::set<std::string> >::iterator iModule = iLibDep->second.begin();
         iModule != iLibDep->second.end(); ++iModule) {
         sstrCluster << "\"" << iModule->first << "\" [style=filled,color=white,URL=\"" 
            << iModule->first << "_Index.html\",fontsize=10];" << endl;
         
         
         for (std::set<std::string>::iterator iLib = iModule->second.begin();
            iLib != iModule->second.end(); ++iLib) {
            const THtml::TMapModuleDepMap& modDep = fHtml->GetLibraryDependencies()[*iLib];
            if (modDep.size()) {
               THtml::TMapModuleDepMap::const_iterator iModDep = modDep.begin();
               const std::string& mod = iModDep->first;
               sstrDeps << "\"" << iModule->first << "\" -> \"" << mod << "\" [lhead=cluster" << *iLib << "];" << endl;
            }
            
            sstrDeps << "\"" << iModule->first <<  "\" -> \"CONT\" [style=invis];" << endl;
         }
      } 
      sstrCluster << endl 
         << "}" << endl;
   } 
   libDepDotFile << sstrCluster.str() << endl
      << sstrDeps.str();
   libDepDotFile << "}" << endl;
   libDepDotFile.close();
   std::ofstream out(filename + ".html");
   if (!out.good()) {
      Error("CreateModuleIndex", "Can't open file '%s.html' !",
            filename.Data());
      return;
   }
   Printf(fHtml->GetCounterFormat(), "", fHtml->GetCounter(), (filename + ".html").Data());
   
   WriteHtmlHeader(out, "Library Dependencies");
   out << "<h1>Library Dependencies</h1>" << endl;
   WriteSearch(out);
   RunDot(filename, &out);
   out << "<img alt=\"Library Dependencies\" class=\"formatsel\" usemap=\"#Map" << title << "\" src=\"" << title << ".gif\"/>" << endl;
   
   WriteHtmlFooter(out);
}
void TDocOutput::CreateProductIndex()
{
   
   
   
   
   TString outFile("index.html");
   gSystem->PrependPathName(GetHtml()->GetOutputDir(), outFile);
   std::ofstream out(outFile);
   if (!out.good()) {
      Error("CreateProductIndex", "Can't open file '%s' !", outFile.Data());
      return;
   }
   Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
   WriteHtmlHeader(out, GetHtml()->GetProductName() + " Reference Guide");
   out << "<h1>" << GetHtml()->GetProductName() + " Reference Guide</h1>" << std::endl;
   if (GetHtml()->GetProductDocDir().Length())
      ProcessDocInDir(out, GetHtml()->GetProductDocDir(), GetHtml()->GetOutputDir(), "./");
   WriteModuleLinks(out);
   out << "<h2>Chapters</h2>" << std::endl
      << "<h3><a href=\"./ClassIndex.html\">Class Index</a></h3>" << std::endl
      << "<p>A complete list of all classes defined in " << GetHtml()->GetProductName() << "</p>" << std::endl
      << "<h3><a href=\"./ClassHierarchy.html\">Class Hierarchy</a></h3>" << std::endl
      << "<p>A hierarchy graph of all classes, showing each class's base and derived classes</p>" << std::endl
      << "<h3><a href=\"./ListOfTypes.html\">Type Index</a></h3>" << std::endl
      << "<p>A complete list of all types</p>" << std::endl
      << "<h3><a href=\"./LibraryDependencies.html\">Library Dependency</a></h3>" << std::endl
      << "<p>A diagram showing all of " << GetHtml()->GetProductName() << "'s libraries and their dependencies</p>" << std::endl;
   WriteHtmlFooter(out);
}
void TDocOutput::CreateTypeIndex()
{
   
   TString outFile("ListOfTypes.html");
   gSystem->PrependPathName(fHtml->GetOutputDir(), outFile);
   std::ofstream typesList(outFile);
   if (!typesList.good()) {
      Error("CreateTypeIndex", "Can't open file '%s' !", outFile.Data());
      return;
   }
   Printf(fHtml->GetCounterFormat(), "", "", outFile.Data());
   
   WriteHtmlHeader(typesList, "List of data types");
   typesList << "<h2> List of data types </h2>" << endl;
   typesList << "<dl><dd>" << endl;
   
   TDataType *type;
   TIter nextType(gROOT->GetListOfTypes());
   std::list<std::string> typeNames;
   while ((type = (TDataType *) nextType()))
      
      if (*type->GetTitle() && !strchr(type->GetName(), '(')
          && !( strchr(type->GetName(), '<') && strchr(type->GetName(),'>'))
          && type->GetName())
            typeNames.push_back(type->GetName());
   sort_strlist_stricmp(typeNames);
   std::vector<std::string> indexChars;
   if (typeNames.size() > 10) {
      typesList << "<div id=\"indxShortX\"><h4>Jump to</h4>" << endl;
      
      GetIndexChars(typeNames, 10 , indexChars);
      for (UInt_t iIdxEntry = 0; iIdxEntry < indexChars.size(); ++iIdxEntry) {
         typesList << "<a href=\"#idx" << iIdxEntry << "\">";
         ReplaceSpecialChars(typesList, indexChars[iIdxEntry].c_str());
         typesList << "</a>" << endl;
      }
      typesList << "</div><br />" << endl;
   }
   typesList << "<ul id=\"indx\">" << endl;
   nextType.Reset();
   int idx = 0;
   UInt_t currentIndexEntry = 0;
   for (std::list<std::string>::iterator iTypeName = typeNames.begin(); 
      iTypeName != typeNames.end(); ++iTypeName) {
      TDataType* type = gROOT->GetType(iTypeName->c_str(), kFALSE);
      typesList << "<li class=\"idxl" << idx%2 << "\">";
      if (currentIndexEntry < indexChars.size()
         && !strncmp(indexChars[currentIndexEntry].c_str(), iTypeName->c_str(), 
                     indexChars[currentIndexEntry].length()))
         typesList << "<a name=\"idx" << currentIndexEntry++ << "\"></a>" << endl;
      typesList << "<a name=\"";
      ReplaceSpecialChars(typesList, iTypeName->c_str());
      typesList << "\"><span class=\"typename\">";
      ReplaceSpecialChars(typesList, iTypeName->c_str());
      typesList << "</span></a> ";
      ReplaceSpecialChars(typesList, type->GetTitle());
      typesList << "</li>" << endl;
      ++idx;
   }
   typesList << "</ul>" << endl;
   
   WriteHtmlFooter(typesList);
   
   typesList.close();
}
void TDocOutput::DecorateEntityBegin(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
{
   
   
   
   
   
   Ssiz_t originalLen = str.Length();
   switch (type) {
      case TDocParser::kCode: break;
      case TDocParser::kComment:
         str.Insert(pos, "<span class=\"comment\">");
         break;
      case TDocParser::kDirective:
         break;
      case TDocParser::kString:
         str.Insert(pos, "<span class=\"string\">");
         break;
      case TDocParser::kKeyword:
         str.Insert(pos, "<span class=\"keyword\">");
         break;
      case TDocParser::kCPP:
         str.Insert(pos, "<span class=\"cpp\">");
         break;
      case TDocParser::kVerbatim:
         str.Insert(pos, "<pre>");
         break;
      default:
         Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
         return;
   }
   Ssiz_t addedLen = str.Length() - originalLen;
   pos += addedLen;
}
void TDocOutput::DecorateEntityEnd(TString& str, Ssiz_t& pos, TDocParser::EParseContext type)
{
   
   
   
   
   
   
   Ssiz_t originalLen = str.Length();
   switch (type) {
      case TDocParser::kCode: break;
      case TDocParser::kComment:
         str.Insert(pos, "</span>");
         break;
      case TDocParser::kDirective:
         break;
      case TDocParser::kString:
         str.Insert(pos, "</span>");
         break;
      case TDocParser::kKeyword:
         str.Insert(pos, "</span>");
         break;
      case TDocParser::kCPP:
         str.Insert(pos, "</span>");
         break;
      case TDocParser::kVerbatim:
         str.Insert(pos, "</pre>");
         break;
      default:
         Error("DecorateEntityBegin", "Unhandled / invalid entity type %d!", (Int_t)type);
         return;
   }
   Ssiz_t addedLen = str.Length() - originalLen;
   pos += addedLen;
}
void TDocOutput::FixupAuthorSourceInfo(TString& authors)
{
   TString original(authors);
   authors = "";
   TString author;
   Ssiz_t pos = 0;
   Bool_t firstAuthor = kTRUE;
   while (original.Tokenize(author, pos, ",")) {
      author.Strip(TString::kBoth);
      if (!firstAuthor)
         authors += ", ";
      firstAuthor = kFALSE;
      
      Ssiz_t cLink = author.First('<'); 
      if (cLink != kNPOS) {
         
         
         Ssiz_t endLink = author.Index(">", cLink + 1);
         if(endLink == kNPOS)
            endLink = author.Length();
         authors += "<a href=\"";
         authors += author(cLink + 1,  endLink - (cLink + 1));
         authors += "\">";
         authors += author(0, cLink);
         authors += "</a>";
         if (endLink != author.Length())
            authors += author(endLink + 1, author.Length());
      } else {
         authors += "<a href=\"";
         authors += fHtml->GetXwho();
         
         TString namePart;
         Ssiz_t posNamePart = 0;
         Bool_t firstNamePart = kTRUE;
         while (author.Tokenize(namePart, posNamePart, " ")) {
            namePart.Strip(TString::kBoth);
            if (!namePart.Length())
               continue;
            if (!firstNamePart)
               authors += '+';
            firstNamePart = kFALSE;
            authors += namePart;
         }
         authors += "\">";
         authors += author;
         authors += "</a>";
      }
   } 
}
Bool_t TDocOutput::IsModified(TClass * classPtr, EFileType type)
{
   TString sourceFile;
   TString classname(classPtr->GetName());
   TString filename;
   TString dir;
   switch (type) {
   case kSource:
      if (classPtr->GetImplFileLine()) {
         sourceFile = fHtml->GetImplFileName(classPtr);
         fHtml->GetSourceFileName(sourceFile);
      } else {
         sourceFile = fHtml->GetDeclFileName(classPtr);
         fHtml->GetSourceFileName(sourceFile);
      }
      dir = "src";
      gSystem->PrependPathName(fHtml->GetOutputDir(), dir);
      filename = classname;
      NameSpace2FileName(filename);
      gSystem->PrependPathName(dir, filename);
      if (classPtr->GetImplFileLine())
         filename += ".cxx.html";
      else
         filename += ".h.html";
      break;
   case kInclude:
      filename = fHtml->GetDeclFileName(classPtr);
      sourceFile = filename;
      fHtml->GetSourceFileName(sourceFile);
      filename = fHtml->GetFileName(filename);
      gSystem->PrependPathName(fHtml->GetOutputDir(), filename);
      break;
   case kTree:
      sourceFile = fHtml->GetDeclFileName(classPtr);
      fHtml->GetSourceFileName(sourceFile);
      NameSpace2FileName(classname);
      gSystem->PrependPathName(fHtml->GetOutputDir(), classname);
      filename = classname;
      filename += "_Tree.pdf";
      break;
   default:
      Error("IsModified", "Unknown file type !");
   }
   
   Long64_t size;
   Long_t id, flags, sModtime, dModtime;
   if (!(gSystem->GetPathInfo(sourceFile, &id, &size, &flags, &sModtime)))
      if (!(gSystem->GetPathInfo(filename, &id, &size, &flags, &dModtime)))
         return (sModtime > dModtime);
   return kTRUE;
}
void TDocOutput::NameSpace2FileName(TString& name)
{
   
   
   const char* replaceWhat = ":<> ,~=";
   for (Ssiz_t i=0; i < name.Length(); ++i)
      if (strchr(replaceWhat, name[i])) 
         name[i] = '_';
}
void TDocOutput::ProcessDocInDir(std::ostream& out, const char* indir, 
                                 const char* outdir, const char* linkdir)
{
   
   
   
   
   
   void * dirHandle = gSystem->OpenDirectory(indir);
   if (!dirHandle) return;
   const char* entry = 0;
   std::list<std::string> files;
   while ((entry = gSystem->GetDirEntry(dirHandle))) {
      FileStat_t stat;
      TString filename(entry);
      gSystem->PrependPathName(indir, filename);
      if (gSystem->GetPathInfo(filename, stat)) 
         continue;
      if (!R_ISREG(stat.fMode)) continue;
      if (TString(entry).BeginsWith("index.", TString::kIgnoreCase)) {
         
         
         if (filename.EndsWith(".txt", TString::kIgnoreCase)) {
            std::ifstream in(filename);
            if (in) {
               out << "<pre>"; 
               TDocParser parser(*this);
               parser.Convert(out, in, "../");
               out << "</pre>";
            }
         } else if (filename.EndsWith(".html", TString::kIgnoreCase)) {
            std::ifstream in(filename);
            TString line;
            while (in) {
               if (!line.ReadLine(in)) break;
               out << line;
            }
         }
      } else
         files.push_back(filename.Data());
   }
   std::stringstream furtherReading;
   files.sort();
   for (std::list<std::string>::const_iterator iFile = files.begin();
      iFile != files.end(); ++iFile) {
      TString filename(iFile->c_str());
      if (!filename.EndsWith(".txt", TString::kIgnoreCase) 
         && !filename.EndsWith(".html", TString::kIgnoreCase))
         continue;
      
      if (gSystem->AccessPathName(outdir))
         if (gSystem->mkdir(outdir, kTRUE) == -1)
            
            Error("CreateModuleIndex", "Cannot create output directory %s", outdir);
      TString outfile(gSystem->BaseName(filename));
      gSystem->PrependPathName(outdir, outfile);
      if (outfile.EndsWith(".txt", TString::kIgnoreCase)) {
         
         outfile.Remove(outfile.Length()-3, 3);
         outfile += "html";
         std::ifstream in(filename);
         std::ofstream out(outfile);
         if (in && out) {
            out << "<pre>"; 
            TDocParser parser(*this);
            parser.Convert(out, in, "../");
            out << "</pre>";
         }
      } else {
         if (gSystem->CopyFile(filename, outfile, kTRUE) == -1)
            continue;
      }
      TString showname(gSystem->BaseName(outfile));
      furtherReading << "<a class=\"linkeddoc\" href=\"" << linkdir << "/" << showname << "\">";
      showname.Remove(showname.Length() - 5, 5); 
      showname.ReplaceAll("_", " ");
      ReplaceSpecialChars(furtherReading, showname);
      furtherReading << "</a> " << endl;
   }
   gSystem->FreeDirectory(dirHandle);
   if (furtherReading.str().length())
      out << "<h3>Further Reading</h3><div id=\"furtherreading\">" << endl
          << furtherReading.str() << "</div><h3>List of Classes</h3>" << endl;
}
void TDocOutput::ReferenceEntity(TSubString& str, TClass* entity, const char* comment )
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   TString link;
   fHtml->GetHtmlFileName(entity, link);
   if (comment && !strcmp(comment, entity->GetName()))
      comment = "";
   AddLink(str, link, comment);
}
void TDocOutput::ReferenceEntity(TSubString& str, TDataMember* entity, const char* comment )
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   TString link;
   TClass* scope = entity->GetClass();
   fHtml->GetHtmlFileName(scope, link);
   link += "#";
   TString mangledName(scope->GetName());
   NameSpace2FileName(mangledName);
   link += mangledName;
   link += ":";
   mangledName = entity->GetName();
   NameSpace2FileName(mangledName);
   link += mangledName;
   TString description;
   if (!comment) {
      description = entity->GetFullTypeName();
      description += " ";
      if (scope) {
         description += scope->GetName();
         description += "::";
      }
      description += entity->GetName();
      comment = description.Data();
   }
   if (comment && !strcmp(comment, entity->GetName()))
      comment = "";
   AddLink(str, link, comment);
}
void TDocOutput::ReferenceEntity(TSubString& str, TDataType* entity, const char* comment )
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   TString link("ListOfTypes.html#");
   TString mangledEntity(entity->GetName());
   NameSpace2FileName(mangledEntity);
   link += mangledEntity;
   if (comment && !strcmp(comment, entity->GetName()))
      comment = "";
   AddLink(str, link, comment);
}
void TDocOutput::ReferenceEntity(TSubString& str, TMethod* entity, const char* comment )
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   TString link;
   TClass* scope = entity->GetClass();
   fHtml->GetHtmlFileName(scope, link);
   link += "#";
   TString mangledName(scope->GetName());
   NameSpace2FileName(mangledName);
   link += mangledName;
   link += ":";
   mangledName = entity->GetName();
   NameSpace2FileName(mangledName);
   link += mangledName;
   TString description;
   if (!comment && entity->GetClass()) {
      TIter iMeth(scope->GetListOfMethods());
      TMethod* mCand = 0;
      while ((mCand = (TMethod*)iMeth()))
         if (!strcmp(mCand->GetName(), entity->GetName())) {
            if (description.Length()) {
               description += " or overloads";
               break;
            }
            description = mCand->GetPrototype();
         }
      comment = description.Data();
   }
   if (comment && !strcmp(comment, entity->GetName()))
      comment = "";
   AddLink(str, link, comment);
}
Bool_t TDocOutput::ReferenceIsRelative(const char* reference) const
{
   
   
   
   return !reference || 
      strncmp(reference, "http", 4) ||
      strncmp(reference + 4, "://", 3) && strncmp(reference + 4, "s://", 4);
}
const char* TDocOutput::ReplaceSpecialChars(const char c)
{
   
   switch (c) {
      case '<': return "<";
      case '&': return "&";
      case '>': return ">";
   };
   return 0;
}
void TDocOutput::ReplaceSpecialChars(TString& text, Ssiz_t &pos)
{
   const char c = text[pos];
   const char* replaced = ReplaceSpecialChars(c);
   if (replaced) {
         text.Replace(pos, 1, replaced);
         pos += strlen(replaced) - 1;
   }
   ++pos;
}
void TDocOutput::ReplaceSpecialChars(TString& text) {
   Ssiz_t pos = 0;
   while (pos < text.Length())
         ReplaceSpecialChars(text, pos);
}
void TDocOutput::ReplaceSpecialChars(std::ostream& out, const char *string)
{
   while (string && *string) {
      const char* replaced = ReplaceSpecialChars(*string);
      if (replaced)
         out << replaced;
      else
         out << *string;
      string++;
   }
}
Bool_t TDocOutput::RunDot(const char* filename, std::ostream* outMap ) {
   if (!fHtml->HaveDot()) 
      return kFALSE;
   TString runDot("dot");
   if (fHtml->GetDotDir() && *fHtml->GetDotDir())
      gSystem->PrependPathName(fHtml->GetDotDir(), runDot);
   runDot += " -q1 -Tgif -o";
   runDot += filename;
   runDot += ".gif ";
   if (outMap) {
      runDot += "-Tcmap -o";
      runDot += filename;
      runDot += ".map ";
   }
   runDot += filename;
   runDot += ".dot";
   if (gDebug > 3)
      Info("RunDot", "Running: %s", runDot.Data());
   Int_t retDot = gSystem->Exec(runDot);
   if (gDebug < 4 && !retDot)
      gSystem->Unlink(Form("%s.dot", filename));
   if (!retDot && outMap) {
      ifstream inmap(Form("%s.map", filename));
      std::string line;
      std::getline(inmap, line);
      if (inmap && !inmap.eof()) {
         *outMap << "<map name=\"Map" << gSystem->BaseName(filename) 
            << "\" id=\"Map" << gSystem->BaseName(filename) << "\">" << endl;
         while (inmap && !inmap.eof()) {
            if (line.compare(0, 6, "<area ") == 0) {
               size_t posEndTag = line.find('>');
               if (posEndTag != std::string::npos)
                  line.replace(posEndTag, 1, "/>");
            }
            *outMap << line << endl;
            std::getline(inmap, line);
         }
         *outMap << "</map>" << endl;
      }
      inmap.close();
      if (gDebug < 7)
         gSystem->Unlink(Form("%s.map", filename));
   }
   if (retDot) {
      Error("RunDot", "Error running %s!", runDot.Data());
      fHtml->SetFoundDot(kFALSE);
      return kFALSE;
   }
   return kTRUE;
}
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *titleNoSpecial, 
                            const char* dir , TClass *cls ,
                            const char* header)
{
   ifstream addHeaderFile(header);
   if (!addHeaderFile.good()) {
      Warning("THtml::WriteHtmlHeader",
              "Can't open html header file %s\n", header);
      return;
   }
   const TString& charset = GetHtml()->GetCharset();
   TDatime date;
   TString strDate(date.AsString());
   TString line;
   while (!addHeaderFile.eof()) {
      line.ReadLine(addHeaderFile, kFALSE);
      if (addHeaderFile.eof())
         break;
      if (line) {
         if (!cls && (
            line.Index("%CLASS%") != kNPOS ||
            line.Index("%INCFILE%") != kNPOS ||
            line.Index("%SRCFILE%") != kNPOS))
            continue; 
         TString txt(line);
         txt.ReplaceAll("%TITLE%", titleNoSpecial);
         txt.ReplaceAll("%DATE%", strDate);
         txt.ReplaceAll("%RELDIR%", dir);
         txt.ReplaceAll("%CHARSET%", charset);
         if (cls) {
            txt.ReplaceAll("%CLASS%", cls->GetName());
            txt.ReplaceAll("%INCFILE%", fHtml->GetDeclFileName(cls));
            txt.ReplaceAll("%SRCFILE%", fHtml->GetImplFileName(cls));
         }
         out << txt << endl;
      }
   }
}
void TDocOutput::WriteHtmlHeader(std::ostream& out, const char *title, 
                            const char* dir , TClass *cls)
{
   TString userHeader = GetHtml()->GetHeader();
   TString noSpecialCharTitle(title);
   ReplaceSpecialChars(noSpecialCharTitle);
   Ssiz_t lenUserHeader = userHeader.Length();
   
   Bool_t bothHeaders = lenUserHeader > 0 && userHeader[lenUserHeader - 1] == '+';
   if (lenUserHeader == 0 || bothHeaders) {
      TString header("header.html");
      gSystem->PrependPathName(fHtml->GetEtcDir(), header);
      WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, header);
   }
   if (lenUserHeader != 0) {
      if (bothHeaders)
         userHeader.Remove(lenUserHeader - 1);
      WriteHtmlHeader(out, noSpecialCharTitle, dir, cls, userHeader);
   };
}
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char* ,
                                 const char* lastUpdate, const char* author,
                                 const char* copyright, const char* footer)
{
   static const char* templateSITags[TDocParser::kNumSourceInfos] = { "%UPDATE%", "%AUTHOR%", "%COPYRIGHT%"};
   TString datimeString;
   if (!lastUpdate) {
      TDatime date;
      datimeString = date.AsString();
      lastUpdate = datimeString.Data();
   }
   const char* siValues[TDocParser::kNumSourceInfos] = { lastUpdate, author, copyright };
   ifstream addFooterFile(footer);
   if (!addFooterFile.good()) {
      Warning("THtml::WriteHtmlFooter",
              "Can't open html footer file %s\n", footer);
      return;
   }
   TString line;
   while (!addFooterFile.eof()) {
      line.ReadLine(addFooterFile, kFALSE);
      if (addFooterFile.eof())
         break;
      if (!line)
         continue;
      for (Int_t siTag = 0; siTag < (Int_t) TDocParser::kNumSourceInfos; ++siTag) {
         Ssiz_t siPos = line.Index(templateSITags[siTag]);
         if (siPos != kNPOS)
            if (siValues[siTag] && siValues[siTag][0])
               line.Replace(siPos, strlen(templateSITags[siTag]), siValues[siTag]);
            else
               line = ""; 
      }
      out << line << std::endl;
   }
}
void TDocOutput::WriteHtmlFooter(std::ostream& out, const char *dir,
                            const char *lastUpdate, const char *author,
                            const char *copyright)
{
   out << endl;
   TString userFooter = GetHtml()->GetFooter();
   if (userFooter.Length() != 0) {
      TString footer(userFooter);
      if (footer.EndsWith("+"))
         footer.Remove(footer.Length() - 1);
      WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
   };
   if (userFooter.Length() == 0 || userFooter.EndsWith("+")) {
      TString footer("footer.html");
      gSystem->PrependPathName(fHtml->GetEtcDir(), footer);
      WriteHtmlFooter(out, dir, lastUpdate, author, copyright, footer);
   }
}
void TDocOutput::WriteModuleLinks(std::ostream& out)
{
   
   if (fHtml->GetListOfModules()->GetSize()) {
      out << "<div id=\"indxModules\"><h4>Modules</h4>" << endl;
      
      TIter iModule(fHtml->GetListOfModules());
      TModuleDocInfo* module = 0;
      while ((module = (TModuleDocInfo*) iModule()))
         if (module->IsSelected())
            out << "<a href=\"" << module->GetName() << "_Index.html\">" 
                      << module->GetName() << "</a>" << endl;
      out<< "</div><br />" << endl;
   }
}
void TDocOutput::WriteSearch(std::ostream& out)
{
   
   
   
   const TString& searchCmd = GetHtml()->GetSearchStemURL();
   if (searchCmd.Length()) {
      
      out << "<script type=\"text/javascript\">" << endl
         << "function onSearch() {" << endl
         << "var s='" << searchCmd <<"';" << endl
         << "window.location.href=s.replace(/%s/ig,escape(document.searchform.t.value));" << endl
         << "return false;}" << endl
         << "</script><form action=\"javascript:onSearch();\" id=\"searchform\" name=\"searchform\" onsubmit=\"return onSearch()\">" << endl
         << "<input name=\"t\" value=\"Search documentation...\"  onfocus=\"if (document.searchform.t.value=='Search documentation...') document.searchform.t.value='';\"></input>" << endl
         << "<button type=\"submit\">Search</button></form>" << endl;
      return;
   }
   const TString& searchEngine = GetHtml()->GetSearchEngine();
   if (searchEngine.Length())
      
      out << "<h2><a href=\"" << searchEngine
          << "\">Search the Class Reference Guide</a></h2>" << endl;
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.