/*
   File:        lingraph.h
   Author:      Andrew W. Moore
   Created:     Wed May  8 19:16:35 EDT 1996
   Description: Header for Graphs with lines on them

   Copyright (C) 1996, A. W. Moore
*/


#ifndef LINGRAPH_H
#define LINGRAPH_H
#include "amut.h"
#include "agbox.h"

#define JOINED_STYLE 0
#define DOTTED_STYLE 1
#define PIXEL_STYLE 2
#define CROSS_STYLE 3
#define SMALLBOX_STYLE 4
#define SMALLTRIANGLE_STYLE 5
#define SMALLCIRCLE_STYLE 6
#define FANCY_STYLE 7
#define DISC_STYLE 8
#define SMALLPLUS_STYLE 9
#define NUM_STYLES 10

typedef struct laxis
{
  char *name;   /* NULL denotes undefined */
  bool min_defined;
  double min_value;
  bool max_defined;
  double max_value;
} laxis;

/* An rspart (real-symbolic-graph) allows the lingraph user to
   define a histogram in which the x-axis is a real number and 
   the y-axis is EITHER the count or the FREQUENCY.

   Each thing added to an rspart is a (x,class) pair. If all 
   things are added with class=0 then all bars will be rendered
   in a single color. If, however, there are several classes then 
   the bars will be broken into different-colored components.
*/
typedef struct rspart
{
  dyv_array *data;

  dyv_array *counts;

    /* Number of classes = dym_array_size(data)
       Datapoints from i'th class = dym_array_ref(data,i)
       dym_ref(dyv_array_ref(data,q),k) = x coord of k'th point in class q
       dym_ref(dyv_array_ref(counts,q),k) = count or weight
                                            of k'th point in class q
    */

  int num_bars; /* -1 = undefined */

  bool ratio; /* TRUE <=> show ratios (i.e. all bars are same total height,
                 only difference is fraction of different classes) */

  string_array *labels;  /* string_array_ref(labels,i) = label for i'th class.
                             NULL denotes undefined */
} rspart;

/* An sspart (symbolic-symbolic-graph) allows the lingraph user to
   define a histogram in which the x-axis is a symbolic variable
   (i.e. each value from one of a discrete set of classes) and 
   the y-axis is EITHER the count or the FREQUENCY.

   Each thing added to an rspart is a (xclass,yclass) pair. If all 
   things are added with yclass=0 then all bars will be rendered
   in a single color. If, however, there are several yclasses then 
   the bars will be broken into different-colored components.
*/
typedef struct sspart
{
  dym *freqs;
    /* Number of classes = dym_cols(freqs)
       Number of bars = dym_rows(freqs)
    */

  bool ratio; /* TRUE <=> show ratios (i.e. all bass are same total height,
                 only difference is fraction of different classes) */

  string_array *labels;  /* string_array_ref(labels,i) = label for i'th class.
                             NULL denotes undefined */

  string_array *barnames; /* string_array_ref(barnames,i) = name for i'th class
                             NULL denotes undefined */
} sspart;


typedef struct lingraph
{
  rspart *rsp; /* NULL denotes "no rspart" */

  sspart *ssp; /* NULL denotes "no sspart" */

  dym_array *lines;
    /* Number of lines = dym_array_size(lines).
       Number of points on jth line = dym_rows(dym_array_ref(lines,j))
       x coord of ith point on jth line = dym_ref(dym_array_ref(lines,j),i,0)
       y coord of ith point on jth line = dym_ref(dym_array_ref(lines,j),i,1)
    */
  ivec *color_codes;

  /*
    binary: 1 requests the renderer to do the conversion
    0 does not
    initial default setting is 1
    a call to set_line_color resets it to 0
    use 'is_convert_color_code_to_ag_color_set()' to check the current setting
    use 'set_line_convert_color_code_to_ag_color()' and
    'unset_line_convert_color_code_to_ag_color()' to change it.
  */
  ivec *convert_color_code_to_ag_color;

  ivec *styles;
  string_array *labels;  /* string_array_ref(labels,i) = label for i'th line.
			    NULL denotes undefined */
  char *title; /* NULL denotes undefined */

  dym *string_locations;
  string_array *strings;
      /* The above two fields are used for strings which
         can appear within the actual diagram. */

  laxis *x;
  laxis *y;
} lingraph;

