/*
   * This method is called every time a mouse event is triggered.
   * This program will only handle mouse clicks.
   */
  public void mouseMoved(MouseEvent e) {
    if (e.getX() > infoWidth) {
      for (StepFunctionLine l : lines) {
        if (l.contains(e.getX(), e.getY())) {
          // l.color=(new Color(255,0,0));
          l.drawArea = true;
          l.highlight = true;
          l.displayInfo(e.getX(), e.getY());

        } else {
          l.highlight = false;
          // l.color=l.defaultColor;
          l.drawArea = false;
        }
      }
    }

    repaint();
  }
  public void mouseReleased(MouseEvent e) {
    if (scrolling) {
      scrolling = false;
      randLines.clear();

      // Clear current average CE and standard deviation
      aveRandCE = 0;
      randSTDev = 0;

      if (numRand != 0) {
        for (int i = 0; i < numRand; i++) {
          shuffle(order);
          StepFunctionLine randLine =
              new StepFunctionLine(
                  sc,
                  order,
                  new Color(200, 200, 200),
                  randLineWidth,
                  windowWidth - (infoWidth + axesWidth),
                  windowHeight - axesWidth - edgeBuffer,
                  infoWidth + (axesWidth * 3 / 4),
                  windowHeight - axesWidth * 3 / 4,
                  "Random",
                  "N/A");

          // Update CE to be divided later
          aveRandCE += randLine.getCE();

          /*
          private static float runningRandSTDev = 0;
          private static float randSTDev = 0; */
          randLines.add(randLine);
        }

        // Running average update: aveRandCE hasn't been divided by the numRand yet
        // so we can just add it to the running total CE and divide later.
        runningAveRandCE = runningAveRandCE * numRandGenerated + aveRandCE;

        // Update the total number of random generated and update the running average
        numRandGenerated += numRand;
        runningAveRandCE = runningAveRandCE / numRandGenerated;

        // Current average CE calculate
        aveRandCE = aveRandCE / numRand;

        // Calculate Standard deviation
        float sumOfSquares = 0;
        Iterator randIt = randLines.iterator();
        while (randIt.hasNext()) {
          StepFunctionLine currentRandLine = (StepFunctionLine) randIt.next();
          sumOfSquares +=
              (currentRandLine.getCE() - aveRandCE) * (currentRandLine.getCE() - aveRandCE);
        }

        randSTDev = (float) Math.sqrt((sumOfSquares / ((float) numRand - 1)));
        runningSumOfSquares += sumOfSquares;
        runningRandSTDev = (float) Math.sqrt(runningSumOfSquares / ((float) numRandGenerated - 1));

        System.out.println(
            "Average CE: "
                + aveRandCE
                + "\nRunning Average CE: "
                + runningAveRandCE
                + "\nStandard Deviation: "
                + randSTDev
                + "\nRunning Standard Deviation"
                + runningRandSTDev);
      }
      repaint();
    }
  }
  public void paint(Graphics g) {
    g2d = (Graphics2D) g;

    RenderingHints rh =
        new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

    g2d.setRenderingHints(rh);

    // Set the font for displaying the text information on the screen.
    g2d.setFont(new Font("Purisa", Font.PLAIN, 14));

    // Set to gray and fill info window
    g2d.setColor(new Color(240, 240, 240));
    g2d.fillRect(0, 0, infoWidth, windowHeight);

    // Set to white and fill the plot window
    g2d.setColor(new Color(255, 255, 255));
    g2d.fillRect(infoWidth, 0, windowWidth, windowHeight);

    //  Draw the axes
    g2d.setColor(new Color(0, 0, 0));
    g2d.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    // y axis
    g2d.drawLine(
        infoWidth + (axesWidth * 3 / 4) - 5,
        windowHeight - axesWidth * 3 / 4,
        infoWidth + (axesWidth * 3 / 4) - 5,
        edgeBuffer);
    // x axis
    g2d.drawLine(
        infoWidth + (axesWidth * 3 / 4),
        windowHeight - axesWidth * 3 / 4,
        windowWidth - edgeBuffer,
        windowHeight - axesWidth * 3 / 4);

    // Draw the ticks
    g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    for (int i = 0; i < numTicks; i++) {
      // Horizontal ticks on y axis
      int vertTickPoint = i * ((windowHeight - axesWidth * 3 / 4) - edgeBuffer) / (numTicks - 1);
      g2d.drawLine(
          infoWidth + (axesWidth * 3 / 4) - tickLength - 5,
          edgeBuffer + vertTickPoint,
          infoWidth + (axesWidth * 3 / 4) + tickLength - 5,
          edgeBuffer + vertTickPoint);
      g2d.drawString(
          (float) (numTicks - 1 - i) * ((float) numReqs / (float) (numTicks - 1)) + "",
          infoWidth + (axesWidth * 3 / 4) - 60,
          edgeBuffer + vertTickPoint + 5);

      // Vertical ticks on x axis
      int horTickPoint =
          i * ((windowWidth - edgeBuffer) - (infoWidth + (axesWidth * 3 / 4))) / (numTicks - 1);
      g2d.drawLine(
          horTickPoint + (infoWidth + (axesWidth * 3 / 4)),
          windowHeight - axesWidth * 3 / 4 - tickLength,
          horTickPoint + (infoWidth + (axesWidth * 3 / 4)),
          windowHeight - axesWidth * 3 / 4 + tickLength);
      g2d.drawString(
          (float) (i) * ((float) execTime / (float) (numTicks - 1)) + "",
          horTickPoint + (infoWidth + (axesWidth * 3 / 4)) - 22,
          windowHeight - axesWidth * 3 / 4 + tickLength + 15);
    }

    // Draw the stepfunctionlines
    for (StepFunctionLine l : randLines) {
      l.setGraphics(g2d);
      l.drawStep();
    }

    for (int i = 0; i < lines.size(); i++) {
      if (show[i] == true) {
        lines.get(i).setGraphics(g2d);
        lines.get(i).drawStep();
      }
    }

    // Draw the plot info
    g2d.setColor(new Color(0, 0, 0));
    g2d.drawString("Coverage: " + matrixFile, 17, 30);
    g2d.drawString("Timing: " + timeFile, 17, 50);
    g2d.drawString("Test Cases: " + lines.get(0).getNumTests(), 17, 70);
    // g2d.drawString("Execution Time: " + lines.get(0).getExecutionTime()+ " ms", 17, 70);

    // Draw a separator box
    g2d.drawRect(0, 0, infoWidth - 1, 85);

    ////////////////// Original and Reverse

    g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    // Draw vert lines between to delimit original/reverse buttons
    for (int i = 0; i <= 1; i++) {
      g2d.drawLine(
          originalGridStartX + i * gridSpacingX,
          originalGridStartY,
          originalGridStartX + i * gridSpacingX,
          originalGridStartY + oTechniques.length * gridSpacingY);
    }

    // Draw hor lines between to delimit original/reverse button grids
    for (int i = 0; i <= oTechniques.length; i++) {
      g2d.drawLine(
          originalGridStartX,
          originalGridStartY + i * gridSpacingY,
          originalGridStartX + gridSpacingX,
          originalGridStartY + i * gridSpacingY);
    }

    // Draw the text labels for the technique buttons
    for (int i = 0; i < oTechniques.length; i++) {
      g2d.drawString(
          oTechniques[i],
          originalGridStartX - originalLabelsOffsetX,
          originalGridStartY + originalLabelsOffsetY + i * gridSpacingY);
    }

    // The buttons
    for (int i = 0; i < 2; i++) {
      if (show[i] == true) {
        int row = i / 1;
        int col = i % 1;

        g2d.fillRect(
            originalGridStartX + col * gridSpacingX + buttonInsetX / 2,
            originalGridStartY + row * gridSpacingY + buttonInsetY / 2,
            gridSpacingX - buttonInsetX,
            gridSpacingY - buttonInsetY);
      }
    }

    // Labels over the controls
    g2d.drawString("Prioritization Techniques", originalGridStartX - 46, originalGridStartY - 30);
    g2d.drawString("Random Prioritizations", scrollBarStartX + 65, scrollBarStartY - 30);

    ///////////////////////////  Big Button grid

    // Draw vert lines between to delimit buttons
    for (int i = 0; i <= gcm.length; i++) {
      g2d.drawLine(
          gridStartX + i * gridSpacingX,
          gridStartY,
          gridStartX + i * gridSpacingX,
          gridStartY + techniques.length * gridSpacingY);
    }

    // Draw hor lines between to delimit grids
    for (int i = 0; i <= techniques.length; i++) {
      g2d.drawLine(
          gridStartX,
          gridStartY + i * gridSpacingY,
          gridStartX + gcm.length * gridSpacingX,
          gridStartY + i * gridSpacingY);
    }

    // Draw the text labels for the technique buttons
    for (int i = 0; i < techniques.length; i++) {
      g2d.setColor(colors[i]);
      g2d.drawString(
          techniques[i],
          gridStartX - techniqueLabelsOffsetX,
          gridStartY + techniqueLabelsOffsetY + i * gridSpacingY);
    }

    g2d.setColor(Color.BLACK);
    // Draw the gcm labels for the technique buttons
    for (int i = 0; i < gcm.length; i++) {
      g2d.drawString(
          gcm[i], gridStartX + gcmLabelsOffsetX + i * gridSpacingX, gridStartY - gcmLabelsOffsetY);
    }

    // The buttons
    for (int i = 2; i < lines.size(); i++) {
      g2d.setColor(colors[(i - 2) / gcm.length]);
      if (show[i] == true) {
        int row = (i - 2) / gcm.length;
        int col = (i - 2) % gcm.length;

        g2d.fillRect(
            gridStartX + col * gridSpacingX + buttonInsetX / 2,
            gridStartY + row * gridSpacingY + buttonInsetY / 2,
            gridSpacingX - buttonInsetX,
            gridSpacingY - buttonInsetY);
      }
    }

    // Scroll Bar
    // g2d.drawLine(scrollBarStartX, scrollBarStartY, scrollBarStartX+scrollBarLength,
    // scrollBarStartY);
    g2d.setColor(Color.WHITE);
    g2d.fillRect(
        scrollBarStartX,
        scrollBarStartY - ((gridSpacingY - buttonInsetY) / 2),
        scrollBarLength,
        gridSpacingY - buttonInsetY);
    g2d.setColor(new Color(200, 200, 200));
    g2d.fillRect(
        scrollBoxX,
        scrollBoxY - ((gridSpacingY - buttonInsetY) / 2),
        gridSpacingX - buttonInsetX,
        gridSpacingY - buttonInsetY);
    g2d.setColor(Color.BLACK);
    g2d.setFont(new Font("Purisa", Font.PLAIN, 18));
    g2d.drawString(numRand + "", scrollBoxX + 26, scrollBoxY + 7);
    g2d.setFont(new Font("Purisa", Font.PLAIN, 14));

    // Stats for random
    g2d.drawString("Avg CE: " + aveRandCE, scrollBarStartX - 5, scrollBarStartY + 29);
    g2d.drawString(
        "Running Avg CE: " + runningAveRandCE, scrollBarStartX - 5, scrollBarStartY + 49);
    g2d.drawString("St. Dev.: " + randSTDev, scrollBarStartX - 5, scrollBarStartY + 69);
    g2d.drawString(
        "Running St. Dev. " + runningRandSTDev, scrollBarStartX - 5, scrollBarStartY + 89);

    // axis labels
    g2d.setColor(Color.black);
    g2d.drawString(
        "Execution Time (ms)",
        (windowWidth - infoWidth) / 2 + infoWidth - 35,
        windowHeight - axesWidth * 3 / 4 + 45);

    g2d.translate((infoWidth + 15), (windowHeight / 2));
    g2d.rotate(-Math.PI / 2);
    g2d.drawString("Covered Requirements", -55, -2);
    g2d.rotate(Math.PI / 2);
  }