//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2015 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
// 
#include "RProcesses.hpp"

#include <RInside.h>  // for the embedded R via RInside

#include "GraphUtils.hpp"


namespace mgx 
{
  static RInside *rPtr;
  using namespace Rcpp;

  QByteArray cleanSvg(QByteArray ba) 
  {
    // These substitutions get rid of the glyph errors, courtesy Michaele Lawrence
    QByteArray result;

    QTextStream in(&ba);
    QTextStream out(&result);

    QRegExp rx1("<symbol"); 
    QRegExp rx2("</symbol");    
    while (!in.atEnd()) {
      QString line = in.readLine();
      line.replace(rx1, "<g"); // so '<symbol' becomes '<g ...'
      line.replace(rx2, "</g");// and '</symbol becomes '</g'
      out << line << "\n";
    }
    out.flush();

    return result;
  } 

  RInside &startR()
  {
    if(!rPtr)
      rPtr = new RInside(0, 0);        // create embedded R inst.
    return *rPtr;
  }

  // Return the type of an Rcpp object
  QString typeR(RObject x)
  {
    if(is<NumericVector>(x)) {
      if(Rf_isMatrix(x)) 
        return "NumericMatrix";
      else 
        return "NumericVector";       
    } else if(is<IntegerVector>(x)) {
      if(Rf_isFactor(x))
        return "factor";
      else 
        return "IntegerVector";
    } else if(is<CharacterVector>(x))
      return "CharacterVector";
    else if(is<LogicalVector>(x))
      return "LogicalVector";
    else if(is<DataFrame>(x))
      return "DataFrame";
    else if(is<List>(x))
      return "List";
    else if(x.isS4())
      return "S4";
    else if(x.isNULL())
      return "NULL";

    return "unknown";
  } 

  // Do an R command
  //#define rCommand(cmd) R.parseEval(QString(cmd).toStdString()); //std::cout << "R command:" << (cmd) << std::endl;

  // Do an R command
  RInside::Proxy rCommand(const QString &cmd)
  {
    RInside &R = startR();

    std::cout << "R command:" << cmd.toStdString() << std::endl;
    return R.parseEval(cmd.toStdString());
  }

  bool writeVecR(const std::vector<double> &values, const QString &data)
  {
    RInside &R = startR();

    // Put data in data
    NumericVector x(values.size());
    for(uint i = 0; i < values.size(); i++)
      x[i] = values[i];

    // Write to R
    R[data.toStdString()] = x;

    return true;
  }

  // Get heat in a vector in same order as label set
  std::vector<double> heatVecLabels(Mesh &mesh, const IntSet &labels, std::map<int, double>& heat)
  {
    // Put in vector in same order as label set
    std::vector<double> result;
    forall(int label, labels){
      if(label < 1) continue;
      result.push_back(heat[label]);
    }

    return result;
  }

  // Plot a histogram of a heat map
  QByteArray histogramR(const QString &data, const QString &label)
  {
    //RInside &R = startR();


    rCommand("library(ggplot2);");
    rCommand(QString("histogramPlot = ggplot(NULL, aes(x=%1)) + geom_histogram() + labs(x='%2');").arg(data).arg(label));
    rCommand("ggsave(file='MGXtoR.svg', plot = histogramPlot);");

    QFile file("MGXtoR.svg");
    if(!file.open(QFile::ReadOnly)) {
      std::cout << "histogramR No data in svg file" << std::endl;
      return QByteArray();
    }
    return cleanSvg(file.readAll());
  }

  // Open window to plot SVG data
  bool plotDataR(const QByteArray &ba, const QString &title)
  {
    if(ba.size() == 0) {
      std::cout << "plotDataR No data in image" << std::endl;
      return false;
    }

    // Open the plot window
    auto *rWind = new RWindow(0);
    if(!rWind) {
      std::cout << "plotDataR Cannot create plot window" << std::endl;
      return false;
    }

    auto &svg = *rWind->ui.svg;
    svg.load(ba);
    rWind->setWindowTitle(title);
    rWind->show();
    return true;
  }

  Rcpp::NumericMatrix createMatrix(const int n) 
  {
    Rcpp::NumericMatrix M(n,n);
    for (int i=0; i<n; i++) {
        for (int j=0; j<n; j++) {
            M(i,j) = i*10 + j; 
        }
    }
    return(M);
}


