#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#ifdef HAVE_WINDOWS_H
#  include <windows.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <Aircraft/aircraft.hxx>
#include <Include/fg_constants.h>
#include <Math/fg_random.h>
#include <Math/mat3.h>
#include <Math/polar3d.hxx>
#include <Scenery/scenery.hxx>
#include <Time/fg_timer.hxx>


#include "hud.hxx"
//========== Top of hud_card class member definitions =============

hud_card ::
hud_card( int       x,
          int       y,
          UINT      width,
          UINT      height,
          DBLFNPTR  data_source,
          UINT      options,
          double    max_value,
          double    min_value,
          double    disp_scaling,
          UINT      major_divs,
          UINT      minor_divs,
          UINT      modulus,
          int       dp_showing,
          double    value_span,
          bool      working) :
                instr_scale( x,y,width,height,
                             data_source, options,
                             value_span,
                             max_value, min_value, disp_scaling,
                             major_divs, minor_divs, modulus,
                             working),
                val_span   ( value_span)
{
  half_width_units = range_to_show() / 2.0;
}

hud_card ::
~hud_card() { }

hud_card ::
hud_card( const hud_card & image):
      instr_scale( (const instr_scale & ) image),
      val_span( image.val_span),
      half_width_units (image.half_width_units)
{
}

hud_card & hud_card ::
operator = (const hud_card & rhs )
{
  if( !( this == &rhs)){
    instr_scale::operator = (rhs);
    val_span = rhs.val_span;
    half_width_units = rhs.half_width_units;
    }
  return *this;
}

