ABasu_lattice/Data.pde
class Data{
  
  // The main data structure
  int noOfTexts;
  int noOfLATs;
  String[] textLabels;
  String[] LATLabels;
  double[][] LATGrid;
  double[][] distanceGrid = null;
  double maxDistance = 0;
  double minDistance = 2147483647;    // The maximum possible int

  double[][] boxPlotMetrics;
  double maxValue;

  /*************************************************************************
   Class constructor: Loads the basic .csv file and parses it into the label and LAT arrays
  *************************************************************************/
  Data(){
    loadData();
    buildDistanceGrid();
    buildBoxPlotData();
  }
  
  /*************************************************************************
   Builds the distance grid based on the euclidian distance between texts
  **************************************************************************/
  void buildDistanceGrid(){
    distanceGrid = new double[noOfTexts][noOfTexts];
    int r, c;
    
    for(r = 0; r < noOfTexts; r++){
      for(c = 0; c < noOfTexts; c++){
        distanceGrid[r][c] = euclideanDistance(LATGrid[r], LATGrid[c]);
        if(distanceGrid[r][c] != 0 && distanceGrid[r][c] < minDistance)
          minDistance = distanceGrid[r][c];
        if(distanceGrid[r][c] > maxDistance)
          maxDistance = distanceGrid[r][c];
      }
    }    
  }
  

/*************************************************************************
 Loads the datafile and parses it
**************************************************************************/
  private void loadData(){
    boolean fileOK = false;
    String promptString = "Choose a .CSV file generated by DocuScope's multi-text viewer";
    String[] lines = null;
    String[] singleLine = null;
    int r, c;
    int LATStartColumn = 0;
    int ignoreLast = 0;     // ignore the last column - "groups" - however for ALL we might need to include this later as it omits groups
    
    // Open the file and check if it's a correct DocuScope file
    while(!fileOK){
      lines = loadStrings(selectInput(promptString));
      singleLine = split(lines[0], ",");
      for(c = 0; c < singleLine.length; c++){
        if(singleLine[c].equals("FirstPer") || singleLine[c].equals("Generic_FirstPerson") || singleLine[c].equals("First_Person") || singleLine[c].equals("[First_Person]")){      // Which column contains the Docuscope magic word? This might need to be tweaked.
          if(!singleLine[c].equals("[First_Person]")){       // "Save ALL was used"
            ignoreLast = -1;  
          }
          LATStartColumn = c;
          fileOK = true;
          break;
        }
      }
      if(!fileOK){
        promptString = "Can't read that file. Please select a DocuScope .CSV file";
      }
    }
  
    noOfTexts = lines.length - 1;
    textLabels = new String[noOfTexts];
    noOfLATs = singleLine.length - LATStartColumn + ignoreLast;
    LATLabels = new String[noOfLATs];
    LATGrid = new double[noOfTexts][singleLine.length - LATStartColumn + ignoreLast];
    
    for(c = LATStartColumn; c < singleLine.length + ignoreLast; c++){
      LATLabels[c-LATStartColumn] = new String(singleLine[c]);
    }
   println(noOfTexts);
    for(r=1; r <= noOfTexts; r++){
      singleLine = split(lines[r], ",");
      textLabels[r-1] = new String(singleLine[0]);
      for(c = LATStartColumn; c < singleLine.length + ignoreLast; c++){
        try {
          LATGrid[r-1][c-LATStartColumn] = Double.parseDouble(singleLine[c]);
        } catch(NumberFormatException e) {
          LATGrid[r-1][c-LATStartColumn] = 0;        
        }
      }
    }
    
  }


  /*************************************************************************
   Calculate the euclidean distance between two vectors
  **************************************************************************/
  private double euclideanDistance(double[] textOne, double[] textTwo){
    int i;
    double distance = 0;
    for(i=0; i < noOfLATs; i++){
      distance += Math.pow(textOne[i] - textTwo[i], 2);
    }
    
    return Math.sqrt(distance);
  }
  /*************************************************************************
   Calculate the data required for the Boxplot
  **************************************************************************/
  void buildBoxPlotData(){
    int i = 0, r, c;
    double[] singleLAT = new double[noOfTexts];
    
    boxPlotMetrics = new double[noOfLATs][5];
    
    for(c = 0; c < noOfLATs; c++){
      for(r = 0; r < noOfTexts; r++){
        singleLAT[r] = LATGrid[r][c];
      }
      Arrays.sort(singleLAT);
      
      for(i = 0; i < noOfTexts; i++){
        if(singleLAT[i] > 0)
          break;
      }
      
      if(i >= noOfTexts)
        i=0;

      boxPlotMetrics[c][0] = singleLAT[i];    //min
      boxPlotMetrics[c][4] = singleLAT[noOfTexts-1];    //max
      boxPlotMetrics[c][1] = singleLAT[(int)(noOfTexts/4)];    // Q1
      boxPlotMetrics[c][2] = singleLAT[(int)(noOfTexts/2)];    // Q2 - median
      boxPlotMetrics[c][3] = singleLAT[(int)(noOfTexts*3/4)];    // Q3
      if(maxValue < boxPlotMetrics[c][4])
        maxValue = boxPlotMetrics[c][4];
    }
  }
}