  // Create a histogram of a heat map
  bool RHeatHist::initialize(QWidget* parent)
  {
    Mesh *mesh = currentMesh();
    if(!mesh)
      throw QString("%1::run No current mesh").arg(name());

    QString heat = parm("Heat Name");
    QString title = "R - Histogram of " + heat;
 
    auto labels = findAllSelectedLabels(mesh->graph());
    if(labels.empty()) labels = findAllLabelsSet(mesh->graph());

    std::map<int, double> heatMap;
    forall(auto p, mesh->labelHeat()){
      heatMap[p.first] = p.second;
    }

    auto heatVec = heatVecLabels(*mesh, labels, heatMap);

    writeVecR(heatVec, "x");
    return plotDataR(histogramR("x", heat), title);
  }
  REGISTER_PROCESS(RHeatHist);


  // Plot a scatter plot of two heat maps and show the correlation
  QByteArray correlationRPlot(const QString &xData, const QString &yData, 
                   const QString &xName, const QString &yName, const QString &method, QString fittedLine, QString parentColors = "")
  {
    RInside &R = startR();
    rCommand("library(ggplot2)");
    rCommand("library(grid)");

    // Find the correlations
    QString corrText;
    if(method != "none") {
      rCommand(QString("%1 = cor.test(%2, %3, method='%1')").arg(method).arg(xData).arg(yData));
      NumericVector correlation = rCommand(QString("%1$estimate").arg(method));
      std::cout << "Correlation:" << correlation[0] << std::endl;
      NumericVector pValue = rCommand(QString("%1$p.value").arg(method));
      std::cout << "P-value:" << pValue[0] << std::endl;
      corrText = QString(" + annotate('text', Inf, Inf, label='Correlation: %1, p-value: %2', hjust=1, vjust=1)").arg(correlation[0]).arg(pValue[0]);
    }
  
    // Make the scatterplot and save it to a file
    QString cmd = QString("scatterPlot = ggplot(NULL, aes(x=%1, y=%2)) + geom_point(size=.5) + labs(x='%3', y='%4')").arg(xData).arg(yData).arg(xName).arg(yName);
    if(parentColors != ""){
      cmd = QString("scatterPlot = ggplot(NULL, aes(x=%1, y=%2, col = factor(%5))) + geom_point(size=.5) + labs(x='%3', y='%4')").arg(xData).arg(yData).arg(xName).arg(yName).arg(parentColors);
    }

    //NumericVector pValue = rCommand(QString("%1$p.value").arg(method));
    if(fittedLine == "Linear"){
      cmd += QString(" + geom_smooth(method='lm')");
    } else if(fittedLine == "Loess"){
      cmd += QString(" + geom_smooth(method='loess')");
    } 
    if(method != "none")
      cmd += corrText;
    //if(drawLabels)
    //  cmd += QString(" + geom_text(aes(label=labels), size=1, vjust=1, hjust=.5)");
    rCommand(cmd);
    rCommand("ggsave(file='MGXtoR.svg', plot = scatterPlot)");

    // Open the file and return the contents
    QFile file("MGXtoR.svg");
    if(!file.open(QFile::ReadOnly)) {
      std::cout << "correlationR No data in image" << std::endl;
      return QByteArray();
    }
    return cleanSvg(file.readAll());
  }

