#include <memory>

#include "TCanvas.h"
#include "TH1.h"
#include "TLatex.h"
#include "TLegend.h"
#include "TLine.h"
#include "TROOT.h"
#include "TString.h"
#include "TGraphErrors.h"
#include "TStyle.h"
//#include "TSystem.h"

#include "QFramework/TQGridScanner.h"
#include "QFramework/TQGridScanResults.h"
#include "QFramework/TQGridScanObservable.h"
#include "QFramework/TQGridScanStyle.h"
#include "QFramework/TQHistogramUtils.h"
#include "QFramework/TQROOTPlotter.h"
#include "QFramework/TQTaggable.h"
#include "QFramework/TQUtils.h"
#include "QFramework/TQLibrary.h"
#include "QFramework/TQPathManager.h"

using std::unique_ptr;

using BoundDirection = TQGridScanBound::Direction;

double kValNotSet = TQGridScanPoint::kValNotSet;

ClassImp(TQGridScanResults)

void TQGridScanResults::sortPoints() {
  if(not m_sorted) {
    std::function<double (const TQGridScanPoint&, const TQGridScanPoint&)> sortFunction;
    if (points()->at(0).foms().empty()) {
      sortFunction = [](const TQGridScanPoint& a, const TQGridScanPoint& b) {
                       return a.significance() > b.significance();
                     };
    }
    else {
      sortFunction = [](const TQGridScanPoint& a, const TQGridScanPoint& b) {
                       return a.foms()[0] > b.foms()[0];
                     };
    }
    sort(
         m_points.begin(),
         m_points.end(),
         sortFunction
         );
  }
  m_sorted = true;
}

void TQGridScanResults::sortPoints(unsigned int fom_index_for_sorting) {
  // Sort points w.r.t. specific FOM (specified by index in fom vector)
  if (points()->at(0).foms().empty()) {
    DEBUGclass("There are not multiple figure of merits defined! Trying to sort w.r.t. the specified evaluator mode!");
    sortPoints();
    return;
  }
  if (fom_index_for_sorting >= points()->at(0).foms().size()) {
    WARNclass("Specified index '%i' is out of range in vector of figure of merits! Cannot sort points w.r.t. this, falling back to first specified figure of merit (with index 0)", fom_index_for_sorting);
    fom_index_for_sorting = 0;
  }
  auto sortFunction = [fom_index_for_sorting](const TQGridScanPoint& a, const TQGridScanPoint& b) {
                        return a.foms().at(fom_index_for_sorting) > b.foms().at(fom_index_for_sorting);
                      };
  sort(
       m_points.begin(),
       m_points.end(),
       sortFunction
       );
}

void TQGridScanResults::printPoints(size_t first, size_t last) {
  // print all points with indices ranging between first and last
  // will only print points that meet the requirements
  if(last >= m_points.size()) last = m_points.size();
  for(size_t i = first; i<last; i++) {
    auto& point = m_points[i];
    if(isAcceptedPoint(point)) printPoint(&point);
  }
}

void TQGridScanResults::printPoints(size_t last) {
  // print all points up to given index
  // will only print points that meet the requirements
  printPoints(0, last);
}

unique_ptr<TLine> TQGridScanResults::drawCutLine(TH1* hist) {
  // draw the vertical line denoting the current cut value
  TString vname = TString::Format("cut.%s",hist->GetName());
  if(!hasTag(vname)) vname.ReplaceAll(":","");
  // What's the point of this?
  //if(!hasTag(vname)) {
  //  size_t idx = findVariable(hist->GetName());
  //  if(idx > variables.size()) return nullptr;
  //  vname = TString::Format("cut.%s",variables[idx].Data());
  //}
  double cut = getTagDoubleDefault(vname,std::numeric_limits<double>::quiet_NaN());
  if(!TQUtils::isNum(cut))
    return nullptr;
  double xmax = TQHistogramUtils::getAxisXmax(hist);
  double xmin = TQHistogramUtils::getAxisXmin(hist);
  if(cut > xmax || cut < xmin) return nullptr;
  gPad->Modified();
  gPad->Update();
  double ymin = gPad->GetUymin();
  double ymax = gPad->GetUymax();
  auto cutline = unique_ptr<TLine>(new TLine(cut,ymin,cut,ymax));
  int cutlinecolor = getTagIntegerDefault("cutLine.color",kRed);
  int cutlinestyle = getTagIntegerDefault("cutLine.style",7);
  int cutlinewidth = getTagIntegerDefault("cutLine.width",2);
  cutline->SetLineStyle(cutlinestyle);
  cutline->SetLineWidth(cutlinewidth);
  cutline->SetLineColor(cutlinecolor);
  cutline->Draw();
  return cutline;
}

bool TQGridScanResults::isAcceptedPoint(const TQGridScanPoint& /*point*/) {
  // TODO: implement
  // VERBOSEclass("Accept the following grid scan point");
  // VERBOSEclass(point.info().Data());
  return true;
}

void TQGridScanResults::plotAndSaveAllSignificanceProfiles(double topFraction, const TString& options, TString outPath) {
  auto topNumber = static_cast<int>(ceil(topFraction * m_points.size()));
  plotAndSaveAllSignificanceProfiles(topNumber, options, outPath);
}

