text: const TWO_PI = 2 * Math.PI;
  
  // The problem with the trig inverse functions on
  // a full circle is that the sector information will be lost
  // Choosing to use arcsin because you can get back the
  // sector with the help of the original coordinates
  function reifyasin(x, y, asin_angle) {
      if (x >= 0 && y >= 0) {
          return asin_angle;
      } else if (x >= 0 && y < 0) {
          return Math.PI - asin_angle;
      } else if (x < 0 && y < 0) {
          return Math.PI - asin_angle;
      } else {
          return TWO_PI + asin_angle;
      }
  }
  
  // rebase and angle so be between -pi and pi
  // rather than 0 to 2PI
  function rebaseNegative(angle) {
      if (angle > Math.PI) {
          return angle - TWO_PI;
      } else {
          return angle;
      }
  }
  
  // rebase an angle so that it is between 0 to 2pi
  // rather than -pi to pi
  function rebasePositive(angle) {
      if (angle < 0) {
          return angle + TWO_PI;
      } else {
          return angle;
      }
  }
  
  /**
   * The Hour Scriber is responsible for drawing the numeral
   * on the screen at the requested angle.
   * It allows for the font to be changed on the fly.
   */
  class HourScriber {
      constructor(radius, numeral_font, draw_test, bg_colour_supplier, numeral_colour_supplier, hour) {
          this.radius = radius;
          this.numeral_font = numeral_font;
          this.draw_test = draw_test;
          this.curr_numeral_font = numeral_font;
          this.bg_colour_supplier = bg_colour_supplier;
          this.numeral_colour_supplier = numeral_colour_supplier;
          this.hours = hour;
          this.curr_hour_x = -1;
          this.curr_hour_y = -1;
          this.curr_hours = -1;
          this.curr_hour_str = null;
          this.last_draw_time = null;
      }
      setNumeralFont(numeral_font) {
          this.numeral_font = numeral_font;
      }
      toString() {
          return "HourScriber{numeralfont=" + this.numeral_font.getName() + ",hours=" + this.hours + "}";
      }
      draw() {
          var changed = false;
          if (this.curr_hours != this.hours || this.curr_numeral_font != this.numeral_font) {
              var background = this.bg_colour_supplier();
              g.setColor(background[0], background[1], background[2]);
              this.curr_numeral_font.draw(this.curr_hour_str,
                  this.curr_hour_x,
                  this.curr_hour_y);
              //console.log("erasing old hour display:" + this.curr_hour_str + " color:" + background);
              var hours_frac = this.hours / 12;
              var angle = TWO_PI * hours_frac;
              var dimensions = this.numeral_font.getDimensions(this.hours);
              // we set the radial coord to be in the middle
              // of the drawn text.
              var width = dimensions[0];
              var height = dimensions[1];
              var delta_center_x = this.radius * Math.sin(angle) - width / 2;
              var delta_center_y = this.radius * Math.cos(angle) + height / 2;
              this.curr_hour_x = screen_center_x + delta_center_x;
              this.curr_hour_y = screen_center_y - delta_center_y;
              this.curr_hour_str = this.numeral_font.hour_txt(this.hours);
              // now work out the angle of the beginning and the end of the
              // text box so we know when to redraw
              // bottom left angle
              var x1 = delta_center_x;
              var y1 = delta_center_y;
              var r1 = Math.sqrt(x1 * x1 + y1 * y1);
              var angle1 = reifyasin(x1, y1, Math.asin(x1 / r1));
              // bottom right angle
              var x2 = delta_center_x;
              var y2 = delta_center_y - height;
              var r2 = Math.sqrt(x2 * x2 + y2 * y2);
              var angle2 = reifyasin(x2, y2, Math.asin(x2 / r2));
              // top left angle
              var x3 = delta_center_x + width;
              var y3 = delta_center_y;
              var r3 = Math.sqrt(x3 * x3 + y3 * y3);
              var angle3 = reifyasin(x3, y3, Math.asin(x3 / r3));
              // top right angle
              var x4 = delta_center_x + width;
              var y4 = delta_center_y - height;
              var r4 = Math.sqrt(x4 * x4 + y4 * y4);
              var angle4 = reifyasin(x4, y4, Math.asin(x4 / r4));
              if (Math.min(angle1, angle2, angle3, angle4) < Math.PI && Math.max(angle1, angle2, angle3, angle4) > 1.5 * Math.PI) {
                  angle1 = rebaseNegative(angle1);
                  angle2 = rebaseNegative(angle2);
                  angle3 = rebaseNegative(angle3);
                  angle3 = rebaseNegative(angle4);
                  this.angle_from = rebasePositive(Math.min(angle1, angle2, angle3, angle4));
                  this.angle_to = rebasePositive(Math.max(angle1, angle2, angle3, angle4));
              } else {
                  this.angle_from = Math.min(angle1, angle2, angle3, angle4);
                  this.angle_to = Math.max(angle1, angle2, angle3, angle4);
              }
              //console.log(angle1 + "/" + angle2  + " / " + angle3 + " / " + angle4);
              //console.log( this.angle_from + " to " + this.angle_to);
              this.curr_hours = this.hours;
              this.curr_numeral_font = this.numeral_font;
              changed = true;
          }
          if (changed ||
              this.draw_test(this.angle_from, this.angle_to, this.last_draw_time)) {
              var numeral_color = this.numeral_colour_supplier();
              g.setColor(numeral_color[0], numeral_color[1], numeral_color[2]);
              this.numeral_font.draw(this.curr_hour_str, this.curr_hour_x, this.curr_hour_y);
              this.last_draw_time = new Date();
              //console.log("redraw digit:" + this.hours);
          }
      }
  }
  
  module.exports = HourScriber;