  // Create a histogram of a heat map
  bool RCorrelation::initialize(QWidget* parent)
  {
    Mesh *mesh = currentMesh();
    if(!mesh)
      throw QString("%1::run No current mesh").arg(name());

    QString heat = "";//parm("Heat");
    QString title =  "";//QString("R - Historgram of %1").arg(heat);

    QString xHeat = parm("X Heat");
    QString yHeat = parm("Y Heat");
    QString method = parm("Method");
    bool drawLine = stringToBool(parm("Draw Line"));
 
    auto labels = findAllSelectedLabels(mesh->graph());
    if(labels.empty()) labels = findAllLabelsSet(mesh->graph());

    std::map<int, double> currentHeat, xHeatMap, yHeatMap;
    forall(auto p, mesh->labelHeat()){
      currentHeat[p.first] = p.second;
    }

    std::cout << "bla " << std::endl;

    if(xHeat == ""){
      xHeatMap = currentHeat;
    } else {
      AttrMap<int, double>& attrData = mesh->attributes().attrMap<int, double>("Measure Label Double " + xHeat);
      if(attrData.empty()) return setErrorMessage("Attr Map X doesn't exist!");

      forall(auto p, attrData){
        xHeatMap[p.first] = p.second;
      }
    }

    if(yHeat == ""){
      yHeatMap = currentHeat;
    } else {
      AttrMap<int, double>& attrData = mesh->attributes().attrMap<int, double>("Measure Label Double " + yHeat);
      if(attrData.empty()) return setErrorMessage("Attr Map Y doesn't exist!");

      forall(auto p, attrData){
        yHeatMap[p.first] = p.second;
      }
    }

    auto xHeatVec = heatVecLabels(*mesh, labels, xHeatMap);
    auto yHeatVec = heatVecLabels(*mesh, labels, yHeatMap);

    writeVecR(xHeatVec, "x");
    writeVecR(yHeatVec, "y");
    QString fittedLine = "None";
    if(drawLine) fittedLine = "Linear";
    return plotDataR(correlationRPlot("x", "y", xHeat, yHeat, method.toLower(), fittedLine), title);

  }

  REGISTER_PROCESS(RCorrelation);


  // Plot a box plot of two heat maps and show the test result
  QByteArray meanTestRPlot(const QString &xData, const QString &yData, const QString &xName, const QString &yName, const QString &test)
  {
//http://www.sthda.com/english/wiki/unpaired-two-samples-t-test-in-r
//
// should test for normality and variance
    rCommand("library(ggplot2)");
    rCommand("library(grid)");
    rCommand("library(grid)");

    if(test == "t-test")
      rCommand(QString("result = t.test(%1, %2, alternative='two.sided')").arg(xData).arg(yData));
    else if(test == "wilcox")
      rCommand(QString("result = wilcox.test(%1, %2, alternative='two.sided')").arg(xData).arg(yData));
    else
      throw QString("meanTRPlot: Test (%1) not yet implemented").arg(test);
    NumericVector pValue = rCommand("result$p.value");

    NumericVector xMean = rCommand(QString("mean(%1)").arg(xData));
    NumericVector yMean = rCommand(QString("mean(%1)").arg(yData));

    rCommand(QString("s1 = rep('Stack1', length(%1))").arg(xData));
    rCommand(QString("s2 = rep('Stack2', length(%1))").arg(yData));
    rCommand(QString("s = c(s1, s2)"));
    rCommand(QString("data = c(%1, %2)").arg(xData).arg(yData));

    QString cmd = QString("resultPlot = ggplot(NULL, aes(x=as.factor(s), y=data)) + geom_violin()");
    cmd += QString(" + labs(x='%1', y='%2')").arg("Stack").arg(xName);
    cmd += QString(" + stat_summary(fun.y=mean)");
    cmd += QString(" + geom_boxplot(width=0.1)");
    cmd += QString(" + annotate('text', Inf, Inf, label='Means: %1 - %2  p-value: %3', hjust=1, vjust=1)")
                                                         .arg(xMean[0]).arg(yMean[0]).arg(pValue[0]);
    rCommand(cmd);

    rCommand(QString("ggsave(file='MDXtoR.svg', plot = resultPlot)"));

    QFile file("MDXtoR.svg");
    if(!file.open(QFile::ReadOnly)) {
      std::cout << (QString("correlationR No data in image").arg(test)).toStdString() << std::endl;
      return QByteArray();
    }
    return cleanSvg(file.readAll());
  }


  // Create a scatterplot and show correlation of two heat maps
  bool RMeanTest::initialize(QWidget* parent)
  {
    Mesh *mesh1 = currentMesh();
    if(!mesh1)
      throw QString("%1::run No current mesh").arg(name());
   
    std::map<int, double> heatMap1;
    forall(auto p, mesh1->labelHeat()){
      heatMap1[p.first] = p.second;
    }

    Mesh *mesh2 = otherMesh();
    if(!mesh2)
      throw QString("%1::run No other mesh").arg(name());

    std::map<int, double> heatMap2;
    forall(auto p, mesh2->labelHeat()){
      heatMap2[p.first] = p.second;
    }

    QString heatName = "";

    QString test = parm("Test");
    if(test != "T-Test" and test != "Wilcox")
      throw QString("%1::run Test type must be T-Test or Wilcox").arg(name());

    QString title = QString("R - %1 for %2").arg(test).arg(heatName);

    auto labels1 = findAllSelectedLabels(mesh1->graph());
    if(labels1.empty()) labels1 = findAllLabelsSet(mesh1->graph());

    auto labels2 = findAllSelectedLabels(mesh2->graph());
    if(labels2.empty()) labels2 = findAllLabelsSet(mesh2->graph());

    auto heat1Vec = heatVecLabels(*mesh1, labels1, heatMap1);
    auto heat2Vec = heatVecLabels(*mesh2, labels2, heatMap2);

    writeVecR(heat1Vec, "x");
    writeVecR(heat2Vec, "y");
    return plotDataR(meanTestRPlot("x", "y", heatName, heatName, test.toLower()), title);
  }