lingraph *mk_empty_lingraph(void);
int lingraph_num_lines(lingraph *lg);
void free_lingraph(lingraph *x);
lingraph *mk_copy_lingraph(lingraph *x);
void fprintf_lingraph(FILE *s,char *m1,lingraph *x,char *m2);
void add_to_lingraph(lingraph *lg,int line_num,double x,double y);
void add_string_to_lingraph(lingraph *lg,double x,double y,char *string);
void set_line_color(lingraph *lg, int line_num, int color );
void set_line_convert_color_code_to_ag_color( lingraph *lg, int line_num );
void unset_line_convert_color_code_to_ag_color( lingraph *lg, int line_num );
bool is_convert_color_code_to_ag_color_set( lingraph *lg, int line_num );
void set_lines_same_color(lingraph *lg,int line_num1,int line_num2);
void set_line_style_dotted(lingraph *lg,int line_num);
void set_line_style_pixel(lingraph *lg,int line_num);
void set_line_style_cross(lingraph *lg,int line_num);
void set_line_style_smallbox(lingraph *lg,int line_num);
void set_line_style_smalltriangle(lingraph *lg,int line_num);
void set_line_style_smallcircle(lingraph *lg,int line_num);
void set_line_style_fancy(lingraph *lg,int line_num);
void set_line_style_disc(lingraph *lg,int line_num);
void set_line_style_smallplus(lingraph *lg,int line_num);
void set_x_axis_label(lingraph *lg,char *label);
void set_y_axis_label(lingraph *lg,char *label);
void set_lingraph_title(lingraph *lg,char *label);
void set_line_label(lingraph *lg,int line_num,char *label);
void set_x_min(lingraph *lg,double xmin);
void set_x_max(lingraph *lg,double xmax);
void set_y_min(lingraph *lg,double ymin);
void set_y_max(lingraph *lg,double ymax);
void maybe_reset_x_min(lingraph *lg,double xmin);
void maybe_reset_x_max(lingraph *lg,double xmax);
void maybe_reset_y_min(lingraph *lg,double ymin);
void maybe_reset_y_max(lingraph *lg,double ymax);

void render_lingraph_in_agbox(lingraph *lg,agbox *agb);
void render_lingraph(lingraph *lg);

/* BEGIN THE API THAT LINGRAPH CREATORS GET TO SEE */

/* Adds to the "RS" (real-symbolic) part of the lingraph. 
   Remember, RS part is a histogram indexed by a real
   axis, where bars can be composed of more than one color
   according to their class. */
void lingraph_rs_add(lingraph *lg,double x,double count,int classnum);

/* Gives a name to the classnum'th bar color in the RS part.
   Remember, RS part is a histogram indexed by a real
   axis, where bars can be composed of more than one color
   according to their class. */
void lingraph_rs_set_class_label(lingraph *lg,int classnum,char *label);

/* Forces the number of bars to be used in the RS part. Note
   it's not necessary to call this..the code will figure out
   a suitable default if you don't.
   Remember, RS part is a histogram indexed by a real
   axis, where bars can be composed of more than one color
   according to their class. */
void lingraph_rs_set_num_bars(lingraph *lg,int num_bars);

/* instructs the RS part to scale all bars to the same heights
   so that the ratios of color sizes in each bar can be inspected.
   Remember, RS part is a histogram indexed by a real
   axis, where bars can be composed of more than one color
   according to their class. */
void lingraph_rs_show_ratio(lingraph *lg);

/* add a new line number to the historgram.  This new line is a array
   with position x and length from 0 to the max in the histogram*/
void add_vertical_downward_arrow_to_rs_lingraph(lingraph *lg,double x, int color);

/*********** Begin visible-to-lingraph-creating-programmer
             ss-API ********/