void TQGridScanResults::plotAndSaveAllSignificanceProfiles(int topNumber, const TString& options, TString outPath) {
  // obtain histogram-like plots
  // showing the significance as a function of each varname
  // optimized over all invisible dimesions to the average
  // of the best topNumber points
  // plot and save them under the given path with the given options

  gROOT->SetBatch(true);
  auto i = 0;
  for (const auto& obs: m_normalObs) {
    if (not obs->bounds()->lower()->isFixed()) {
      plotAndSaveSignificanceProfile(BoundDirection::lower, i, topNumber, options, outPath);
    }
    if (not obs->bounds()->upper()->isFixed()) {
      plotAndSaveSignificanceProfile(BoundDirection::upper, i, topNumber, options, outPath);
    }
    ++i;
  }
  for (unsigned int i=0; i < m_splitObs.size(); i++) {
    plotAndSaveSignificanceProfile(BoundDirection::split, i, topNumber, options, outPath);
  }
  gROOT->SetBatch(false);
}

void TQGridScanResults::plotAndSaveSignificanceProfile(BoundDirection direction, int i, int topNumber, const TString& options, TString outPath) {
  // obtain a histogram-like plot
  // showing the significance as a function of varname
  // optimized over all invisible dimesions to the average
  // of the best topNumber points
  // plot and save it under the given path with the given options
  TQTaggable tags(options);
  tags.importTags(this);
  bool showmax = tags.getTagBoolDefault("showmax",getTagBoolDefault("profile.showmax",true));
  TString extension = tags.getTagStringDefault("ext","pdf");
  auto hist = getSignificanceProfile(direction, i, topNumber);
  // This gets invalidated if hist gets reassigned, just FYI
  auto histptr = hist.get();
  if(!hist) return;
  auto c = TQGridScanStyle::defaultCanvas();
  c->cd();
  unique_ptr<TLine> cutline = nullptr;
  unique_ptr<TH1F> histmax = nullptr;
  unique_ptr<TGraphAsymmErrors> ga = nullptr;
  unique_ptr<TGraphAsymmErrors> ga_max = nullptr;
  hist->SetLineColor(tags.getTagIntegerDefault("style.profile.color",getTagIntegerDefault("color",kBlue+4)));
  TQHistogramUtils::edge(histptr, getTagDoubleDefault("profile.plotMinSignificance",0.));
  if(showmax && topNumber > 1) {
    histmax = getSignificanceProfile(direction, i, 1);
    TQGridScanStyle::setStyle(c.get(), histptr, tags);
    TQGridScanStyle::setStyleAndRangeSignifProfile(histptr, histmax.get(), tags);
    if (tags.getTagBoolDefault("profile.newArrowStyle", true)) {
      ga = makeGraphFromLowBinEdges(histptr, direction);
      ga_max = makeGraphFromLowBinEdges(histmax.get(), direction);
      TQGridScanStyle::setStyleSignifProfileGraphs(ga.get(), ga_max.get(), tags);
      ga_max->Draw("AP|>");
      ga->Draw("sameP|>");
      if (tags.getTagBoolDefault("profile.drawHistogram", false)) {
        histmax->Draw("histsame");
        ga_max->Draw("sameP|>");
        ga->Draw("sameP|>");
      }
    } else {
      hist->Draw("same");
      histmax->Draw("histsame");
    }
    cutline = drawCutLine(histmax.get());
  } else {
    TQGridScanStyle::setStyle(c.get(), histptr, tags);
    TQGridScanStyle::setStyleAndRangeSignifProfile(histptr, nullptr, tags);
    hist->Draw("");
    cutline = drawCutLine(histptr);
  }
  auto topFraction = static_cast<double>(topNumber) / m_points.size();
  if(topNumber > 1) {
    // Will anyone want to use top number rather than fraction?
    //drawLegend(histptr, histmax.get(), tags, TString::Format("top %d average",topNumber), cutline.get());
    TQGridScanStyle::drawLegend(histptr, histmax.get(), tags, TString::Format("top %0.1g%% average", topFraction*100), cutline.get(), ga.get(), ga_max.get());
  } else {
    // TODO: verify this gives correct behavior
    TQGridScanStyle::drawLegend(nullptr, histptr, tags, "", cutline.get(), ga.get(), ga_max.get());
  }
  gPad->Modified();
  gPad->Update();

  auto obsName = (direction == BoundDirection::split) ? m_splitObs[i]->name() : m_normalObs[i]->name();
  if (outPath.IsNull()) outPath = getTagStringDefault("plotDirectory", "plots/");
  TQUtils::ensureDirectoryForFile(TQPathManager::getPathManager()->getTargetPath(outPath));

  auto outFilename = TQFolder::concatPaths(outPath, "signifProfile");
  if (m_points.at(0).foms().size() > 1) {outFilename = outFilename + TString::Format("%i_", m_fom_index_for_plotting);}
  outFilename = outFilename + TQFolder::makeValidIdentifier(obsName);
  auto suffix = TQFolder::makeValidIdentifier(TString::Format("_topf_%0.1g",topFraction));
  outFilename = outFilename + suffix + "." + extension;
  c->SaveAs(
            TQPathManager::getPathManager()->getTargetPath(outFilename).c_str(),
      extension
  );
}