  REGISTER_PROCESS(RMeanTest);

  void RAdvanced::updateRPlot()
  {

    Mesh *m = currentMesh();

    if(rWind->ui.radioHistogram->isChecked()){
      type = "Hist";
    } else {
      type = "Scatter";
    }

    std::set<int> labels;

    forall(auto p, heatMapX){
      if(selectedType == "All Cells" or (selectedType == "Selected Cells" and selectedLabels.find(p.first) != selectedLabels.end())
        or (selectedType == "Unselected Cells" and selectedLabels.find(p.first) == selectedLabels.end())){
        labels.insert(p.first);
      }
      
    }

    if(type == "Scatter"){
      std::set<int> labelsBoth;
      forall(auto p, heatMapY){
        if(labels.find(p.first) != labels.end())
          labelsBoth.insert(p.first);
      }
      labels = labelsBoth;
    } 

    std::vector<double> parentVec;
    QString parents = "parents";
    if(colorType != "None"){
      parentLabels.clear();
      forall(int p, labels){
        parentLabels[p] = m->parents()[p];
      }
      parentVec = heatVecLabels(*m, labels, parentLabels);
      writeVecR(parentVec, parents);
    }

    if(labels.empty()) return;

    auto heatVec = heatVecLabels(*m, labels, heatMapX);
    QString nameX = measureX.replace("/", "");
    nameX = nameX.replace(" ", "");

    writeVecR(heatVec, nameX);

    auto &svg = *rWind->ui.svg;

    QString title = type + " ";
    title+=nameX;

    QByteArray xData;

    if(type == "Scatter"){
      auto heatVecY = heatVecLabels(*m, labels, heatMapY);
      QString nameY = measureY.replace('/', "");
      nameY = nameY.replace(" ", "");
      writeVecR(heatVecY, nameY);
      if(colorType != "None"){
        xData = correlationRPlot(nameX, nameY, nameX, nameY, correlationType.toLower(), fittedLine, parents);
      } else {
        xData = correlationRPlot(nameX, nameY, nameX, nameY, correlationType.toLower(), fittedLine);
      }
      

      title+=" ";
      title+=nameY;
    } else{
      xData = histogramR(nameX, nameX);
    }

    if(xData.size() == 0) {
      std::cout << "plotDataR No data in image" << std::endl;
      return;
    }




    svg.load(xData);
    rWind->setWindowTitle(title);
    rWind->show();

  }

  void RAdvanced::setCorrelation(QString type)
  {
    correlationType = type;

    updateRPlot();
  }

  void RAdvanced::setFitted(QString type)
  {
    fittedLine = type;

    updateRPlot();
  }

  void RAdvanced::setSelected(QString type)
  {
    selectedType = type;

    updateRPlot();
  }

  void RAdvanced::setColor(QString type)
  {
    colorType = type;

    updateRPlot();
  }

  void RAdvanced::setMeasure()
  {
    Mesh *m = currentMesh();
    Mesh *m2 = otherMesh();


    QString measureXNew = rWind->ui.comboSelector1->currentText();
    QString measureYNew = rWind->ui.comboSelector2->currentText();

    qDebug() << measureXNew << "\n";

    AttrMap<int, double> attrX = m->attributes().attrMap<int, double>("Measure Label Double " + measureXNew);
    AttrMap<int, double> attrY = m->attributes().attrMap<int, double>("Measure Label Double " + measureYNew);

    heatMapX.clear();
    heatMapY.clear();

    measureX = measureXNew;
    measureY = measureYNew;

    forall(auto p, attrX){
      heatMapX[p.first] = p.second;
    }

    forall(auto p, attrY){
      heatMapY[p.first] = p.second;
    }

    std::cout << "sizes " << heatMapX.size() << "/" << heatMapY.size() << "//" << attrX.size() << "/" << attrY.size() << std::endl;

    updateRPlot();
  }