void hud_card ::
draw( void ) //  (HUD_scale * pscale )
{
  double vmin, vmax;
  int marker_xs;
  int marker_xe;
  int marker_ys;
  int marker_ye;
  /* register */ int i;
  char TextScale[80];
  bool condition;
  int disp_val = 0;
  POINT mid_scr    = get_centroid();
  double cur_value = get_value();
  RECT   scrn_rect = get_location();
  UINT options     = get_options();

  vmin = cur_value - half_width_units; // width units == needle travel
  vmax = cur_value + half_width_units; // or picture unit span.
    // Draw the basic markings for the scale...

  if( options & HUDS_VERT ) { // Vertical scale
    drawOneLine( scrn_rect.left,     // Bottom tick bar
                 scrn_rect.top,
                 scrn_rect.left + scrn_rect.right,
                 scrn_rect.top);

    drawOneLine( scrn_rect.left,    // Top tick bar
                 scrn_rect.top  + scrn_rect.bottom,
                 scrn_rect.left + scrn_rect.right,
                 scrn_rect.top  + scrn_rect.bottom );

    marker_xs = scrn_rect.left;
    marker_xe = scrn_rect.left + scrn_rect.right;

    // We do not use else in the following so that combining the two
    // options produces a "caged" display with double carrots. The
    // same is done for horizontal card indicators.

    if( options & HUDS_LEFT ) {    // Calculate x marker offset
      drawOneLine( scrn_rect.left + scrn_rect.right,
                   scrn_rect.top,
                   scrn_rect.left + scrn_rect.right,
                   scrn_rect.top + scrn_rect.bottom); // Cap right side

      marker_xs  = marker_xe - scrn_rect.right / 3;   // Adjust tick xs
                                                      // Indicator carrot
      drawOneLine( marker_xs, mid_scr.y,
                   marker_xe, mid_scr.y + scrn_rect.right / 6);
      drawOneLine( marker_xs, mid_scr.y,
                   marker_xe, mid_scr.y - scrn_rect.right / 6);

      }
    if( options & HUDS_RIGHT ) {  // We'll default this for now.
      drawOneLine( scrn_rect.left,
                   scrn_rect.top,
                   scrn_rect.left,
                   scrn_rect.top + scrn_rect.bottom);  // Cap left side

      marker_xe = scrn_rect.left + scrn_rect.right / 3;     // Adjust tick xe
                                                       // Indicator carrot
      drawOneLine( scrn_rect.left, mid_scr.y +  scrn_rect.right / 6,
                   marker_xe, mid_scr.y );
      drawOneLine( scrn_rect.left, mid_scr.y -  scrn_rect.right / 6,
                   marker_xe, mid_scr.y);
      }

    // At this point marker x_start and x_end values are transposed.
    // To keep this from confusing things they are now interchanged.
    if(( options & HUDS_BOTH) == HUDS_BOTH) {
      marker_ye = marker_xs;
      marker_xs = marker_xe;
      marker_xe = marker_ye;
      }

    // Work through from bottom to top of scale. Calculating where to put
    // minor and major ticks.

    for( i = (int)vmin; i <= (int)vmax; i++ )      {
      condition = true;
      if( !modulo()) {
        if( i < min_val()) {
          condition = false;
          }
        }

      if( condition ) {  // Show a tick if necessary
                         // Calculate the location of this tick
        marker_ys = scrn_rect.top + (int)((i - vmin) * factor() + .5);

        // Block calculation artifact from drawing ticks below min coordinate.
        // Calculation here accounts for text height.

        if(( marker_ys < (scrn_rect.top + 4)) |
           ( marker_ys > (scrn_rect.top + scrn_rect.bottom - 4))) {
            // Magic numbers!!!
          continue;
          }
        if( div_min()) {
          if( (i%div_min()) == 0) {
            if((( marker_ys - 5) > scrn_rect.top ) &&
               (( marker_ys + 5) < (scrn_rect.top + scrn_rect.bottom))){
              if( (options & HUDS_BOTH) == HUDS_BOTH ) {
                drawOneLine( scrn_rect.left, marker_ys,
                             marker_xs,      marker_ys );
                drawOneLine( marker_xe,      marker_ys,
                             scrn_rect.left + scrn_rect.right,  marker_ys );
                }
              else {
                if( options & HUDS_LEFT ) {
                  drawOneLine( marker_xs + 4, marker_ys,
                               marker_xe,     marker_ys );
                  }
                else {
                  drawOneLine( marker_xs,     marker_ys,
                               marker_xe - 4, marker_ys );
                  }
                }
              }
            }
          }
        if( div_max()) {
          if( !(i%(int)div_max())){
            if(modulo()) {
              if( disp_val < 0) {
                disp_val += modulo();
                }
              else {
                disp_val = i % modulo();
                }
              }
            else {
              disp_val = i;
              }
            sprintf( TextScale, "%d", (int)(disp_val  * data_scaling() +.5));
            if(( (marker_ys - 8 ) > scrn_rect.top ) &&
               ( (marker_ys + 8) < (scrn_rect.top + scrn_rect.bottom))){
              if( (options & HUDS_BOTH) == HUDS_BOTH) {
                drawOneLine( scrn_rect.left, marker_ys,
                             marker_xs,      marker_ys);
                drawOneLine( marker_xs,                  marker_ys,
                             scrn_rect.left + scrn_rect.right,
                             marker_ys);
                if( !(options & HUDS_NOTEXT)) {
                  textString ( marker_xs + 2,  marker_ys,
                               TextScale,  GLUT_BITMAP_8_BY_13 );
                  }
                }
              else {
                drawOneLine( marker_xs, marker_ys, marker_xe, marker_ys );
                if( !(options & HUDS_NOTEXT)) {
                  if( options & HUDS_LEFT )              {
                    textString( marker_xs -  8 * strlen(TextScale) - 2,
                                marker_ys - 4,
                                TextScale, GLUT_BITMAP_8_BY_13 );
                    }
                  else  {
                    textString( marker_xe + 3 * strlen(TextScale),
                                marker_ys - 4,
                                TextScale, GLUT_BITMAP_8_BY_13 );
                    }
                  }
                }
              } // Else read oriented right
            } // End if modulo division by major interval is zero
          }  // End if major interval divisor non-zero
        } // End if condition
      } // End for range of i from vmin to vmax
    }  // End if VERTICAL SCALE TYPE
  else {                                // Horizontal scale by default
    drawOneLine( scrn_rect.left,     // left tick bar
                 scrn_rect.top,
                 scrn_rect.left,
                 scrn_rect.top + scrn_rect.bottom);

    drawOneLine( scrn_rect.left + scrn_rect.right,    // right tick bar
                 scrn_rect.top,
                 scrn_rect.left + scrn_rect.right,
                 scrn_rect.top  + scrn_rect.bottom );

    marker_ys = scrn_rect.top;                       // Starting point for
    marker_ye = scrn_rect.top + scrn_rect.bottom;    // tick y location calcs

    if( options & HUDS_TOP ) {
      drawOneLine( scrn_rect.left,
                   scrn_rect.top,
                   scrn_rect.left + scrn_rect.right,
                   scrn_rect.top);                    // Bottom box line

      marker_ye  = scrn_rect.top + scrn_rect.bottom / 2;   // Tick point adjust
                                                      // Bottom arrow
      drawOneLine( mid_scr.x, marker_ye,
                   mid_scr.x - scrn_rect.bottom / 4, scrn_rect.top);
      drawOneLine( mid_scr.x, marker_ye,
                   mid_scr.x + scrn_rect.bottom / 4, scrn_rect.top);
      }
    if( options & HUDS_BOTTOM) {
      drawOneLine( scrn_rect.left,
                   scrn_rect.top + scrn_rect.bottom,
                   scrn_rect.left + scrn_rect.right,
                   scrn_rect.top + scrn_rect.bottom);  // Top box line
                                                       // Tick point adjust
      marker_ys = scrn_rect.top +
                  scrn_rect.bottom - scrn_rect.bottom  / 2;
                                                       // Top arrow
      drawOneLine( mid_scr.x + scrn_rect.bottom / 4,
                          scrn_rect.top + scrn_rect.bottom,
                   mid_scr.x ,
                          marker_ys );
      drawOneLine( mid_scr.x - scrn_rect.bottom / 4,
                          scrn_rect.top + scrn_rect.bottom,
                   mid_scr.x ,
                          marker_ys );
      }

//    if(( options & HUDS_BOTTOM) == HUDS_BOTTOM ) {
//      marker_xe = marker_ys;
//      marker_ys = marker_ye;
//      marker_ye = marker_xe;
//      }

    // printf("vmin = %d  vmax = %d\n", (int)vmin, (int)vmax);
    for( i = (int)vmin; i <= (int)vmax; i++ )     {
      // printf("<*> i = %d\n", i);
      condition = true;
      if( !modulo()) {
        if( i < min_val()) {
          condition = false;
          }
        }
      // printf("<**> i = %d\n", i);
      if( condition )        {
        marker_xs = scrn_rect.left + (int)((i - vmin) * factor() + .5);
        if( div_min()){
          if( (i%(int)div_min()) == 0 ) {
            // draw in ticks only if they aren't too close to the edge.
            if((( marker_xs - 5) > scrn_rect.left ) &&
               (( marker_xs + 5 )< (scrn_rect.left + scrn_rect.right))){

              if( (options & HUDS_BOTH) == HUDS_BOTH ) {
                drawOneLine( marker_xs, scrn_rect.top,
                             marker_xs, marker_ys - 4);
                drawOneLine( marker_xs, marker_ye + 4,
                             marker_xs, scrn_rect.top + scrn_rect.bottom);
                }
              else {
                if( options & HUDS_TOP) {
                  drawOneLine( marker_xs, marker_ys,
                               marker_xs, marker_ye - 4);
                  }
                else {
                  drawOneLine( marker_xs, marker_ys + 4,
                               marker_xs, marker_ye);
                  }
                }
              }
            }
          }
	// printf("<***> i = %d\n", i);
        if( div_max()) {
	  // printf("i = %d\n", i);
          if( (i%(int)div_max())==0 ) {
            if(modulo()) {
              if( disp_val < 0) {
                disp_val += modulo();
                }
              else {
                disp_val = i % modulo();
                }
              }
            else {
              disp_val = i;
              }
	    // printf("disp_val = %d\n", disp_val);
	    // printf("%d\n", (int)(disp_val  * (double)data_scaling() + 0.5));
            sprintf( TextScale, "%d", (int)(disp_val  * data_scaling() +.5));
            // Draw major ticks and text only if far enough from the edge.
            if(( (marker_xs - 10)> scrn_rect.left ) &&
               ( (marker_xs + 10) < (scrn_rect.left + scrn_rect.right))){
              if( (options & HUDS_BOTH) == HUDS_BOTH) {
                drawOneLine( marker_xs, scrn_rect.top,
                             marker_xs, marker_ys);
                drawOneLine( marker_xs, marker_ye,
                             marker_xs, scrn_rect.top + scrn_rect.bottom);

                if( !(options & HUDS_NOTEXT)) {
                  textString ( marker_xs - 4 * strlen(TextScale),
                               marker_ys + 4,
                               TextScale,  GLUT_BITMAP_8_BY_13 );
                  }
                }
              else {
                drawOneLine( marker_xs, marker_ys,
                             marker_xs, marker_ye );
                if( !(options & HUDS_NOTEXT)) {
                  if( options & HUDS_TOP )              {
                    textString ( marker_xs - 4 * strlen(TextScale),
                                 scrn_rect.top + scrn_rect.bottom - 10,
                                 TextScale, GLUT_BITMAP_8_BY_13 );
                    }
                  else  {
                    textString( marker_xs - 4 * strlen(TextScale),
                                scrn_rect.top,
                                TextScale, GLUT_BITMAP_8_BY_13 );
                    }
                  }
                }
              }
            }
	  }
	// printf("<****> i = %d\n", i);
        }
      }
    }
}