unique_ptr<TH1F> TQGridScanResults::getSignificanceProfile(BoundDirection direction, int i, int topNumber) {
  // obtain a histogram-like plot
  // showing the significance as a function of varname
  // optimized over all invisible dimesions to the average
  // of the best topNumber points
  sortPoints();

  auto hist = unique_ptr<TH1F>();
  TString obsName;
  TQGridScanBound::Range range;

  if (direction == BoundDirection::lower) {
    const auto obs = m_normalObs[i];
    hist = unique_ptr<TH1F>(dynamic_cast<TH1F*>(obs->hist().Clone()));
    obsName = obs->name();
    const TQGridScanBound* bound = obs->bounds()->lower();
    range = bound->range();
  } else if (direction == BoundDirection::upper) {
    const auto obs = m_normalObs[i];
    obsName = obs->name();
    hist = unique_ptr<TH1F>(dynamic_cast<TH1F*>(obs->hist().Clone()));
    const TQGridScanBound* bound = obs->bounds()->upper();
    range = bound->range();
  } else {
    const auto obs = m_splitObs[i];
    obsName = obs->name();
    hist = unique_ptr<TH1F>(dynamic_cast<TH1F*>(obs->hist().Clone()));
    const TQGridScanBound* bound = obs->bound();
    range = bound->range();
  }
  int lowerBin = range[0];
  int upperBin = range[1];

  hist->SetStats(kFALSE);
  hist->SetDirectory(nullptr);

  auto histFills = unique_ptr<TH1F>(dynamic_cast<TH1F*>(hist->Clone()));
  auto histSquares = unique_ptr<TH1F>(dynamic_cast<TH1F*>(hist->Clone()));
  auto histPtr = hist.get();
  auto histSquaresPtr = histSquares.get();
  auto histFillsPtr = histFills.get();

  bool showExtraBins = getTagBoolDefault("profile.showExtraBins",false);
  bool showUnderflow = showExtraBins && direction == BoundDirection::lower;
  bool showOverflow = showExtraBins && direction == BoundDirection::upper;

  auto axis = hist->GetXaxis();

  switch (direction) {
    case BoundDirection::lower:
      for(const auto& point: m_points) {
        if(!isAcceptedPoint(point)) continue;
        auto nBin = point.normalBounds()[i].first;
        auto fom = point.foms().at(m_fom_index_for_plotting);
        //if (not nBin) nBin = BinExtrema::min;
        TQGridScanStyle::fillHists(histPtr, histSquaresPtr, histFillsPtr, nBin, fom, topNumber, showUnderflow, showOverflow);
      }
      axis->SetRange(lowerBin, upperBin);
      break;
    case BoundDirection::upper:
      for(const auto& point: m_points) {
        if(!isAcceptedPoint(point)) continue;
        // Add 1 to account for the inclusive->exclusive upper bound conversion
        auto nBin = point.normalBounds()[i].second + 1;
        auto fom = point.foms().at(m_fom_index_for_plotting);
        //if (not nBin) nBin = BinExtrema::max;
        TQGridScanStyle::fillHists(histPtr, histSquaresPtr, histFillsPtr, nBin, fom, topNumber, showUnderflow, showOverflow);
      }
      hist->GetXaxis()->SetRange(lowerBin + 1, upperBin + 1);
      break;
    case BoundDirection::split:
      for(const auto& point: m_points) {
        if(!isAcceptedPoint(point)) continue;
        auto nBin = point.splitBounds()[i];
        auto fom = point.foms().at(m_fom_index_for_plotting);
        TQGridScanStyle::fillHists(histPtr, histSquaresPtr, histFillsPtr, nBin, fom, topNumber, showUnderflow, showOverflow);
      }
      hist->GetXaxis()->SetRange(lowerBin, upperBin);
      break;
  }
  TQGridScanStyle::excludeOverflow(axis);
  hist->Divide(histFillsPtr);
  histSquares->Divide(histFillsPtr);
  TQGridScanStyle::fillErrors(histPtr, histSquaresPtr, histFillsPtr);
  hist->SetEntries(topNumber);
  hist->SetMinimum(getTagDoubleDefault("profile.plotMinSignificance",4.));

  // Build and set title
  TString titleFigureOfMerit = getTagStringDefault("profile.titleFigureOfMerit", "Z_{exp}");
  TString plotTitle = getTagStringDefault("profile.title", hist->GetTitle());
  TString titleSuffix = TQGridScanStyle::getObsTitleSuffix(obsName, direction);
  TString fullTitle = ";";
  if(!plotTitle.IsNull()){
    plotTitle.ReplaceAll("$(VAR)", hist->GetTitle());
    if (plotTitle.First("[") > 0 || plotTitle.First("(") > 0) { // if unit is specified
      fullTitle += plotTitle.Insert(plotTitle.First("["), titleSuffix+" ")+";";
    } else {fullTitle += plotTitle+" "+titleSuffix+";";}
  } else {
    fullTitle += ";";
  }
  fullTitle += titleFigureOfMerit;
  hist->SetTitle(fullTitle);

  // Now that the hist is filled, we can rebin it; rebinning only happens if necessary
  // (i.e. stepSize > 1)
  hist = TQGridScanStyle::rebinHist(std::move(hist), range, direction);

  return hist;
}