  // fill a QTreeWidget with all existing measures
  void getAttrMaps(Mesh* m, QStringList& attrList, QStringList& types)
  {
    attrList.clear();
    types.clear();

    Attributes *attributes;
    attributes = &m->attributes();
    QStringList attr = attributes->getAttrList();
    QStringList measureAttr;

    attr.sort(Qt::CaseSensitive);

    forall(const QString &text, attr) {
      QStringList list = text.split(" ");

      if(list.size() < 4) continue;
      if(list[0] != "Measure") continue;
      if(list[1] != "Label") continue;
      QString name;
      for(int i = 3; i<list.size(); i++){
        if(i!=3) name = name + " ";
        name = name + list[i];
      }
      types << list[2];
      attrList << name;
    }

  }

  // fill a QTreeWidget with all existing measures
  QStringList getAttrMapsOfType(Mesh* m, QString type)
  {
    QStringList attrList;

    Attributes *attributes;
    attributes = &m->attributes();
    QStringList attr = attributes->getAttrList();
    QStringList measureAttr;

    forall(const QString &text, attr) {
      QStringList list = text.split(" ");

      if(list.size() < 4) continue;
      if(list[0] != "Measure") continue;
      if(list[1] != "Label") continue;
      if(list[2] != type) continue;
      QString name;
      for(int i = 3; i<list.size(); i++){
        name = name + list[i];
        if(i < list.size()-1) name += " ";
      }
      attrList << name;
    }

    attrList.sort(Qt::CaseSensitive);

    return attrList;
  }

  // fill a QTreeWidget with all existing measures
  QStringList getAttrMapsOfType(QStringList attributes, QStringList types, QString type)
  {
    QStringList attrList;

    for(int i = 0; i < attributes.size(); i++){
      if(types[i] != type) continue;
      attrList << attributes[i];
    }

    return attrList;
  }

  // fill a QTreeWidget with all existing measures
  void getCommonAttrMaps(Mesh* m, Mesh* m2, QStringList& attrList, QStringList& types)
  {
    attrList.clear();
    types.clear();

    QStringList attrList1, attrList2, types1, types2;

    getAttrMaps(m, attrList1, types1);
    getAttrMaps(m2, attrList2, types2);

    // find indentical ones

    for(int i = 0; i < attrList1.size(); i++){
      QString map1 = attrList1[i];
      for(int j = 0; j < attrList2.size(); j++){
        QString map2 = attrList2[j];
        if(map1 != map2 or types1[i] != types2[j]) continue;

        attrList << map1;
        types << types1;
      }
    }

  }

  void RAdvanced::updateRTestPlot()
  {

    Mesh *m = currentMesh();
    Mesh *m2 = otherMesh();


    if(!rWind->ui.comboSelectorTestAttr->isEnabled()) return;

    comparisonType = rWind->ui.comboTest->currentText();

    // get labels
    std::set<int> labels1, labels2;

    forall(auto p, heatMapX){
      labels1.insert(p.first);
    }
    forall(auto p, heatMapY){
      labels2.insert(p.first);
    }

    std::cout << "d " << labels1.size() << "/" << heatMapX.size() << "/" << heatMapY.size() << std::endl;

    if(labels1.empty() or labels2.empty()) return;

    auto heatVec = heatVecLabels(*m, labels1, heatMapX);
    auto heatVecY = heatVecLabels(*m2, labels2, heatMapY);


    QString nameX = measureX.replace("/", "");
    nameX += " 1";
    nameX = nameX.replace(" ", "");

    QString nameY = measureY.replace('/', "");
    nameY += " 2";
    nameY = nameY.replace(" ", "");

    writeVecR(heatVec, nameX);
    writeVecR(heatVecY, nameY);

    QByteArray xData = meanTestRPlot(nameX, nameY, nameX, nameY, comparisonType.toLower());

    auto &svg = *rWind->ui.svg_2;

    QString title = " ";

    if(xData.size() == 0) {
      std::cout << "meanTestRPlot No data in image" << std::endl;
      return;
    }

    svg.load(xData);
    rWind->setWindowTitle(title);
    rWind->show();

  }

