/**
  * Highlights the subsequence of the rule.
  *
  * @param The rule index.
  */
 private void highlightPatternInChart(String rule) {
   consoleLogger.debug("Selected rule: " + rule);
   ArrayList<RuleInterval> arrPos = chartData.getRulePositionsByRuleNum(Integer.valueOf(rule));
   consoleLogger.debug("Size: " + arrPos.size() + " - Positions: " + arrPos);
   timeseriesPlot.clearDomainMarkers();
   for (RuleInterval saxPos : arrPos) {
     addMarker(timeseriesPlot, saxPos.getStartPos(), saxPos.getEndPos());
   }
 }
 /**
  * Highlights intervals in between selected rule subsequences - ones which suppose to be periods.
  *
  * @param rule The rule whose subsequences will be period boundaries.
  */
 private void highlightPeriodsBetweenPatterns(String rule) {
   consoleLogger.debug("Selected rule: " + rule);
   ArrayList<RuleInterval> arrPos = chartData.getRulePositionsByRuleNum(Integer.valueOf(rule));
   consoleLogger.debug("Size: " + arrPos.size() + " - Positions: " + arrPos);
   timeseriesPlot.clearDomainMarkers();
   for (int i = 1; i < arrPos.size(); i++) {
     RuleInterval c = arrPos.get(i - 1);
     RuleInterval p = arrPos.get(i);
     addPeriodMarker(timeseriesPlot, c.getEndPos(), p.getStartPos());
   }
 }
  /** Puts rules density on show. */
  private void displayRuleDensity() {

    // this is the new "insert" - elastic boundaries chart panel
    //
    paintTheChart(this.chartData.getOriginalTimeseries());
    ChartPanel chartPanel = new ChartPanel(this.chart);
    chartPanel.setMinimumDrawWidth(0);
    chartPanel.setMinimumDrawHeight(0);
    chartPanel.setMaximumDrawWidth(1920);
    chartPanel.setMaximumDrawHeight(1200);
    //
    this.removeAll();
    //
    this.add(chartPanel);

    // timeseriesPlot.clearDomainMarkers();
    int rulesNum = this.chartData.getRulesNumber();

    // find the rule density value
    int maxObservedCoverage = 0;
    int[] coverageArray = new int[chartData.getOriginalTimeseries().length];

    for (GrammarRuleRecord r : chartData.getGrammarRules()) {
      if (0 == r.ruleNumber()) {
        continue;
      }
      ArrayList<RuleInterval> arrPos = chartData.getRulePositionsByRuleNum(r.ruleNumber());
      for (RuleInterval saxPos : arrPos) {
        int start = saxPos.getStartPos();
        int end = saxPos.getEndPos();
        for (int j = start; j < end; j++) {
          if (CoverageCountStrategy.COUNT == this.session.getCountStrategy()) {
            coverageArray[j] = coverageArray[j] + 1;
          } else if (CoverageCountStrategy.LEVEL == this.session.getCountStrategy()) {
            coverageArray[j] = coverageArray[j] + r.getRuleLevel();
          } else if (CoverageCountStrategy.OCCURRENCE == this.session.getCountStrategy()) {
            coverageArray[j] = coverageArray[j] + r.getOccurrences().size();
          } else if (CoverageCountStrategy.YIELD == this.session.getCountStrategy()) {
            coverageArray[j] = coverageArray[j] + r.getRuleYield();
          } else if (CoverageCountStrategy.PRODUCT == this.session.getCountStrategy()) {
            coverageArray[j] = coverageArray[j] + r.getRuleLevel() * r.getOccurrences().size();
          }
          if (maxObservedCoverage < coverageArray[j]) {
            maxObservedCoverage = coverageArray[j];
          }
        }
      }
    }

    // since we know the maximal coverage value, we can compute the increment for a single coverage
    // interval
    double covIncrement = 1. / (double) maxObservedCoverage;

    for (int i = 0; i < rulesNum; i++) {
      GrammarRuleRecord r = chartData.getRule(i);
      if (0 == r.ruleNumber()) {
        continue;
      }
      ArrayList<RuleInterval> arrPos = chartData.getRulePositionsByRuleNum(i);
      for (RuleInterval saxPos : arrPos) {
        IntervalMarker marker = new IntervalMarker(saxPos.getStartPos(), saxPos.getEndPos());
        marker.setLabelOffsetType(LengthAdjustmentType.EXPAND);
        marker.setPaint(Color.BLUE);

        // marker.setAlpha((float) 0.05);
        if (CoverageCountStrategy.COUNT == this.session.getCountStrategy()) {
          marker.setAlpha((float) covIncrement);
        } else if (CoverageCountStrategy.LEVEL == this.session.getCountStrategy()) {
          marker.setAlpha((float) covIncrement * r.getRuleLevel());
        } else if (CoverageCountStrategy.OCCURRENCE == this.session.getCountStrategy()) {
          marker.setAlpha((float) covIncrement * r.getOccurrences().size());
        } else if (CoverageCountStrategy.YIELD == this.session.getCountStrategy()) {
          marker.setAlpha((float) covIncrement * r.getRuleYield());
        } else if (CoverageCountStrategy.PRODUCT == this.session.getCountStrategy()) {
          marker.setAlpha((float) covIncrement * (r.getRuleLevel() * r.getOccurrences().size()));
        }
        marker.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
        marker.setLabelPaint(Color.green);
        marker.setLabelAnchor(RectangleAnchor.TOP_LEFT);
        marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);
        timeseriesPlot.addDomainMarker(marker, Layer.BACKGROUND);
      }
    }

    // not sure if I need this
    //
    validate();
    repaint();

    // and finally save the coverage curve
    //

    this.saveRuleDensityCurve(coverageArray);
  }