std::unique_ptr<TGraphAsymmErrors> TQGridScanResults::makeGraphFromLowBinEdges(TH1* hist, BoundDirection direction) {
  // Convert histogram to TGraphAsymmErrors with low bin edges of histogram as points
  // and errors only in one direction, depending on the BoundDirection
  // Those errors are in the end displayed as arrows in the 'direction the cut is applied'
  double binwidth = hist->GetBinWidth(1);
  double lowlimit = hist->GetXaxis()->GetBinLowEdge(hist->GetXaxis()->GetFirst());
  double uplimit = hist->GetXaxis()->GetBinUpEdge(hist->GetXaxis()->GetLast());
  auto gr = unique_ptr<TGraphErrors>(new TGraphErrors(hist));
  std::vector<double> x, y, exlow, eylow, exhigh, eyhigh;
  for (int i=0; i <  gr->GetN(); i++) {
    double tmp_x, tmp_y;
    gr->GetPoint(i, tmp_x, tmp_y);
    // only regard points in range
    if ((tmp_x < lowlimit) || (tmp_x > uplimit)) continue;
    double tmp_ex = gr->GetErrorX(i);
    // double tmp_ey = gr->GetErrorY(i); // XXX BW: hashed to fix compiler warning (unused variable)
    // shift x by half binwidth
    tmp_x = tmp_x - binwidth/2.;
    x.push_back(tmp_x);
    y.push_back(tmp_y);
    if (direction == BoundDirection::lower) {
      exlow.push_back(0);
      exhigh.push_back(tmp_ex);
    } else if (direction == BoundDirection::upper) {
      exlow.push_back(tmp_ex);
      exhigh.push_back(0);
    } else { // split cut, no arrow -> no error
      exlow.push_back(0);
      exhigh.push_back(0);
    }
    eylow.push_back(0);
    eyhigh.push_back(0);
  }

  auto ga = unique_ptr<TGraphAsymmErrors>(new TGraphAsymmErrors(x.size(), x.data(), y.data(), exlow.data(), exhigh.data(), eylow.data(), eyhigh.data()));
  ga->GetXaxis()->SetRangeUser(lowlimit, uplimit);
  if (direction == BoundDirection::upper) {
    ga->GetXaxis()->SetRangeUser(lowlimit-binwidth, uplimit);
  }
  ga->SetMinimum(hist->GetMinimum());
  ga->SetMaximum(hist->GetMaximum());
  ga->GetXaxis()->SetTitle(hist->GetXaxis()->GetTitle());
  ga->GetYaxis()->SetTitle(hist->GetYaxis()->GetTitle());
  return ga;
}

void TQGridScanResults::setFOMIndexForPlotting(int fom_index_for_plotting) {

  if (unsigned(fom_index_for_plotting) >= points()->at(0).foms().size()) {
    WARNclass("Index for figure of merit to plot is specified to %d, which is out of range! Falling back to using the first specified figure of merit (index 0)", fom_index_for_plotting);
    m_fom_index_for_plotting = 0;
    return;
  }
  m_fom_index_for_plotting = fom_index_for_plotting;
}

void TQGridScanResults::plotInputDistributions(TQTaggable& tags, const TString& channelName) {
  DEBUGclass("This function will plot the input distributions for the first defined region only!");
  gROOT->SetBatch(true);
  TStyle *style = TQHistogramUtils::ATLASstyle();
  style->SetName("ATLAS");
  gROOT->SetStyle("ATLAS");
  gROOT->ForceStyle();

  for (unsigned ireg = 0; ireg < m_inputHistsSig.size(); ireg++) {
    TString regionName = m_inputHistsSig[ireg].regionName;

    for (unsigned ihist = 0; ihist < m_inputHistsSig[ireg].hists.size(); ihist++) {

      TH1F* hist_sig = &m_inputHistsSig[ireg].hists[ihist];
      TH1F* hist_bkg = &m_inputHistsBkg[ireg].hists[ihist];
      TString obsName = TQFolder::makeValidIdentifier(hist_sig->GetName());

      // Create canvas and set some style options
      auto c = TQGridScanStyle::defaultCanvas();
      c->cd();
      TQGridScanStyle::setStyle(c.get(), hist_sig, tags);
      TQGridScanStyle::setStyleInputHists(hist_sig, hist_bkg, tags);

      // Add generic legend
      unique_ptr<TLegend> leg (new TLegend(0.65, 0.75, 0.9, 0.9));
      leg->AddEntry(hist_sig, "Signal", "F");
      leg->AddEntry(hist_bkg, "Total Bkg", "F");

      // Draw not normalized histogram
      hist_bkg->GetYaxis()->SetTitle("Events");
      hist_bkg->Draw("hist");
      hist_sig->Draw("histsame");
      leg->Draw("same");

      // Save
      TString baseFilePath = tags.getTagStringDefault("plotDirectory", "plots/");
      baseFilePath = TQFolder::concatPaths(baseFilePath, "input-observables");
      TString extension = tags.getTagStringDefault("plotFormat","pdf");
      TQUtils::ensureDirectory(TQPathManager::getPathManager()->getTargetPath(baseFilePath));
      TString plotname;
      if (!channelName.IsNull()) {
          plotname = "inputDistribution-"+channelName+"-"+regionName+"-"+obsName;
        } else {
          plotname = "inputDistribution-"+regionName+"-"+obsName;
        }
      TString outputname =  TQFolder::concatPaths(baseFilePath, plotname);
      c->SaveAs( TQPathManager::getPathManager()->getTargetPath(outputname+"."+extension).c_str() );

      // Save normalized histogram
      c->Clear();
      hist_sig->Scale(1./hist_sig->GetSumOfWeights());
      hist_bkg->Scale(1./hist_bkg->GetSumOfWeights());
      double ymax1 = TQHistogramUtils::getHistogramMaximum(2, hist_sig, hist_bkg);
      hist_sig->GetYaxis()->SetRangeUser(0, ymax1*3/2.);
      hist_sig->GetYaxis()->SetTitle("Normalized Events");
      hist_sig->Draw("hist");
      hist_bkg->Draw("histsame");
      leg->Draw("same");
      c->SaveAs( TQPathManager::getPathManager()->getTargetPath(outputname+"_norm."+extension).c_str() );
    }
  }
  gROOT->SetBatch(false);
  gROOT->SetStyle("Default");
  gROOT->ForceStyle();
}