  void RAdvanced::setTestMeasure()
  {
    if(!rWind->ui.comboSelectorTestAttr->isEnabled()) return;

    QString measureComp = rWind->ui.comboSelectorTestAttr->currentText();

    Mesh *m = currentMesh();
    Mesh *m2 = otherMesh();

    AttrMap<int, double> attr1 = m->attributes().attrMap<int, double>("Measure Label Double " + measureComp);
    AttrMap<int, double> attr2 = m2->attributes().attrMap<int, double>("Measure Label Double " + measureComp);

    heatMapX.clear();
    heatMapY.clear();

    forall(auto p, attr1){
      heatMapX[p.first] = p.second;
    }

    forall(auto p, attr2){
      heatMapY[p.first] = p.second;
    }

    updateRTestPlot();
  }

  // Create a scatterplot and show correlation of two heat maps
  bool RAdvanced::initialize(QWidget* parent)
  {

    Mesh *m = currentMesh();
    if(!m)
      throw QString("%1::run No current mesh").arg(name());

    selectedLabels.clear();

    forall(vertex v, m->selectedVertices()){
      if(!v->selected) continue;
      selectedLabels.insert(v->label);
    }

    Mesh *m2 = otherMesh();

    // init GUI
    rWind = new RWindowAdvanced(0);
    if(!rWind) {
      std::cout << "plotDataR Cannot create plot window" << std::endl;
      return false;
    }

    rWind->show();
    
    // fill GUI with Attr Maps
    QStringList attrList = getAttrMapsOfType(m, "Double");

    if(attrList.empty()) return setErrorMessage("No Attribute Maps present. Generate some data first.");

    QStringList attrListCommon, typesCommon;
    getCommonAttrMaps(m, m2, attrListCommon, typesCommon);
    QStringList attrListCommonDouble = getAttrMapsOfType(attrListCommon, typesCommon, "Double");

    rWind->ui.comboSelector1->clear();
    rWind->ui.comboSelector2->clear();

    rWind->ui.comboSelector1->addItems(attrList);
    rWind->ui.comboSelector2->addItems(attrList);

    if(attrListCommonDouble.empty()){
      attrListCommonDouble << "No Attribute found!";
      rWind->ui.comboSelectorTestAttr->setEnabled(false);
      measureComparison = "";
    }
    rWind->ui.comboSelectorTestAttr->addItems(attrListCommonDouble);

    correlationType = "Pearson";
    fittedLine = "None";
    selectedType = "All Cells";
    colorType = "None";
    setMeasure();
    updateRPlot();

    setTestMeasure();
    updateRTestPlot();

    // read the GUI & load the attr map
    connect(rWind->ui.comboSelector1, SIGNAL(currentIndexChanged(QString)), this, SLOT(setMeasure()));
    connect(rWind->ui.comboSelector2, SIGNAL(currentIndexChanged(QString)), this, SLOT(setMeasure()));

    connect(rWind->ui.radioHistogram, SIGNAL(toggled(bool)), this, SLOT(updateRPlot()));
    connect(rWind->ui.radioScatter, SIGNAL(toggled(bool)), this, SLOT(updateRPlot()));

    connect(rWind->ui.comboFittedLine, SIGNAL(currentIndexChanged(QString)), this, SLOT(setFitted(QString)));
    connect(rWind->ui.comboCorrelation, SIGNAL(currentIndexChanged(QString)), this, SLOT(setCorrelation(QString)));
    connect(rWind->ui.comboSelection, SIGNAL(currentIndexChanged(QString)), this, SLOT(setSelected(QString)));
    connect(rWind->ui.comboParents, SIGNAL(currentIndexChanged(QString)), this, SLOT(setColor(QString)));

    connect(rWind->ui.comboSelectorTestAttr, SIGNAL(currentIndexChanged(QString)), this, SLOT(setTestMeasure()));

    connect(rWind->ui.comboTest, SIGNAL(currentIndexChanged(QString)), this, SLOT(updateRTestPlot()));

    return true;
  }
  REGISTER_PROCESS(RAdvanced);