/* Add a count to the specified part of the symbolic-symbolic
   component of the lingraph. */
/* Remember that the SS part of a lingraph is where you may 
   graph a histogram indexed by different values of a symbolic
   attribute along the X-axis, and where if you wish, the
   histogram bars may be broken up according to different
   values of the "class"...a second symbolic attribute. */
void lingraph_ss_add(lingraph *lg,int barnum,int classnum,double count);

/* Sets the text label associated with the classnum'th
   class (Y-symbolic-value) */
/* Remember that the SS part of a lingraph is where you may 
   graph a histogram indexed by different values of a symbolic
   attribute along the X-axis, and where if you wish, the
   histogram bars may be broken up according to different
   values of the "class"...a second symbolic attribute. */
void lingraph_ss_set_class_label(lingraph *lg,int classnum,char *label);

/* Sets the text label associated with the barnum'th
   bar (X-symbolic-value) */
/* Remember that the SS part of a lingraph is where you may 
   graph a histogram indexed by different values of a symbolic
   attribute along the X-axis, and where if you wish, the
   histogram bars may be broken up according to different
   values of the "class"...a second symbolic attribute. */
void lingraph_ss_set_bar_label(lingraph *lg,int barnum,char *label);

/* If you call this, the histrogram will have all bars
   stretched to the same height so you can see the
   various ratios of y-class (classnum) values. */
/* Remember that the SS part of a lingraph is where you may 
   graph a histogram indexed by different values of a symbolic
   attribute along the X-axis, and where if you wish, the
   histogram bars may be broken up according to different
   values of the "class"...a second symbolic attribute. */
void lingraph_ss_show_ratio(lingraph *lg);




/* The set of points corresponding to K std devs from the mean is
     S = { r : (r - m)^T COV^-1 (r - m) = K^2 / 2 }

   Write COV = L L^T where L is lower triangular and write KK = K^2 / 2

     S = { r : (r - m)^T (L L^T)^-1 (r - m) = KK }
       = { r : (r - m) (L^T)^-1 L^-1 (r - m) = KK }
       = { r : [L^-1 (r - m)]^T  L^-1 (r - m) = KK }
       = { r : | L^-1 (r - m)] | = sqrt(KK) }
       = { r : exists t with L^-1 (r - m) = sqrt(KK) * (cos t, sin t) }
       = { r : exists t with r = m + sqrt(KK) * L * (cos t, sin t) }
*/
void add_ellipse_to_lingraph(lingraph *lg,int line,dyv *mean,dym *cov,double k_std_devs);

/*------------------------------------------
  This adds an ellipse 'linenum' to lingraph 'lg'
  ellipse is defined by its center coordinates 'x0' 'y0',
  half-axes lengths 'a' and 'b' and rotation angle 'phi' 
  (phi in degrees!!!)
  'resolution' determines how many line segments will
  compose the ellipse. Put resolution=72 to get one line
  segment per a 5 degree angle slice (360/72 = 5).
  Coded by Artur Dubrawski, 03 Aug. 1996
------------------------------------------*/
void add_parametric_ellipse_to_lingraph(lingraph *lg, int linenum, 
			                                  double x0, double y0, double a, double b, double phi, 
			                                  int resolution );

/* The following functions are NOT for general use. */
laxis *mk_empty_laxis(void);
void free_laxis(laxis *x);
laxis *mk_copy_laxis(laxis *x);
void fprintf_laxis(FILE *s,char *m1,laxis *x,char *m2);
void maybe_replace(char **x,char *label);

void add_dyv_to_lingraph(lingraph *lg,int line,dyv *dv);
lingraph *mk_lingraph_from_dyv(char *title,dyv *dv);
void lingraph_draw_dyv(char *title,dyv *dv);

lingraph *mk_histogram(dyv *x,char *xname);
void render_histogram(dyv *x,char *xname);

lingraph *mk_lingraph_from_dyvs(dyv *x,char *xname,dyv *y,char *yname);
void render_dyvs(dyv *x,char *xname,dyv *y,char *yname);

#endif /* #ifndef LINGRAPH_H */