void TQGridScanResults::printPoint(TQGridScanPoint* point) {

  auto normalBinEdges = point->normalVals(m_normalObs);
  auto normalBinBounds = point->normalBounds();
  auto splitBinEdges = point->splitVals(m_splitObs);

  auto nNormalObs = normalBinEdges.size();
  for(size_t i = 0; i < nNormalObs; ++i) {
    auto vals = normalBinEdges[i];
    auto lowerVal = vals.first;
    auto upperVal = vals.second;
    auto binbounds = normalBinBounds[i];
    auto lowerBin = binbounds.first;
    auto upperBin = binbounds.second;
    auto obs = m_normalObs[i];
    auto obsName = obs->name();
    if (lowerVal == kValNotSet and upperVal == kValNotSet) {
      std::cout << obsName << " (no cut)";
    }
    else {
      if (lowerVal != kValNotSet) std::cout << lowerVal;
      if (lowerBin == TQGridScanBound::BinExtrema::min) std::cout << " (underflow bin)";
      std::cout << " < ";
      std::cout << obsName;
      if (upperVal != kValNotSet) std::cout << " < " << upperVal;
      if (upperBin == TQGridScanBound::BinExtrema::max) std::cout << " (overflow bin)";
    }
    TQGridScanStyle::printDelimiter(i, nNormalObs);
  }
  auto nSplitObs = splitBinEdges.size();
  for(size_t i = 0; i < nSplitObs; ++i) {
    auto val = splitBinEdges[i];
    auto obsName = m_splitObs[i]->name();
    std::cout << obsName << " | " << val;
    TQGridScanStyle::printDelimiter(i, nSplitObs);
  }
  std::cout << point->info() << std::endl;
}
 TQGridScanResults.cxx:1
 TQGridScanResults.cxx:2
 TQGridScanResults.cxx:3
 TQGridScanResults.cxx:4
 TQGridScanResults.cxx:5
 TQGridScanResults.cxx:6
 TQGridScanResults.cxx:7
 TQGridScanResults.cxx:8
 TQGridScanResults.cxx:9
 TQGridScanResults.cxx:10
 TQGridScanResults.cxx:11
 TQGridScanResults.cxx:12
 TQGridScanResults.cxx:13
 TQGridScanResults.cxx:14
 TQGridScanResults.cxx:15
 TQGridScanResults.cxx:16
 TQGridScanResults.cxx:17
 TQGridScanResults.cxx:18
 TQGridScanResults.cxx:19
 TQGridScanResults.cxx:20
 TQGridScanResults.cxx:21
 TQGridScanResults.cxx:22
 TQGridScanResults.cxx:23
 TQGridScanResults.cxx:24
 TQGridScanResults.cxx:25
 TQGridScanResults.cxx:26
 TQGridScanResults.cxx:27
 TQGridScanResults.cxx:28
 TQGridScanResults.cxx:29
 TQGridScanResults.cxx:30
 TQGridScanResults.cxx:31
 TQGridScanResults.cxx:32
 TQGridScanResults.cxx:33
 TQGridScanResults.cxx:34
 TQGridScanResults.cxx:35
 TQGridScanResults.cxx:36
 TQGridScanResults.cxx:37
 TQGridScanResults.cxx:38
 TQGridScanResults.cxx:39
 TQGridScanResults.cxx:40
 TQGridScanResults.cxx:41
 TQGridScanResults.cxx:42
 TQGridScanResults.cxx:43
 TQGridScanResults.cxx:44
 TQGridScanResults.cxx:45
 TQGridScanResults.cxx:46
 TQGridScanResults.cxx:47
 TQGridScanResults.cxx:48
 TQGridScanResults.cxx:49
 TQGridScanResults.cxx:50
 TQGridScanResults.cxx:51
 TQGridScanResults.cxx:52
 TQGridScanResults.cxx:53
 TQGridScanResults.cxx:54
 TQGridScanResults.cxx:55
 TQGridScanResults.cxx:56
 TQGridScanResults.cxx:57
 TQGridScanResults.cxx:58
 TQGridScanResults.cxx:59
 TQGridScanResults.cxx:60
 TQGridScanResults.cxx:61
 TQGridScanResults.cxx:62
 TQGridScanResults.cxx:63
 TQGridScanResults.cxx:64
 TQGridScanResults.cxx:65
 TQGridScanResults.cxx:66
 TQGridScanResults.cxx:67
 TQGridScanResults.cxx:68
 TQGridScanResults.cxx:69
 TQGridScanResults.cxx:70
 TQGridScanResults.cxx:71
 TQGridScanResults.cxx:72
 TQGridScanResults.cxx:73
 TQGridScanResults.cxx:74
 TQGridScanResults.cxx:75
 TQGridScanResults.cxx:76
 TQGridScanResults.cxx:77
 TQGridScanResults.cxx:78
 TQGridScanResults.cxx:79
 TQGridScanResults.cxx:80
 TQGridScanResults.cxx:81
 TQGridScanResults.cxx:82
 TQGridScanResults.cxx:83
 TQGridScanResults.cxx:84
 TQGridScanResults.cxx:85
 TQGridScanResults.cxx:86
 TQGridScanResults.cxx:87
 TQGridScanResults.cxx:88
 TQGridScanResults.cxx:89
 TQGridScanResults.cxx:90
 TQGridScanResults.cxx:91
 TQGridScanResults.cxx:92
 TQGridScanResults.cxx:93
 TQGridScanResults.cxx:94
 TQGridScanResults.cxx:95
 TQGridScanResults.cxx:96
 TQGridScanResults.cxx:97
 TQGridScanResults.cxx:98
 TQGridScanResults.cxx:99
 TQGridScanResults.cxx:100
 TQGridScanResults.cxx:101
 TQGridScanResults.cxx:102
 TQGridScanResults.cxx:103
 TQGridScanResults.cxx:104
 TQGridScanResults.cxx:105
 TQGridScanResults.cxx:106
 TQGridScanResults.cxx:107
 TQGridScanResults.cxx:108
 TQGridScanResults.cxx:109
 TQGridScanResults.cxx:110
 TQGridScanResults.cxx:111
 TQGridScanResults.cxx:112
 TQGridScanResults.cxx:113
 TQGridScanResults.cxx:114
 TQGridScanResults.cxx:115
 TQGridScanResults.cxx:116
 TQGridScanResults.cxx:117
 TQGridScanResults.cxx:118
 TQGridScanResults.cxx:119
 TQGridScanResults.cxx:120
 TQGridScanResults.cxx:121
 TQGridScanResults.cxx:122
 TQGridScanResults.cxx:123
 TQGridScanResults.cxx:124
 TQGridScanResults.cxx:125
 TQGridScanResults.cxx:126
 TQGridScanResults.cxx:127
 TQGridScanResults.cxx:128
 TQGridScanResults.cxx:129
 TQGridScanResults.cxx:130
 TQGridScanResults.cxx:131
 TQGridScanResults.cxx:132
 TQGridScanResults.cxx:133
 TQGridScanResults.cxx:134
 TQGridScanResults.cxx:135
 TQGridScanResults.cxx:136
 TQGridScanResults.cxx:137
 TQGridScanResults.cxx:138
 TQGridScanResults.cxx:139
 TQGridScanResults.cxx:140
 TQGridScanResults.cxx:141
 TQGridScanResults.cxx:142
 TQGridScanResults.cxx:143
 TQGridScanResults.cxx:144
 TQGridScanResults.cxx:145
 TQGridScanResults.cxx:146
 TQGridScanResults.cxx:147
 TQGridScanResults.cxx:148
 TQGridScanResults.cxx:149
 TQGridScanResults.cxx:150
 TQGridScanResults.cxx:151
 TQGridScanResults.cxx:152
 TQGridScanResults.cxx:153
 TQGridScanResults.cxx:154
 TQGridScanResults.cxx:155
 TQGridScanResults.cxx:156
 TQGridScanResults.cxx:157
 TQGridScanResults.cxx:158
 TQGridScanResults.cxx:159
 TQGridScanResults.cxx:160
 TQGridScanResults.cxx:161
 TQGridScanResults.cxx:162
 TQGridScanResults.cxx:163
 TQGridScanResults.cxx:164
 TQGridScanResults.cxx:165
 TQGridScanResults.cxx:166
 TQGridScanResults.cxx:167
 TQGridScanResults.cxx:168
 TQGridScanResults.cxx:169
 TQGridScanResults.cxx:170
 TQGridScanResults.cxx:171
 TQGridScanResults.cxx:172
 TQGridScanResults.cxx:173
 TQGridScanResults.cxx:174
 TQGridScanResults.cxx:175
 TQGridScanResults.cxx:176
 TQGridScanResults.cxx:177
 TQGridScanResults.cxx:178
 TQGridScanResults.cxx:179
 TQGridScanResults.cxx:180
 TQGridScanResults.cxx:181
 TQGridScanResults.cxx:182
 TQGridScanResults.cxx:183
 TQGridScanResults.cxx:184
 TQGridScanResults.cxx:185
 TQGridScanResults.cxx:186
 TQGridScanResults.cxx:187
 TQGridScanResults.cxx:188
 TQGridScanResults.cxx:189
 TQGridScanResults.cxx:190
 TQGridScanResults.cxx:191
 TQGridScanResults.cxx:192
 TQGridScanResults.cxx:193
 TQGridScanResults.cxx:194
 TQGridScanResults.cxx:195
 TQGridScanResults.cxx:196
 TQGridScanResults.cxx:197
 TQGridScanResults.cxx:198
 TQGridScanResults.cxx:199
 TQGridScanResults.cxx:200
 TQGridScanResults.cxx:201
 TQGridScanResults.cxx:202
 TQGridScanResults.cxx:203
 TQGridScanResults.cxx:204
 TQGridScanResults.cxx:205
 TQGridScanResults.cxx:206
 TQGridScanResults.cxx:207
 TQGridScanResults.cxx:208
 TQGridScanResults.cxx:209
 TQGridScanResults.cxx:210
 TQGridScanResults.cxx:211
 TQGridScanResults.cxx:212
 TQGridScanResults.cxx:213
 TQGridScanResults.cxx:214
 TQGridScanResults.cxx:215
 TQGridScanResults.cxx:216
 TQGridScanResults.cxx:217
 TQGridScanResults.cxx:218
 TQGridScanResults.cxx:219
 TQGridScanResults.cxx:220
 TQGridScanResults.cxx:221
 TQGridScanResults.cxx:222
 TQGridScanResults.cxx:223
 TQGridScanResults.cxx:224
 TQGridScanResults.cxx:225
 TQGridScanResults.cxx:226
 TQGridScanResults.cxx:227
 TQGridScanResults.cxx:228
 TQGridScanResults.cxx:229
 TQGridScanResults.cxx:230
 TQGridScanResults.cxx:231
 TQGridScanResults.cxx:232
 TQGridScanResults.cxx:233
 TQGridScanResults.cxx:234
 TQGridScanResults.cxx:235
 TQGridScanResults.cxx:236
 TQGridScanResults.cxx:237
 TQGridScanResults.cxx:238
 TQGridScanResults.cxx:239
 TQGridScanResults.cxx:240
 TQGridScanResults.cxx:241
 TQGridScanResults.cxx:242
 TQGridScanResults.cxx:243
 TQGridScanResults.cxx:244
 TQGridScanResults.cxx:245
 TQGridScanResults.cxx:246
 TQGridScanResults.cxx:247
 TQGridScanResults.cxx:248
 TQGridScanResults.cxx:249
 TQGridScanResults.cxx:250
 TQGridScanResults.cxx:251
 TQGridScanResults.cxx:252
 TQGridScanResults.cxx:253
 TQGridScanResults.cxx:254
 TQGridScanResults.cxx:255
 TQGridScanResults.cxx:256
 TQGridScanResults.cxx:257
 TQGridScanResults.cxx:258
 TQGridScanResults.cxx:259
 TQGridScanResults.cxx:260
 TQGridScanResults.cxx:261
 TQGridScanResults.cxx:262
 TQGridScanResults.cxx:263
 TQGridScanResults.cxx:264
 TQGridScanResults.cxx:265
 TQGridScanResults.cxx:266
 TQGridScanResults.cxx:267
 TQGridScanResults.cxx:268
 TQGridScanResults.cxx:269
 TQGridScanResults.cxx:270
 TQGridScanResults.cxx:271
 TQGridScanResults.cxx:272
 TQGridScanResults.cxx:273
 TQGridScanResults.cxx:274
 TQGridScanResults.cxx:275
 TQGridScanResults.cxx:276
 TQGridScanResults.cxx:277
 TQGridScanResults.cxx:278
 TQGridScanResults.cxx:279
 TQGridScanResults.cxx:280
 TQGridScanResults.cxx:281
 TQGridScanResults.cxx:282
 TQGridScanResults.cxx:283
 TQGridScanResults.cxx:284
 TQGridScanResults.cxx:285
 TQGridScanResults.cxx:286
 TQGridScanResults.cxx:287
 TQGridScanResults.cxx:288
 TQGridScanResults.cxx:289
 TQGridScanResults.cxx:290
 TQGridScanResults.cxx:291
 TQGridScanResults.cxx:292
 TQGridScanResults.cxx:293
 TQGridScanResults.cxx:294
 TQGridScanResults.cxx:295
 TQGridScanResults.cxx:296
 TQGridScanResults.cxx:297
 TQGridScanResults.cxx:298
 TQGridScanResults.cxx:299
 TQGridScanResults.cxx:300
 TQGridScanResults.cxx:301
 TQGridScanResults.cxx:302
 TQGridScanResults.cxx:303
 TQGridScanResults.cxx:304
 TQGridScanResults.cxx:305
 TQGridScanResults.cxx:306
 TQGridScanResults.cxx:307
 TQGridScanResults.cxx:308
 TQGridScanResults.cxx:309
 TQGridScanResults.cxx:310
 TQGridScanResults.cxx:311
 TQGridScanResults.cxx:312
 TQGridScanResults.cxx:313
 TQGridScanResults.cxx:314
 TQGridScanResults.cxx:315
 TQGridScanResults.cxx:316
 TQGridScanResults.cxx:317
 TQGridScanResults.cxx:318
 TQGridScanResults.cxx:319
 TQGridScanResults.cxx:320
 TQGridScanResults.cxx:321
 TQGridScanResults.cxx:322
 TQGridScanResults.cxx:323
 TQGridScanResults.cxx:324
 TQGridScanResults.cxx:325
 TQGridScanResults.cxx:326
 TQGridScanResults.cxx:327
 TQGridScanResults.cxx:328
 TQGridScanResults.cxx:329
 TQGridScanResults.cxx:330
 TQGridScanResults.cxx:331
 TQGridScanResults.cxx:332
 TQGridScanResults.cxx:333
 TQGridScanResults.cxx:334
 TQGridScanResults.cxx:335
 TQGridScanResults.cxx:336
 TQGridScanResults.cxx:337
 TQGridScanResults.cxx:338
 TQGridScanResults.cxx:339
 TQGridScanResults.cxx:340
 TQGridScanResults.cxx:341
 TQGridScanResults.cxx:342
 TQGridScanResults.cxx:343
 TQGridScanResults.cxx:344
 TQGridScanResults.cxx:345
 TQGridScanResults.cxx:346
 TQGridScanResults.cxx:347
 TQGridScanResults.cxx:348
 TQGridScanResults.cxx:349
 TQGridScanResults.cxx:350
 TQGridScanResults.cxx:351
 TQGridScanResults.cxx:352
 TQGridScanResults.cxx:353
 TQGridScanResults.cxx:354
 TQGridScanResults.cxx:355
 TQGridScanResults.cxx:356
 TQGridScanResults.cxx:357
 TQGridScanResults.cxx:358
 TQGridScanResults.cxx:359
 TQGridScanResults.cxx:360
 TQGridScanResults.cxx:361
 TQGridScanResults.cxx:362
 TQGridScanResults.cxx:363
 TQGridScanResults.cxx:364
 TQGridScanResults.cxx:365
 TQGridScanResults.cxx:366
 TQGridScanResults.cxx:367
 TQGridScanResults.cxx:368
 TQGridScanResults.cxx:369
 TQGridScanResults.cxx:370
 TQGridScanResults.cxx:371
 TQGridScanResults.cxx:372
 TQGridScanResults.cxx:373
 TQGridScanResults.cxx:374
 TQGridScanResults.cxx:375
 TQGridScanResults.cxx:376
 TQGridScanResults.cxx:377
 TQGridScanResults.cxx:378
 TQGridScanResults.cxx:379
 TQGridScanResults.cxx:380
 TQGridScanResults.cxx:381
 TQGridScanResults.cxx:382
 TQGridScanResults.cxx:383
 TQGridScanResults.cxx:384
 TQGridScanResults.cxx:385
 TQGridScanResults.cxx:386
 TQGridScanResults.cxx:387
 TQGridScanResults.cxx:388
 TQGridScanResults.cxx:389
 TQGridScanResults.cxx:390
 TQGridScanResults.cxx:391
 TQGridScanResults.cxx:392
 TQGridScanResults.cxx:393
 TQGridScanResults.cxx:394
 TQGridScanResults.cxx:395
 TQGridScanResults.cxx:396
 TQGridScanResults.cxx:397
 TQGridScanResults.cxx:398
 TQGridScanResults.cxx:399
 TQGridScanResults.cxx:400
 TQGridScanResults.cxx:401
 TQGridScanResults.cxx:402
 TQGridScanResults.cxx:403
 TQGridScanResults.cxx:404
 TQGridScanResults.cxx:405
 TQGridScanResults.cxx:406
 TQGridScanResults.cxx:407
 TQGridScanResults.cxx:408
 TQGridScanResults.cxx:409
 TQGridScanResults.cxx:410
 TQGridScanResults.cxx:411
 TQGridScanResults.cxx:412
 TQGridScanResults.cxx:413
 TQGridScanResults.cxx:414
 TQGridScanResults.cxx:415
 TQGridScanResults.cxx:416
 TQGridScanResults.cxx:417
 TQGridScanResults.cxx:418
 TQGridScanResults.cxx:419
 TQGridScanResults.cxx:420
 TQGridScanResults.cxx:421
 TQGridScanResults.cxx:422
 TQGridScanResults.cxx:423
 TQGridScanResults.cxx:424
 TQGridScanResults.cxx:425
 TQGridScanResults.cxx:426
 TQGridScanResults.cxx:427
 TQGridScanResults.cxx:428
 TQGridScanResults.cxx:429
 TQGridScanResults.cxx:430
 TQGridScanResults.cxx:431
 TQGridScanResults.cxx:432
 TQGridScanResults.cxx:433
 TQGridScanResults.cxx:434
 TQGridScanResults.cxx:435
 TQGridScanResults.cxx:436
 TQGridScanResults.cxx:437
 TQGridScanResults.cxx:438
 TQGridScanResults.cxx:439
 TQGridScanResults.cxx:440
 TQGridScanResults.cxx:441
 TQGridScanResults.cxx:442
 TQGridScanResults.cxx:443
 TQGridScanResults.cxx:444
 TQGridScanResults.cxx:445
 TQGridScanResults.cxx:446
 TQGridScanResults.cxx:447
 TQGridScanResults.cxx:448
 TQGridScanResults.cxx:449
 TQGridScanResults.cxx:450
 TQGridScanResults.cxx:451
 TQGridScanResults.cxx:452
 TQGridScanResults.cxx:453
 TQGridScanResults.cxx:454
 TQGridScanResults.cxx:455
 TQGridScanResults.cxx:456
 TQGridScanResults.cxx:457
 TQGridScanResults.cxx:458
 TQGridScanResults.cxx:459
 TQGridScanResults.cxx:460
 TQGridScanResults.cxx:461
 TQGridScanResults.cxx:462
 TQGridScanResults.cxx:463
 TQGridScanResults.cxx:464
 TQGridScanResults.cxx:465
 TQGridScanResults.cxx:466
 TQGridScanResults.cxx:467
 TQGridScanResults.cxx:468
 TQGridScanResults.cxx:469
 TQGridScanResults.cxx:470
 TQGridScanResults.cxx:471
 TQGridScanResults.cxx:472
 TQGridScanResults.cxx:473
 TQGridScanResults.cxx:474
 TQGridScanResults.cxx:475
 TQGridScanResults.cxx:476
 TQGridScanResults.cxx:477
 TQGridScanResults.cxx:478
 TQGridScanResults.cxx:479
 TQGridScanResults.cxx:480
 TQGridScanResults.cxx:481
 TQGridScanResults.cxx:482
 TQGridScanResults.cxx:483
 TQGridScanResults.cxx:484
 TQGridScanResults.cxx:485
 TQGridScanResults.cxx:486
 TQGridScanResults.cxx:487
 TQGridScanResults.cxx:488
 TQGridScanResults.cxx:489
 TQGridScanResults.cxx:490
 TQGridScanResults.cxx:491
 TQGridScanResults.cxx:492
 TQGridScanResults.cxx:493
 TQGridScanResults.cxx:494
 TQGridScanResults.cxx:495
 TQGridScanResults.cxx:496
 TQGridScanResults.cxx:497
 TQGridScanResults.cxx:498
 TQGridScanResults.cxx:499
 TQGridScanResults.cxx:500
 TQGridScanResults.cxx:501
 TQGridScanResults.cxx:502
 TQGridScanResults.cxx:503