  // Create a scatterplot and show correlation of two heat maps
  bool RStudio::initialize(QWidget* parent)
  {

    Mesh *mesh = currentMesh();
    if(!mesh)
      throw QString("%1::run No current mesh").arg(name());

    QString frameName = parm("Data Frame");

    if(frameName == "") frameName = "mgx";

    QStringList tensorStrings = QStringList() << "v1X" << "v1Y" << "v1Z" << "v2X" << "v2Y" << "v2Z" << "v3X" << "v3Y" << "v3Z"; 

    // Start R
    RInside &R = startR();

    QString frame(frameName + " = data.frame(");

    // go through all measure attr maps
    QStringList attrList, attrTypes;
    getAttrMaps(mesh, attrList, attrTypes);

    std::set<int> selLabelSet = findAllSelectedLabels(mesh->graph());
    if(selLabelSet.empty()) selLabelSet = findAllLabelsSet(mesh->graph());

    std::vector<int> selectedLabels;


    forall(int l, selLabelSet){
      if(l < 1) continue;
      selectedLabels.push_back(l);
    }

    std::vector<double> labelVec;

    for(int j = 0; j< selectedLabels.size(); j++){
      labelVec.push_back(selectedLabels[j]);
    }
    writeVecR(labelVec, "Labels");
    frame += "Labels,";
    std::cout << "s" << labelVec.size() << std::endl;

    for(int i = 0; i < attrList.size(); i++){
      qDebug() << "bla " << attrList[i] << "/" << attrTypes[i] << "\n";

      QString name = attrList[i];
      name.replace(' ', "");
      name.replace('/', "");

      if(attrTypes[i] == "Double"){
        AttrMap<int, double>& attrData = mesh->attributes().attrMap<int, double>("Measure Label Double " + attrList[i]);
        std::vector<double> heatVec;
        for(int j = 0; j< selectedLabels.size(); j++){
          heatVec.push_back(attrData[labelVec[j]]);
        }
        writeVecR(heatVec, name);
        frame += name + ",";
        std::cout << "s" << heatVec.size() << std::endl;
      }

      if(attrTypes[i] == "Vector"){
        AttrMap<int, Point3d>& attrData = mesh->attributes().attrMap<int, Point3d>("Measure Label Vector " + attrList[i]);
        std::vector<double> heatVecX, heatVecY, heatVecZ;
        for(int j = 0; j< selectedLabels.size(); j++){
          heatVecX.push_back(attrData[labelVec[j]].x());
          heatVecY.push_back(attrData[labelVec[j]].y());
          heatVecZ.push_back(attrData[labelVec[j]].z());
        }
        writeVecR(heatVecX, name+"X");
        frame += name + "X,";
        writeVecR(heatVecY, name+"Y");
        frame += name + "Y,";
        writeVecR(heatVecZ, name+"Z");
        frame += name + "Z,";
      }

      if(attrTypes[i] == "Tensor"){
        AttrMap<int, SymmetricTensor>& attrData = mesh->attributes().attrMap<int, SymmetricTensor>("Measure Label Tensor " + attrList[i]);
        std::vector<std::vector<double> > heatMat(9);
        for(int j = 0; j< selectedLabels.size(); j++){
          SymmetricTensor t = attrData[labelVec[j]];

          heatMat[0].push_back(t.ev1().x());
          heatMat[1].push_back(t.ev1().y());
          heatMat[2].push_back(t.ev1().z());

          heatMat[3].push_back(t.ev2().x());
          heatMat[4].push_back(t.ev2().y());
          heatMat[5].push_back(t.ev2().z());

          heatMat[6].push_back(t.evals().x());
          heatMat[7].push_back(t.evals().y());
          heatMat[8].push_back(t.evals().z());

        }
        for(int j = 0; j < 9; j++){
          writeVecR(heatMat[j], name + tensorStrings[j]);
          frame += name + tensorStrings[j] + ",";
        }
        
      }

    }

    int pos = frame.lastIndexOf(QChar(','));
    frame = frame.left(pos);
    frame += ")";
    rCommand(frame);
    rCommand("save(mgx, file='MGXtoR.data')");
    QFile file("MGXtoR.r");
    if(!file.open(QFile::WriteOnly))
      throw QString("%1::run Cannot open output file MGXtoR.r").arg(name());
    QTextStream out(&file);
    out << "load('MGXtoR.data')" << endl;
    file.close();
    system("rstudio MGXtoR.r &");

    return true;
  }
  REGISTER_PROCESS(RStudio);


}
