<?php
//
// +----------------------------------------------------------------------+
// |zen-cart Open Source E-commerce                                       |
// +----------------------------------------------------------------------+
// | Copyright (c) 2003-2009 The zen-cart developers                           |
// |                                                                      |
// | http://www.zen-cart.com/index.php                                    |
// |                                                                      |
// | Portions Copyright (c) 2003 osCommerce                               |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the GPL license,       |
// | that is bundled with this package in the file LICENSE, and is        |
// | available through the world-wide-web at the following url:           |
// | http://www.zen-cart.com/license/2_0.txt.                             |
// | If you did not receive a copy of the zen-cart license and are unable |
// | to obtain it through the world-wide-web, please send a note to       |
// | license@zen-cart.com so we can mail you a copy immediately.          |
// +----------------------------------------------------------------------+
//  $Id: phplot.php 15673 2010-03-14 21:40:00Z kuroi $

/*
  PHPLOT 4.4.6 Copyright (c) 1998-2001 Afan Ottenheimer
*/

class PHPlot{

  var $is_inline = 0;			//0 = Sends headers, 1 = sends just raw image data
  var $browser_cache = '1';	// 0 = Sends headers for browser to not cache the image, (i.e. 0 = don't let browser cache image)
                  // (only if is_inline = 0 also)
  var $session_set = '';		//Do not change
  var $scale_is_set = '';		//Do not change
  var $draw_plot_area_background = '';

  var $image_width;	//Total Width in Pixels
  var $image_height; 	//Total Height in Pixels
  var $image_border_type = ''; //raised, plain, ''
  var $x_left_margin;
  var $y_top_margin;
  var $x_right_margin;
  var $y_bot_margin;
  var $plot_area = array(5,5,600,400);
  var $x_axis_position = 0;	//Where to draw the X_axis (world coordinates)
  var $y_axis_position = '';  //Leave blank for Y axis at left of plot. (world coord.)
  var $xscale_type = 'linear';  //linear or log
  var $yscale_type = 'linear';

//Use for multiple plots per image
  var $print_image = 1;  //Used for multiple charts per image.

//Fonts
  var $use_ttf  = 0;		  //Use TTF fonts (1) or not (0)
  var $font_path = './';  //To be added
  var $font = './benjamingothic.ttf';

  ///////////Fonts: Small/Generic
  var $small_ttffont_size = 12; //
  //non-ttf
  var $small_font = 2; // fonts = 1,2,3,4 or 5
  var $small_font_width = 6.0; // width in pixels (2=6,3=8,4=8)
  var $small_font_height = 8.0; // height in pixels (2=8,3=10,4=12)

  //////////   Fonts:Title
  var $title_ttffont = './benjamingothic.ttf';
  var $title_ttffont_size = 14;
  var $title_angle= 0;
  //non-ttf
  var $title_font = '4'; // fonts = 1,2,3,4,5

  //////////////  Fonts:Axis
  var $axis_ttffont = './benjamingothic.ttf';
  var $axis_ttffont_size = 8;
  var $x_datalabel_angle = 0;
  //non-ttf
  var $axis_font = 2;

  ////////////////Fonts:Labels of Data
  var $datalabel_font = '2';

  //////////////// Fonts:Labels (Axis Titles)
  var $x_label_ttffont = './benjamingothic.ttf';
  var $x_label_ttffont_size = '12';
  var $x_label_angle = '0';

  var $y_label_ttffont = './benjamingothic.ttf';
  var $y_label_ttffont_size = '12';
  var $y_label_angle = 90;
  var $y_label_width = '';

//Formats
  var $file_format = 'png';
  var $file_name = '';  //For output to a file instead of stdout

//Plot Colors
  var $shading = 0;
  var $color_array = 1;	//1 = include small list
              //2 = include large list
              //array =  define your own color translation. See rgb.inc.php and SetRGBArray
  var $bg_color;
  var $plot_bg_color;
  var $grid_color;
  var $light_grid_color;
  var $tick_color;
  var $title_color;
  var $label_color;
  var $text_color;
  var $i_light = '';

//Data
  var $data_type = 'text-data'; //text-data, data-data-error, data-data
  var $plot_type= 'linepoints'; //bars, lines, linepoints, area, points, pie, thinbarline
  var $line_width = 2;
  var $line_style = array('solid','solid','solid','dashed','dashed','solid'); //Solid or dashed lines

  var $data_color = ''; //array('blue','green','yellow',array(0,0,0));
  var $data_border_color = '';

  var $label_scale_position = '.5';  //1 = top, 0 = bottom
  var $group_frac_width = '.7'; //value from 0 to 1 = width of bar
  var $bar_width_adjust = '1'; //1 = bars of normal width, must be > 0

  var $point_size = 10;
  var $point_shape = 'diamond'; //rect,circle,diamond,triangle,dot,line,halfline
  var $error_bar_shape = 'tee'; //tee, line
  var $error_bar_size = 5; //right left size of tee
  var $error_bar_line_width = ''; //If set then use it, else use $line_width for thickness
  var $error_bar_color = '';
  var $data_values;

  var $plot_border_type = 'full'; //left, none, full
  var $plot_area_width = '';
  var $number_x_points;
  var $plot_min_x; // Max and min of the plot area
  var $plot_max_x= ''; // Max and min of the plot area
  var $plot_min_y= ''; // Max and min of the plot area
  var $plot_max_y = ''; // Max and min of the plot area
  var $min_y = '';
  var $max_y = '';
  var $max_x = 10;  //Must not be = 0;
  var $y_precision = '1';
  var $x_precision = '1';
  var $si_units = '';

//Labels
  var $draw_data_labels = '0';
  var $legend = '';  //an array
  var $legend_x_pos = '';
  var $legend_y_pos = '';
  var $title_txt = "";
  var $y_label_txt = '';
  var $x_label_txt = "";

//DataAxis Labels (on each axis)
  var $y_grid_label_type = 'data';    //data, none, time, other
  var $y_grid_label_pos = 'plotleft'; //plotleft, plotright, yaxis, both
  var $x_grid_label_type = 'data';    //data, title, none, time, other
  var $draw_x_data_labels = '';       // 0=false, 1=true, ""=let program decide
  var $x_time_format = "%H:%m:%s";    //See http://www.php.net/manual/html/function.strftime.html
  var $x_datalabel_maxlength = 10;

//Tick Formatting
  var $tick_length = '10';   //pixels: tick length from axis left/downward
  //tick_length2 to be implemented
  //var $tick_length2 = '';  //pixels: tick length from axis line rightward/upward
  var $draw_vert_ticks = 1;  //1 = draw ticks, 0 = don't draw ticks
  var $num_vert_ticks = '';
  var $vert_tick_increment=''; //Set num_vert_ticks or vert_tick_increment, not both.
  var $vert_tick_position = 'both'; //plotright=(right of plot only), plotleft=(left of plot only),
                //both = (both left and right of plot), yaxis=(crosses y axis)
  var $horiz_tick_increment=''; //Set num_horiz_ticks or horiz_tick_increment, not both.
  var $num_horiz_ticks='';
  var $skip_top_tick = '0';
  var $skip_bottom_tick = '0';

//Grid Formatting
  var $draw_x_grid = 0;
  var $draw_y_grid = 1;


//BEGIN CODE
//////////////////////////////////////////////////////
  //Constructor: Setup Img pointer, Colors and Size of Image
  function PHPlot($which_width=600,$which_height=400,$which_output_file="",$which_input_file="") {

    $this->SetRGBArray('2');
    $this->background_done = 0; //Set to 1 after background image first drawn

    if ($which_output_file != "") { $this->SetOutputFile($which_output_file);  }

    if ($which_input_file != "") {
      $this->SetInputFile($which_input_file) ;
    } else {
      $this->SetImageArea($which_width, $which_height);
      $this->InitImage();
    }

    if ( ($this->session_set == 1) && ($this->img == "") ) {  //For sessions
      //Do nothing
    } else {
      $this->SetDefaultColors();
    }

    $this->SetIndexColors();

  }

  //Set up the image and colors
  function InitImage() {
    //if ($this->img) {
    //	ImageDestroy($this->img);
    //}
    $this->img = ImageCreate($this->image_width, $this->image_height);
    return true;
  }

  function SetBrowserCache($which_browser_cache) {  //Submitted by Thiemo Nagel
    $this->browser_cache = $which_browser_cache;
    return true;
  }

  function SetPrintImage($which_pi) {
    $this->print_image = $which_pi;
    return true;
  }

  function SetIsInline($which_ii) {
    $this->is_inline = $which_ii;
    return true;
  }

  function SetUseTTF($which_ttf) {
    $this->use_ttf = $which_ttf;
    return true;
  }

  function SetTitleFontSize($which_tfs) {
    //TTF
    $this->title_ttffont_size = $which_tfs; //pt size

    //Non-TTF settings
    if (($which_tfs > 5) && (!$this->use_ttf)) {
      $this->DrawError('Non-TTF font size must be 1,2,3,4 or 5');
      return false;
    } else {
      $this->title_font = $which_tfs;
      //$this->title_font_height = ImageFontHeight($which_tfs) // height in pixels
      //$this->title_font_width = ImageFontWidth($which_tfs); // width in pixels
    }
    return true;
  }

  function SetLineStyles($which_sls){
    $this->line_style = $which_sls;
    return true;
  }

  function SetLegend($which_leg){
    if (is_array($which_leg)) {
      $this->legend = $which_leg;
      return true;
    } else {
      $this->DrawError('Error: SetLegend argument must be an array');
      return false;
    }
  }

  function SetLegendPixels($which_x,$which_y,$which_type) {
    //which_type not yet used
    $this->legend_x_pos = $which_x;
    $this->legend_y_pos = $which_y;
    return true;
  }

  function SetLegendWorld($which_x,$which_y,$which_type='') {
    //which_type not yet used
    //Must be called after scales are set up.
    if ($this->scale_is_set != 1) { $this->SetTranslation(); }
    $this->legend_x_pos = $this->xtr($which_x);
    $this->legend_y_pos = $this->ytr($which_y);
    return true;
  }
/* ***************************************
  function SetFileFormat($which_file_format) { //Only works with PHP4
    $asked = strtolower($which_file_format);
    if( $asked =="jpg" || $asked =="png" || $asked =="gif" || $asked =="wbmp" ) {
      if( $asked=="jpg" && !(imagetypes() & IMG_JPG) )
        return false;
      elseif( $asked=="png" && !(imagetypes() & IMG_PNG) )
        return false;
      elseif( $asked=="gif" && !(imagetypes() & IMG_GIF) )
        return false;
      elseif( $asked=="wbmp" && !(imagetypes() & IMG_WBMP) )
        return false;
      else {
        $this->img_format=$asked;
        return true;
      }
    }
    else
      return false;
  }

*************************************** */
  function SetFileFormat($which_file_format) {
  //eventually test to see if that is supported - if not then return false
    $asked = strtolower(trim($which_file_format));
    if( ($asked=='jpg') || ($asked=='png') || ($asked=='gif') || ($asked=='wbmp') ) {
      $this->file_format = $asked;
      return true;
    } else {
      return false;
    }
  }

  function SetInputFile($which_input_file) {
    //$this->SetFileFormat($which_frmt);
    $size = GetImageSize($which_input_file);
    $input_type = $size[2];

    switch($input_type) {  //After SetFileFormat is in lower case
      case "1":
        $im = @ImageCreateFromGIF ($which_input_file);
        if (!$im) { // See if it failed
          $this->PrintError("Unable to open $which_input_file as a GIF");
          return false;
        }
      break;
      case "3":
        $im = @ImageCreateFromPNG ($which_input_file);
        if (!$im) { // See if it failed
          $this->PrintError("Unable to open $which_input_file as a PNG");
          return false;
        }
      break;
      case "2":
        $im = @ImageCreateFromJPEG ($which_input_file);
        if (!$im) { // See if it failed
          $this->PrintError("Unable to open $which_input_file as a JPG");
          return false;
        }
      break;
      default:
        $this->PrintError('Please select wbmp,gif,jpg, or png for image type!');
        return false;
      break;
    }

    //Get Width and Height of Image
    $this->SetImageArea($size[0],$size[1]);

    $this->img = $im;

    return true;

  }

  function SetOutputFile($which_output_file) {
    $this->output_file = $which_output_file;
    return true;
  }

  function SetImageArea($which_iw,$which_ih) {
    //Note this is now an Internal function - please set w/h via PHPlot()
    $this->image_width = $which_iw;
    $this->image_height = $which_ih;

    return true;
  }


  function SetYAxisPosition($which_pos) {
    $this->y_axis_position = $which_pos;
    return true;
  }
  function SetXAxisPosition($which_pos) {
    $this->x_axis_position = $which_pos;
    return true;
  }
  function SetXTimeFormat($which_xtf) {
    $this->x_time_format = $which_xtf;
    return true;
  }
  function SetXDataLabelMaxlength($which_xdlm) {
    if ($which_xdlm >0 ) {
      $this->x_datalabel_maxlength = $which_xdlm;
      return true;
    } else {
      return false;
    }
  }
  function SetXDataLabelAngle($which_xdla) {
    $this->x_datalabel_angle = $which_xdla;
    return true;
  }
  function SetXScaleType($which_xst) {
    $this->xscale_type = $which_xst;
    return true;
  }
  function SetYScaleType($which_yst) {
    $this->yscale_type = $which_yst;
    if ($this->x_axis_position <= 0) {
      $this->x_axis_position = 1;
    }
    return true;
  }

  function SetPrecisionX($which_prec) {
    $this->x_precision = $which_prec;
    return true;
  }
  function SetPrecisionY($which_prec) {
    $this->y_precision = $which_prec;
    return true;
  }


  function SetIndexColors() { //Internal Method called to set colors and preserve state
    //These are the colors of the image that are used. They are initialized
    //to work with sessions and PHP.

    $this->ndx_i_light = $this->SetIndexColor($this->i_light);
    $this->ndx_i_dark  = $this->SetIndexColor($this->i_dark);
    $this->ndx_bg_color= $this->SetIndexColor($this->bg_color);
    $this->ndx_plot_bg_color= $this->SetIndexColor($this->plot_bg_color);

    $this->ndx_title_color= $this->SetIndexColor($this->title_color);
    $this->ndx_tick_color= $this->SetIndexColor($this->tick_color);
    $this->ndx_label_color= $this->SetIndexColor($this->label_color);
    $this->ndx_text_color= $this->SetIndexColor($this->text_color);
    $this->ndx_light_grid_color= $this->SetIndexColor($this->light_grid_color);
    $this->ndx_grid_color= $this->SetIndexColor($this->grid_color);

    reset($this->error_bar_color);
    unset($ndx_error_bar_color);
    $i = 0;
    while (list(, $col) = each($this->error_bar_color)) {
      $this->ndx_error_bar_color[$i] = $this->SetIndexColor($col);
      $i++;
    }
    //reset($this->data_border_color);
    unset($ndx_data_border_color);
    $i = 0;
    while (list(, $col) = each($this->data_border_color)) {
      $this->ndx_data_border_color[$i] = $this->SetIndexColor($col);
      $i++;
    }
    //reset($this->data_color);
    unset($ndx_data_color);
    $i = 0;
    while (list(, $col) = each($this->data_color)) {
      $this->ndx_data_color[$i] = $this->SetIndexColor($col);
      $i++;
    }

    return true;
  }


  function SetDefaultColors() {

    $this->i_light = array(194,194,194);
    $this->i_dark =  array(100,100,100);
    $this->SetPlotBgColor(array(222,222,222));
    $this->SetBackgroundColor(array(200,222,222)); //can use rgb values or "name" values
    $this->SetLabelColor('black');
    $this->SetTextColor('black');
    $this->SetGridColor('black');
    $this->SetLightGridColor(array(175,175,175));
    $this->SetTickColor('black');
    $this->SetTitleColor(array(0,0,0)); // Can be array or name
    $this->data_color = array('blue','green','yellow','red','orange');
    $this->error_bar_color = array('blue','green','yellow','red','orange');
    $this->data_border_color = array('black');

    $this->session_set = 1; //Mark it down for PHP session() usage.
  }

  function PrintImage() {

    if ( ($this->browser_cache == 0) && ($this->is_inline == 0)) { //Submitted by Thiemo Nagel
      header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
      header('Last-Modified: ' . gmdate("D, d M Y H:i:s") . 'GMT');
      header('Cache-Control: no-cache, must-revalidate');
      header('Pragma: no-cache');
    }

    switch($this->file_format) {
      case "png":
        if ($this->is_inline == 0) {
          Header('Content-type: image/png');
        }
        if ($this->is_inline == 1 && $this->output_file != "") {
          ImagePng($this->img,$this->output_file);
        } else {
          ImagePng($this->img);
        }
        break;
      case "jpg":
        if ($this->is_inline == 0) {
          Header('Content-type: image/jpeg');
        }
        if ($this->is_inline == 1 && $this->output_file != "") {
          ImageJPEG($this->img,$this->output_file);
        } else {
          ImageJPEG($this->img);
        }
        break;
      case "gif":
        if ($this->is_inline == 0) {
          Header('Content-type: image/gif');
        }
        if ($this->is_inline == 1 && $this->output_file != "") {
          ImageGIF($this->img,$this->output_file);
        } else {
          ImageGIF($this->img);
        }

        break;
      case "wbmp":
        if ($this->is_inline == 0) {
          Header('Content-type: image/wbmp');
        }
        if ($this->is_inline == 1 && $this->output_file != "") {
          ImageWBMP($this->img,$this->output_file);
        } else {
          ImageWBMP($this->img);
        }

        break;
      default:
        $this->PrintError('Please select an image type!<br>');
        break;
    }
    ImageDestroy($this->img);
    return true;
  }


  function DrawBackground() {
    //if ($this->img == "") { $this->InitImage(); }
    if ($this->background_done == 0) { //Don't draw it twice if drawing two plots on one image
      ImageFilledRectangle($this->img, 0, 0,
        $this->image_width, $this->image_height, $this->ndx_bg_color);
      $this->background_done = 1;
    }
    return true;
  }

  function DrawImageBorder() {
    switch ($this->image_border_type) {
      case "raised":
        ImageLine($this->img,0,0,$this->image_width-1,0,$this->ndx_i_light);
        ImageLine($this->img,1,1,$this->image_width-2,1,$this->ndx_i_light);
        ImageLine($this->img,0,0,0,$this->image_height-1,$this->ndx_i_light);
        ImageLine($this->img,1,1,1,$this->image_height-2,$this->ndx_i_light);
        ImageLine($this->img,$this->image_width-1,0,$this->image_width-1,$this->image_height-1,$this->ndx_i_dark);
        ImageLine($this->img,0,$this->image_height-1,$this->image_width-1,$this->image_height-1,$this->ndx_i_dark);
        ImageLine($this->img,$this->image_width-2,1,$this->image_width-2,$this->image_height-2,$this->ndx_i_dark);
        ImageLine($this->img,1,$this->image_height-2,$this->image_width-2,$this->image_height-2,$this->ndx_i_dark);
      break;
      case "plain":
        ImageLine($this->img,0,0,$this->image_width,0,$this->ndx_i_dark);
        ImageLine($this->img,$this->image_width-1,0,$this->image_width-1,$this->image_height,$this->ndx_i_dark);
        ImageLine($this->img,$this->image_width-1,$this->image_height-1,0,$this->image_height-1,$this->ndx_i_dark);
        ImageLine($this->img,0,0,0,$this->image_height,$this->ndx_i_dark);
      break;
      default:
      break;
    }
    return true;
  }

  function SetPlotBorderType($which_pbt) {
    $this->plot_border_type = $which_pbt; //left, none, anything else=full
  }

  function SetImageBorderType($which_sibt) {
    $this->image_border_type = $which_sibt; //raised, plain
  }

  function SetDrawPlotAreaBackground($which_dpab) {
    $this->draw_plot_area_background = $which_dpab;  // 1=true or anything else=false
  }

  function SetDrawDataLabels($which_ddl) {  //Draw next to datapoints
    $this->draw_data_labels = $which_ddl;  // 1=true or anything else=false
  }

  function SetDrawXDataLabels($which_dxdl) {  //Draw on X Axis
    $this->draw_x_data_labels = $which_dxdl;  // 1=true or anything else=false
  }

  function SetDrawYGrid($which_dyg) {
    $this->draw_y_grid = $which_dyg;  // 1=true or anything else=false
  }

  function SetDrawXGrid($which_dxg) {
    $this->draw_x_grid = $which_dxg;  // 1=true or anything else=false
  }

  function SetYGridLabelType($which_yglt) {
    $this->y_grid_label_type = $which_yglt;
    return true;
  }

  function SetXGridLabelType($which_xglt) {
    $this->x_grid_label_type = $which_xglt;
    return true;
  }

  function SetXLabel($xlbl) {
    $this->x_label_txt = $xlbl;
    return true;
  }
  function SetYLabel($ylbl) {
    $this->y_label_txt = $ylbl;
    return true;
  }
  function SetTitle($title) {
    $this->title_txt = $title;
    return true;
  }

  //function SetLabels($xlbl,$ylbl,$title) {
  //	$this->title_txt = $title;
  //	$this->x_label_txt = $xlbl;
  //	$this->y_label_txt = $ylbl;
  //}

  function DrawLabels() {
    $this->DrawTitle();
    $this->DrawXLabel();
    $this->DrawYLabel();
    return true;
  }

  function DrawXLabel() {
    if ($this->use_ttf == 1) {
      $xpos = $this->xtr(($this->plot_max_x + $this->plot_min_x)/2.0) ;
      $ypos = $this->ytr($this->plot_min_y) + $this->x_label_height/2.0;
      $this->DrawText($this->x_label_ttffont, $this->x_label_angle,
        $xpos, $ypos, $this->ndx_label_color, $this->x_label_ttffont_size, $this->x_label_txt,'center');
    } else {
      //$xpos = 0.0 - (ImageFontWidth($this->small_font)*strlen($this->x_label_txt)/2.0) + $this->xtr(($this->plot_max_x+$this->plot_min_x)/2.0) ;
      $xpos = 0.0 + $this->xtr(($this->plot_max_x+$this->plot_min_x)/2.0) ;
      $ypos = ($this->ytr($this->plot_min_y) + $this->x_label_height/2);

      $this->DrawText($this->small_font, $this->x_label_angle,
        $xpos, $ypos, $this->ndx_label_color, "", $this->x_label_txt, 'center');

    }
    return true;
  }

  function DrawYLabel() {
    if ($this->use_ttf == 1) {
      $size = $this->TTFBBoxSize($this->y_label_ttffont_size, 90, $this->y_label_ttffont, $this->y_label_txt);
      $xpos = 8 + $size[0];
      $ypos = ($size[1])/2 + $this->ytr(($this->plot_max_y + $this->plot_min_y)/2.0) ;
      $this->DrawText($this->y_label_ttffont, 90,
        $xpos, $ypos, $this->ndx_label_color, $this->y_label_ttffont_size, $this->y_label_txt);
    } else {
      $xpos = 8;
      $ypos = (($this->small_font_width*strlen($this->y_label_txt)/2.0) +
          $this->ytr(($this->plot_max_y + $this->plot_min_y)/2.0) );
      $this->DrawText($this->small_font, 90,
        $xpos, $ypos, $this->ndx_label_color, $this->y_label_ttffont_size, $this->y_label_txt);
    }
    return true;
  }

  function DrawText($which_font,$which_angle,$which_xpos,$which_ypos,$which_color,$which_size,$which_text,$which_halign='left',$which_valign='') {
    if ($this->use_ttf == 1 ) {
      $size = $this->TTFBBoxSize($which_size, $which_angle, $which_font, $which_text);
      if ($which_valign == 'bottom') {
        $which_ypos = $which_ypos + ImageFontHeight($which_font);
      }
      if ($which_halign == 'center') {
        $which_xpos = $which_xpos - $size[0]/2;
      }
      ImageTTFText($this->img, $which_size, $which_angle,
        $which_xpos, $which_ypos, $which_color, $which_font, $which_text);
    } else {
      if ($which_valign == 'top') {
        $which_ypos = $which_ypos - ImageFontHeight($which_font);
      }
      $which_text = preg_replace("/\r/","",$which_text);
      $str = preg_split("/\n/",$which_text); //multiple lines submitted by Remi Ricard
      $height = ImageFontHeight($which_font);
      $width = ImageFontWidth($which_font);
      if ($which_angle == 90) {  //Vertical Code Submitted by Marlin Viss
        for($i=0;$i<count($str);$i++) {
          ImageStringUp($this->img, $which_font, ($i*$height + $which_xpos), $which_ypos, $str[$i], $which_color);
        }
      } else {
        for($i=0;$i<count($str);$i++) {
          if ($which_halign == 'center') {
                      $xpos = $which_xpos - strlen($str[$i]) * $width/2;
             ImageString($this->img, $which_font, $xpos, ($i*$height + $which_ypos), $str[$i], $which_color);
          } else {
            ImageString($this->img, $which_font, $which_xpos, ($i*$height + $which_ypos), $str[$i], $which_color);
          }
        }
      }

    }
    return true;

  }
  function DrawTitle() {
    if ($this->use_ttf == 1 ) {
      $xpos = ($this->plot_area[0] + $this->plot_area_width / 2);
      $ypos = $this->y_top_margin/2;
      $this->DrawText($this->title_ttffont, $this->title_angle,
        $xpos, $ypos, $this->ndx_title_color, $this->title_ttffont_size, $this->title_txt,'center');
    } else {
      $xpos = ($this->plot_area[0] + $this->plot_area_width / 2);
      $ypos = ImageFontHeight($this->title_font);
      $this->DrawText($this->title_font, $this->title_angle,
        $xpos, $ypos, $this->ndx_title_color, '', $this->title_txt,'center');
    }
    return true;

  }

  function DrawPlotAreaBackground() {
    ImageFilledRectangle($this->img,$this->plot_area[0],
      $this->plot_area[1],$this->plot_area[2],$this->plot_area[3],
      $this->ndx_plot_bg_color);
  }

  function SetBackgroundColor($which_color) {
    $this->bg_color= $which_color;
    $this->ndx_bg_color= $this->SetIndexColor($which_color);
    return true;
  }
  function SetPlotBgColor($which_color) {
    $this->plot_bg_color= $which_color;
    $this->ndx_plot_bg_color= $this->SetIndexColor($which_color);
    return true;
  }

  function SetShading($which_s) {
    $this->shading = $which_s;
    return true;
  }

  function SetTitleColor($which_color) {
    $this->title_color= $which_color;
    $this->ndx_title_color= $this->SetIndexColor($which_color);
    return true;
  }

  function SetTickColor ($which_color) {
    $this->tick_color= $which_color;
    $this->ndx_tick_color= $this->SetIndexColor($which_color);
    return true;
  }

  function SetLabelColor ($which_color) {
    $this->label_color= $which_color;
    $this->ndx_label_color= $this->SetIndexColor($which_color);
    return true;
  }

  function SetTextColor ($which_color) {
    $this->text_color= $which_color;
    $this->ndx_text_color= $this->SetIndexColor($which_color);
    return true;
  }

  function SetLightGridColor ($which_color) {
    $this->light_grid_color= $which_color;
    $this->ndx_light_grid_color= $this->SetIndexColor($which_color);
    return true;
  }

  function SetGridColor ($which_color) {
    $this->grid_color = $which_color;
    $this->ndx_grid_color= $this->SetIndexColor($which_color);
    return true;
  }

  function SetCharacterHeight() {
    //to be set
    return true;
  }

  function SetPlotType($which_pt) {
    $accepted = "bars,lines,linepoints,area,points,pie,thinbarline";
    $asked = trim($which_pt);
    if (preg_match('/' . $asked . '/i', $accepted)) {
      $this->plot_type = $which_pt;
      return true;
    } else {
      $this->DrawError('$which_pt not an acceptable plot type');
      return false;
    }
  }

  function FindDataLimits() {
    //Text-Data is different than data-data graphs. For them what
    // we have, instead of X values, is # of records equally spaced on data.
    //text-data is passed in as $data[] = (title,y1,y2,y3,y4,...)
    //data-data is passed in as $data[] = (title,x,y1,y2,y3,y4,...)

    $this->number_x_points = count($this->data_values);

    switch ($this->data_type) {
      case "text-data":
        $minx = 0; //valid for BAR TYPE GRAPHS ONLY
        $maxx = $this->number_x_points - 1 ;  //valid for BAR TYPE GRAPHS ONLY
        $miny = (double) $this->data_values[0][1];
        $maxy = $miny;
        if ($this->draw_x_data_labels == "") {
          $this->draw_x_data_labels = 1;  //labels_note1: prevent both data labels and x-axis labels being both drawn and overlapping
        }
      break;
      default:  //Everything else: data-data, etc.
        $maxx = $this->data_values[0][1];
        $minx = $maxx;
        $miny = $this->data_values[0][2];
        $maxy = $miny;
        $maxy = $miny;
      break;
    }

    $max_records_per_group = 0;
    $total_records = 0;
    $mine = 0; //Maximum value for the -error bar (assume error bars always > 0)
    $maxe = 0; //Maximum value for the +error bar (assume error bars always > 0)

    reset($this->data_values);
    while (list($dat_key, $dat) = each($this->data_values)) {  //for each X barchart setting
    //foreach($this->data_values as $dat)  //can use foreach only in php4

      $tmp = 0;
      $total_records += count($dat) - 1; // -1 for label

      switch ($this->data_type) {
        case "text-data":
          //Find the relative Max and Min

          while (list($key, $val) = each($dat)) {
            if ($key != 0) {  //$dat[0] = label
              SetType($val,"double");
              if ($val > $maxy) {
                $maxy = $val ;
              }
              if ($val < $miny) {
                $miny = (double) $val ;
              }
            }
            $tmp++;
          }
        break;
        case "data-data":  //X-Y data is passed in as $data[] = (title,x,y,y2,y3,...) which you can use for multi-dimentional plots.

          while (list($key, $val) = each($dat)) {
            if ($key == 1) {  //$dat[0] = label
              SetType($val,"double");
              if ($val > $maxx) {
                $maxx = $val;
              } elseif ($val < $minx) {
                $minx = $val;
              }
            } elseif ($key > 1) {
              SetType($val,"double");
              if ($val > $maxy) {
                $maxy = $val ;
              } elseif ($val < $miny) {
                $miny = $val ;
              }
            }
            $tmp++;
          }
          $tmp = $tmp - 1; //# records per group
        break;
        case "data-data-error":  //Assume 2-D for now, can go higher
        //Regular X-Y data is passed in as $data[] = (title,x,y,error+,error-,y2,error2+,error2-)

          while (list($key, $val) = each($dat)) {
            if ($key == 1) {  //$dat[0] = label
              SetType($val,'double');
              if ($val > $maxx) {
                $maxx = $val;
              } elseif ($val < $minx) {
                $minx = $val;
              }
            } elseif ($key%3 == 2) {
              SetType($val,'double');
              if ($val > $maxy) {
                $maxy = $val ;
              } elseif ($val < $miny) {
                $miny = $val ;
              }
            } elseif ($key%3 == 0) {
              SetType($val,'double');
              if ($val > $maxe) {
                $maxe = $val ;
              }
            } elseif ($key%3 == 1) {
              SetType($val,'double');
              if ($val > $mine) {
                $mine = $val ;
              }
            }
            $tmp++;
          }
          $maxy = $maxy + $maxe;
          $miny = $miny - $mine; //assume error bars are always > 0

        break;
        default:
          $this->PrintError('ERROR: unknown chart type');
        break;
      }
      if ($tmp > $max_records_per_group) {
        $max_records_per_group = $tmp;
      }
    }


    $this->min_x = $minx;
    $this->max_x = $maxx;
    $this->min_y = $miny;
    $this->max_y = $maxy;


    if ($max_records_per_group > 1) {
      $this->records_per_group = $max_records_per_group - 1;
    } else {
      $this->records_per_group = 1;
    }


    //$this->data_count = $total_records ;
  } // function FindDataLimits

  function SetMargins() {
    /////////////////////////////////////////////////////////////////
    // When the image is first created - set the margins
    // to be the standard viewport.
    // The standard viewport is the full area of the view surface (or panel),
    // less a margin of 4 character heights all round for labelling.
    // It thus depends on the current character size, set by SetCharacterHeight().
    /////////////////////////////////////////////////////////////////

    $str = preg_split("/\n/",$this->title_txt);
    $nbLines = count($str);

    if ($this->use_ttf == 1) {
      $title_size = $this->TTFBBoxSize($this->title_ttffont_size, $this->title_angle, $this->title_ttffont, 'X'); //An array
      if ($nbLines == 1) {
        $this->y_top_margin = $title_size[1] * 4;
      } else {
        $this->y_top_margin = $title_size[1] * ($nbLines+3);
      }

      //ajo working here
      //$x_label_size = $this->TTFBBoxSize($this->x_label_ttffont_size, 0, $this->axis_ttffont, $this->x_label_txt);

      $this->y_bot_margin = $this->x_label_height ;
      $this->x_left_margin = $this->y_label_width * 2 + $this->tick_length;
      $this->x_right_margin = 33.0; // distance between right and end of x axis in pixels
    } else {
      $title_size = array(ImageFontWidth($this->title_font) * strlen($this->title_txt),ImageFontHeight($this->title_font));
      //$this->y_top_margin = ($title_size[1] * 4);
      if ($nbLines == 1) {
        $this->y_top_margin = $title_size[1] * 4;
      } else {
        $this->y_top_margin = $title_size[1] * ($nbLines+3);
      }
      if ($this->x_datalabel_angle == 90) {
        $this->y_bot_margin = 76.0; // Must be integer
      } else {
        $this->y_bot_margin = 66.0; // Must be integer
      }
      $this->x_left_margin = 77.0; // distance between left and start of x axis in pixels
      $this->x_right_margin = 33.0; // distance between right and end of x axis in pixels
    }

//exit;
    $this->x_tot_margin = $this->x_left_margin + $this->x_right_margin;
    $this->y_tot_margin = $this->y_top_margin + $this->y_bot_margin;

    if ($this->plot_max_x && $this->plot_max_y && $this->plot_area_width ) { //If data has already been analysed then set translation
      $this->SetTranslation();
    }
  }

  function SetMarginsPixels($which_lm,$which_rm,$which_tm,$which_bm) {
    //Set the plot area using margins in pixels (left, right, top, bottom)
    $this->SetNewPlotAreaPixels($which_lm,$which_tm,($this->image_width - $which_rm),($this->image_height - $which_bm));
    return true;
  }

  function SetNewPlotAreaPixels($x1,$y1,$x2,$y2) {
    //Like in GD 0,0 is upper left set via pixel Coordinates
    $this->plot_area = array($x1,$y1,$x2,$y2);
    $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0];
    $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1];
    $this->y_top_margin = $this->plot_area[1];
    if ($this->plot_max_x) {
      $this->SetTranslation();
    }
    return true;
  }

  function SetPlotAreaPixels($x1,$y1,$x2,$y2) {
    //Like in GD 0,0 is upper left
    if (!$this->x_tot_margin) {
      $this->SetMargins();
    }
    if ($x2 && $y2) {
      $this->plot_area = array($x1,$y1,$x2,$y2);
    } else {
      $this->plot_area = array($this->x_left_margin, $this->y_top_margin,
                $this->image_width - $this->x_right_margin,
                $this->image_height - $this->y_bot_margin
              );
    }
    $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0];
    $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1];

    return true;

  }

  function SetPlotAreaWorld($xmin,$ymin,$xmax,$ymax) {
    if (($xmin == "")  && ($xmax == "")) {
      //For automatic setting of data we need $this->max_x
        if (!$this->max_y) {
          $this->FindDataLimits() ;
        }
        if ($this->data_type == 'text-data') { //labels for text-data is done at data drawing time for speed.
          $xmax = $this->max_x + 1 ;  //valid for BAR CHART TYPE GRAPHS ONLY
          $xmin = 0 ; 				//valid for BAR CHART TYPE GRAPHS ONLY
        } else {
          $xmax = $this->max_x * 1.02;
          $xmin = $this->min_x;
        }

        $ymax = ceil($this->max_y * 1.2);
        if ($this->min_y < 0) {
          $ymin = floor($this->min_y * 1.2);
        } else {
          $ymin = 0;
        }
    }

    $this->plot_min_x = $xmin;
    $this->plot_max_x = $xmax;

    if ($ymin == $ymax) {
      $ymax += 1;
    }
    if ($this->yscale_type == "log") {
      //extra error checking
      if ($ymin <= 0) {
        $ymin = 1;
      }
      if ($ymax <= 0) {
        $this->PrintError('Log plots need data greater than 0');
      }
    }
    $this->plot_min_y = $ymin;
    $this->plot_max_y = $ymax;

    if ($ymax <= $ymin) {
      $this->DrawError('Error in Data - max not gt min');
    }

//Set the boundaries of the box for plotting in world coord
//		if (!$this->x_tot_margin) { //We need to know the margins before we can calculate scale
//			$this->SetMargins();
//		}
    //For this we have to reset the scale
    if ($this->plot_area_width) {
      $this->SetTranslation();
    }

    return true;

  } //function SetPlotAreaWorld


  function PrintError($error_message) {
  // prints the error message to stdout and die
    echo "<p><b>Fatal error</b>: $error_message<p>";
    die;
  }

  function DrawError($error_message) {
  // prints the error message inline into
  // the generated image

    if (($this->img) == "") { $this->InitImage(); } ;

    $ypos = $this->image_height/2;

    if ($this->use_ttf == 1) {
      ImageRectangle($this->img, 0,0,$this->image_width,$this->image_height,ImageColorAllocate($this->img,255,255,255));
      ImageTTFText($this->img, $this->small_ttffont_size, 0, $xpos, $ypos, ImageColorAllocate($this->img,0,0,0), $this->axis_ttffont, $error_message);
    } else {
      ImageRectangle($this->img, 0,0,$this->image_width,$this->image_height,ImageColorAllocate($this->img,255,255,255));
      ImageString($this->img, $this->small_font,1,$ypos,$error_message, ImageColorAllocate($this->img,0,0,0));
    }

    $this->PrintImage();
    return true;
  }

  function TTFBBoxSize($size, $angle, $font, $string) {

    //Assume angle < 90
    $arr = ImageTTFBBox($size, 0, $font, $string);
    $flat_width  = $arr[0] - $arr[2];
    $flat_height = abs($arr[3] - $arr[5]);

      // for 90deg:
      //	$height = $arr[5] - $arr[7];
      //	$width = $arr[2] - $arr[4];

    $angle = deg2rad($angle);
    $width  = ceil(abs($flat_width*cos($angle) + $flat_height*sin($angle))); //Must be integer
    $height = ceil(abs($flat_width*sin($angle) + $flat_height*cos($angle))); //Must be integer

    return array($width, $height);
  }

  function SetXLabelHeight() {

    if ($this->use_ttf == 1) {
      //Space for the X Label
      $size = $this->TTFBBoxSize($this->x_label_ttffont_size, 0, $this->axis_ttffont, $this->x_label_txt);
      $tmp = $size[1];

      //$string = Str_Repeat('w', $this->x_datalabel_maxlength);
      $i = 0;
      $string = '';
      while ($i < $this->x_datalabel_maxlength) {
        $string .= 'w';
        $i++;
      }

      //Space for the axis data labels
      $size = $this->TTFBBoxSize($this->axis_ttffont_size, $this->x_datalabel_angle, $this->axis_ttffont, $string);

      $this->x_label_height = 2*$tmp + $size[1] + 4;

    } else {
      //For Non-TTF fonts we can have only angles 0 or 90
      if ($this->x_datalabel_angle == 90) {
        $this->x_label_height = $this->x_datalabel_maxlength * ImageFontWidth($this->small_font) / 1.5;
      } else {
        $this->x_label_height = 5 * ImageFontHeight($this->small_font);
      }
    }

    $this->SetMargins();

    return true;
  } //function SetXLabelHeight

  function SetYLabelWidth() {
    //$ylab = sprintf("%6.1f %s",$i,$si_units[0]);  //use for PHP2 compatibility
    //the "." is for space. It isn't actually printed
    $ylab = number_format($this->max_y, $this->y_precision, ".", ",") . $this->si_units . ".";

    if ($this->use_ttf == 1) {
      $size = $this->TTFBBoxSize($this->axis_ttffont_size, 0, $this->axis_ttffont, $ylab);
    } else {
      $size[0] = StrLen($ylab) * $this->small_font_width * .6;
    }

    $this->y_label_width = $size[0] * 2;
//echo "SYLW: $this->y_label_width<br>";
//exit;

    $this->SetMargins();
    return true;
  }

  function SetEqualXCoord() {
    //for plots that have equally spaced x variables and multiple bars per x-point.

    $space = ($this->plot_area[2] - $this->plot_area[0]) / ($this->number_x_points * 2) * $this->group_frac_width;
    $group_width = $space * 2;
    $bar_width = $group_width / $this->records_per_group;
  //I think that eventually this space variable will be replaced by just graphing x.
    $this->data_group_space = $space;
    $this->record_bar_width = $bar_width;
    return true;
  }

  function SetLabelScalePosition($which_blp) {
    //0 to 1
    $this->label_scale_position = $which_blp;
    return true;
  }

  function SetErrorBarSize($which_ebs) {
    //in pixels
    $this->error_bar_size = $which_ebs;
    return true;
  }

  function SetErrorBarShape($which_ebs) {
    //in pixels
    $this->error_bar_shape = $which_ebs;
    return true;
  }

  function SetPointShape($which_pt) {
    //in pixels
    $this->point_shape = $which_pt;
    return true;
  }

  function SetPointSize($which_ps) {
    //in pixels
    SetType($which_ps,'integer');
    $this->point_size = $which_ps;

    if ($this->point_shape == "diamond" or $this->point_shape == "triangle") {
      if ($this->point_size % 2 != 0) {
        $this->point_size++;
      }
    }
    return true;
  }

  function SetDataType($which_dt) {
    //The next three lines are for past compatibility.
    if ($which_dt == "text-linear") { $which_dt = "text-data"; }
    if ($which_dt == "linear-linear") { $which_dt = "data-data"; }
    if ($which_dt == "linear-linear-error") { $which_dt = "data-data-error"; }

    $this->data_type = $which_dt; //text-data, data-data, data-data-error
    return true;
  }

  function SetDataValues($which_dv) {
    $this->data_values = $which_dv;
//echo $this->data_values
    return true;
  }

//////////////COLORS
  function SetRGBArray ($which_color_array) {
    if ( is_array($which_color_array) ) {
      //User Defined Array
      $this->rgb_array = $which_color_array;
      return true;
    } elseif ($which_color_array == 2) { //Use the small predefined color array
    $this->rgb_array = array(
      "white"			=> array(255, 255, 255),
      "snow"			=> array(255, 250, 250),
      "PeachPuff"		=> array(255, 218, 185),
      "ivory"			=> array(255, 255, 240),
      "lavender"		=> array(230, 230, 250),
      "black"			=> array(  0,   0,   0),
      "DimGrey"			=> array(105, 105, 105),
      "gray"			=> array(190, 190, 190),
      "grey"			=> array(190, 190, 190),
      "navy"			=> array(  0,   0, 128),
      "SlateBlue"			=> array(106,  90, 205),
      "blue"			=> array(  0,   0, 255),
      "SkyBlue"			=> array(135, 206, 235),
      "cyan"			=> array(  0, 255, 255),
      "DarkGreen"			=> array(  0, 100,   0),
      "green"			=> array(  0, 255,   0),
      "YellowGreen"			=> array(154, 205,  50),
      "yellow"			=> array(255, 255,   0),
      "orange"			=> array(255, 165,   0),
      "gold"			=> array(255, 215,   0),
      "peru"			=> array(205, 133,  63),
      "beige"			=> array(245, 245, 220),
      "wheat"			=> array(245, 222, 179),
      "tan"			=> array(210, 180, 140),
      "brown"			=> array(165,  42,  42),
      "salmon"			=> array(250, 128, 114),
      "red"			=> array(255,   0,   0),
      "pink"			=> array(255, 192, 203),
      "maroon"			=> array(176,  48,  96),
      "magenta"			=> array(255,   0, 255),
      "violet"			=> array(238, 130, 238),
      "plum"			=> array(221, 160, 221),
      "orchid"			=> array(218, 112, 214),
      "purple"			=> array(160,  32, 240),
      "azure1"			=> array(240, 255, 255),
      "aquamarine1"		=> array(127, 255, 212)
      );
      return true;
    } elseif ($which_color_array == 1)  {
      include("./rgb.inc.php"); //Get large $ColorArray
      $this->rgb_array = $RGBArray;
    } else {
      $this->rgb_array = array("white" =>array(255,255,255), "black" => array(0,0,0));
      exit;
    }

    return true;
  }

  function SetColor($which_color) {
    //obsoleted by SetRGBColor
    SetRgbColor($which_color);
    return true;
  }

  function SetIndexColor($which_color) { //Color is passed in as anything
      list ($r, $g, $b) = $this->SetRgbColor($which_color);  //Translate to RGB
    $index = ImageColorExact($this->img, $r, $g, $b);
    if ($index == -1) {
          //return ImageColorAllocate($this->img, $r, $g, $b);
          //return ImageColorClosest($this->img, $r, $g, $b);
          return ImageColorResolve($this->img, $r, $g, $b); //requires PHP 3.0.2 and later
     } else {
          return $index;
      }
  }

  function SetTransparentColor($which_color) {
    ImageColorTransparent($this->img,$this->SetIndexColor($which_color));
    return true;
  }

  function SetRgbColor($color_asked) {
    //Returns an array in R,G,B format 0-255
    if ($color_asked == "") { $color_asked = array(0,0,0); }

    if ( count($color_asked) == 3 ) { //already array of 3 rgb
         $ret_val =  $color_asked;
    } else { // is asking for a color by string
      if(substr($color_asked,0,1) == "#") {  //asking in #FFFFFF format.
        $ret_val =  array(hexdec(substr($color_asked,1,2)), hexdec(substr($color_asked,3,2)), hexdec(substr($color,5,2)));
      } else {
        $ret_val =  $this->rgb_array[$color_asked];
      }
    }
    return $ret_val;
  }

  function SetDataColors($which_data,$which_border) {
    //Set the data to be displayed in a particular color
    if (!$which_data) {
      $which_data = array(array(0,255,0),array(0,0,248),'yellow',array(255,0,0),'orange');
      $which_border = array('black');
    }

    $this->data_color = $which_data;  //an array
    $this->data_border_color = $which_border;  //an array

    unset($this->ndx_data_color);
    reset($this->data_color);  //data_color can be an array of colors, one for each thing plotted
    //while (list(, $col) = each($this->data_color))
    $i = 0;
    while (list(, $col) = each($which_data)) {
      $this->ndx_data_color[$i] = $this->SetIndexColor($col);
      $i++;
    }

    // border_color
    //If we are also going to put a border on the data (bars, dots, area, ...)
    //	then lets also set a border color as well.
    //foreach($this->data_border_color as $col)
    unset($this->ndx_data_border_color);
    reset($this->data_border_color);
    $i = 0;
    while (list(, $col) = each($this->data_border_color)) {
      $this->ndx_data_border_color[$i] = $this->SetIndexColor($col);
      $i++;
    }

    //Set color of the error bars to be that of data if not already set.
    if (!$this->error_bar_color) {
        reset($which_data);
        $this->SetErrorBarColors($which_data);
    }

    return true;

  } //function SetDataColors

  function SetErrorBarColors($which_data) {

   //Set the data to be displayed in a particular color

   if ($which_data) {
    $this->error_bar_color = $which_data;  //an array
    unset($this->ndx_error_bar_color);
    reset($this->error_bar_color);  //data_color can be an array of colors, one for each thing plotted
    $i = 0;
    while (list(, $col) = each($this->error_bar_color)) {
      $this->ndx_error_bar_color[$i] = $this->SetIndexColor($col);
      $i++;
    }
    return true;
    }
    return false;
  } //function SetErrorBarColors


  function DrawPlotBorder() {
    switch ($this->plot_border_type) {
      case "left" :
        ImageLine($this->img, $this->plot_area[0],$this->ytr($this->plot_min_y),
          $this->plot_area[0],$this->ytr($this->plot_max_y),$this->ndx_grid_color);
      break;
      case "none":
        //Draw No Border
      break;
      default:
        ImageRectangle($this->img, $this->plot_area[0],$this->ytr($this->plot_min_y),
          $this->plot_area[2],$this->ytr($this->plot_max_y),$this->ndx_grid_color);
      break;
    }
    $this->DrawYAxis();
    $this->DrawXAxis();
    return true;
  }


  function SetHorizTickIncrement($which_ti) {
    //Use either this or NumHorizTicks to set where to place x tick marks
    if ($which_ti) {
      $this->horiz_tick_increment = $which_ti;  //world coordinates
    } else {
      if (!$this->max_x) {
        $this->FindDataLimits();  //Get maxima and minima for scaling
      }
      //$this->horiz_tick_increment = ( ceil($this->max_x * 1.2) - floor($this->min_x * 1.2) )/10;
      $this->horiz_tick_increment =  ($this->plot_max_x  - $this->plot_min_x  )/10;
    }
    $this->num_horiz_ticks = ''; //either use num_vert_ticks or vert_tick_increment, not both
    return true;
  }

  function SetDrawVertTicks($which_dvt) {
    $this->draw_vert_ticks = $which_dvt;
    return true;
  }

  function SetVertTickIncrement($which_ti) {
    //Use either this or NumVertTicks to set where to place y tick marks
    if ($which_ti) {
      $this->vert_tick_increment = $which_ti;  //world coordinates
    } else {
      if (!$this->max_y) {
        $this->FindDataLimits();  //Get maxima and minima for scaling
      }
      //$this->vert_tick_increment = ( ceil($this->max_y * 1.2) - floor($this->min_y * 1.2) )/10;
      $this->vert_tick_increment =  ($this->plot_max_y  - $this->plot_min_y  )/10;
    }
    $this->num_vert_ticks = ''; //either use num_vert_ticks or vert_tick_increment, not both
    return true;
  }

  function SetNumHorizTicks($which_nt) {
    $this->num_horiz_ticks = $which_nt;
    $this->horiz_tick_increment = '';  //either use num_horiz_ticks or horiz_tick_increment, not both
    return true;
  }

  function SetNumVertTicks($which_nt) {
    $this->num_vert_ticks = $which_nt;
    $this->vert_tick_increment = '';  //either use num_vert_ticks or vert_tick_increment, not both
    return true;
  }
  function SetVertTickPosition($which_tp) {
    $this->vert_tick_position = $which_tp; //plotleft, plotright, both, yaxis
    return true;
  }
  function SetSkipBottomTick($which_sbt) {
    $this->skip_bottom_tick = $which_sbt;
    return true;
  }

  function SetTickLength($which_tl) {
    $this->tick_length = $which_tl;
    return true;
  }

  function DrawYAxis() {
    //Draw Line at left side or at this->y_axis_position
    if ($this->y_axis_position != "") {
      $yaxis_x = $this->xtr($this->y_axis_position);
    } else {
      $yaxis_x = $this->plot_area[0];
    }

    ImageLine($this->img, $yaxis_x, $this->plot_area[1],
      $yaxis_x, $this->plot_area[3], $this->ndx_grid_color);
      //$yaxis_x, $this->plot_area[3], 9);

    if ($this->draw_vert_ticks == 1) {
      $this->DrawVerticalTicks();
    }

  } //function DrawYAxis

  function DrawXAxis() {
    //Draw Tick and Label for Y axis
    $ylab =$this->FormatYTickLabel($this->x_axis_position);
    if ($this->skip_bottom_tick != 1) {
      $this->DrawVerticalTick($ylab,$this->x_axis_position);
    }

    //Draw X Axis at Y=$x_axis_postion
    ImageLine($this->img,$this->plot_area[0]+1,$this->ytr($this->x_axis_position),
        $this->xtr($this->plot_max_x)-1,$this->ytr($this->x_axis_position),$this->ndx_tick_color);

    //X Ticks and Labels
    if ($this->data_type != 'text-data') { //labels for text-data done at data drawing time for speed.
      $this->DrawHorizontalTicks();
    }
    return true;
  }

  function DrawHorizontalTicks() {
    //Ticks and lables are drawn on the left border of PlotArea.
    //Left Bottom
    ImageLine($this->img,$this->plot_area[0],
        $this->plot_area[3]+$this->tick_length,
        $this->plot_area[0],$this->plot_area[3],$this->ndx_tick_color);

    switch ($this->x_grid_label_type) {
      case "title":
        $xlab = $this->data_values[0][0];
      break;
      case "data":
        $xlab = number_format($this->plot_min_x,$this->x_precision,".",",") . "$this->si_units";
      break;
      case "none":
        $xlab = '';
      break;
      case "time":  //Time formatting suggested by Marlin Viss
        $xlab = strftime($this->x_time_format,$this->plot_min_x);
      break;
      default:
        //Unchanged from whatever format is passed in
        $xlab = $this->plot_min_x;
      break;
    }

    if ($this->x_datalabel_angle == 90) {
      $xpos =  $this->plot_area[0] - $this->small_font_height/2;
      $ypos = ( $this->small_font_width*strlen($xlab) + $this->plot_area[3] + $this->small_font_height);
      ImageStringUp($this->img, $this->small_font,$xpos, $ypos, $xlab, $this->ndx_text_color);
    } else {
      $xpos = $this->plot_area[0] - $this->small_font_width*strlen($xlab)/2 ;
      $ypos = $this->plot_area[3] + $this->small_font_height;
      ImageString($this->img, $this->small_font,$xpos, $ypos, $xlab, $this->ndx_text_color);
    }

    //Will be changed to allow for TTF fonts in data as well.
    //$this->DrawText($this->small_font, $this->x_datalabel_angle, $xpos, $ypos, $this->ndx_title_color, '', $xlab);

    //Top

    if ($this->horiz_tick_increment) {
      $delta_x = $this->horiz_tick_increment;
    } elseif ($this->num_horiz_ticks) {
      $delta_x = ($this->plot_max_x - $this->plot_min_x) / $this->num_horiz_ticks;
    } else {
      $delta_x =($this->plot_max_x - $this->plot_min_x) / 10 ;
    }

    $i = 0;
    $x_tmp = $this->plot_min_x;
    SetType($x_tmp,'double');

    while ($x_tmp <= $this->plot_max_x){
      //$xlab = sprintf("%6.1f %s",$min_x,$si_units[0]);  //PHP2 past compatibility
      switch ($this->x_grid_label_type) {
        case "title":
          $xlab = $this->data_values[$x_tmp][0];
        break;
        case "data":
          $xlab = number_format($x_tmp,$this->x_precision,".",",") . "$this->si_units";
        break;
        case "none":
          $xlab = '';
        break;
        case "time":  //Time formatting suggested by Marlin Viss
          $xlab = strftime($this->x_time_format,$x_tmp);
        break;
        default:
          //Unchanged from whatever format is passed in
          $xlab = $x_tmp;
        break;
      }

      $x_pixels = $this->xtr($x_tmp);

      //Bottom Tick
      ImageLine($this->img,$x_pixels,$this->plot_area[3] + $this->tick_length,
        $x_pixels,$this->plot_area[3], $this->ndx_tick_color);
      //Top Tick
      //ImageLine($this->img,($this->xtr($this->plot_max_x)+$this->tick_length),
      //	$y_pixels,$this->xtr($this->plot_max_x)-1,$y_pixels,$this->ndx_tick_color);

      if ($this->draw_x_grid == 1) {
        ImageLine($this->img,$x_pixels,$this->plot_area[1],
          $x_pixels,$this->plot_area[3], $this->ndx_light_grid_color);
      }

      if ($this->x_datalabel_angle == 90) {  //Vertical Code Submitted by Marlin Viss
          ImageStringUp($this->img, $this->small_font,
        ( $x_pixels - $this->small_font_height/2),
        ( $this->small_font_width*strlen($xlab) + $this->plot_area[3] + $this->small_font_height),$xlab, $this->ndx_text_color);
      } else {
        ImageString($this->img, $this->small_font,
          ( $x_pixels - $this->small_font_width*strlen($xlab)/2) ,
          ( $this->small_font_height + $this->plot_area[3]),$xlab, $this->ndx_text_color);
      }

      $i++;
      $x_tmp += $delta_x;
    }

  } // function DrawHorizontalTicks

  function FormatYTickLabel($which_ylab) {
    switch ($this->y_grid_label_type) {
      case "data":
        $ylab = number_format($which_ylab,$this->y_precision,".",",") . "$this->si_units";
      break;
      case "none":
        $ylab = '';
      break;
      case "time":
        $ylab = strftime($this->y_time_format,$which_ylab);
      break;
      case "right":
        //Make it right aligned
        //$ylab = str_pad($which_ylab,$this->y_label_width," ",STR_PAD_LEFT); //PHP4 only
        $sstr = "%".strlen($this->plot_max_y)."s";
        $ylab = sprintf($sstr,$which_ylab);
      break;
      default:
        //Unchanged from whatever format is passed in
        $ylab = $which_ylab;
      break;
    }

    return($ylab);

  } //function FormatYTickLabel

  function DrawVerticalTick($which_ylab,$which_ypos) {  //ylab in world coord.
    //Draw Just one Tick, called from DrawVerticalTicks
    //Ticks and datalables can be left of plot only, right of plot only,
    //  both on the left and right of plot, or crossing a user defined Y-axis
    //
    //Its faster to draw both left and right ticks at same time
    //  than first left and then right.

    if ($this->y_axis_position != "") {
      //Ticks and lables are drawn on the left border of yaxis
      $yaxis_x = $this->xtr($this->y_axis_position);
    } else {
      //Ticks and lables are drawn on the left border of PlotArea.
      $yaxis_x = $this->plot_area[0];
    }

    $y_pixels = $this->ytr($which_ypos);

    //Lines Across the Plot Area
    if ($this->draw_y_grid == 1) {
      ImageLine($this->img,$this->plot_area[0]+1,$y_pixels,
        $this->plot_area[2]-1,$y_pixels,$this->ndx_light_grid_color);
    }

    //Ticks to the Left of the Plot Area
    if (($this->vert_tick_position == "plotleft") || ($this->vert_tick_position == "both") ) {
      ImageLine($this->img,(-$this->tick_length+$yaxis_x),
      $y_pixels,$yaxis_x,
      $y_pixels, $this->ndx_tick_color);
    }

    //Ticks to the Right of the Plot Area
    if (($this->vert_tick_position == "plotright") || ($this->vert_tick_position == "both") ) {
      ImageLine($this->img,($this->plot_area[2]+$this->tick_length),
      $y_pixels,$this->plot_area[2],
      $y_pixels,$this->ndx_tick_color);
    }

    //Ticks on the Y Axis
    if (($this->vert_tick_position == "yaxis") ) {
      ImageLine($this->img,($yaxis_x - $this->tick_length),
      $y_pixels,$yaxis_x,$y_pixels,$this->ndx_tick_color);
    }

    //DataLabel
//ajo working
    //$this->DrawText($this->y_label_ttffont, 0,($yaxis_x - $this->y_label_width - $this->tick_length/2),
    //		$y_pixels, $this->ndx_text_color, $this->axis_ttffont_size, $which_ylab);
    ImageString($this->img, $this->small_font, ($yaxis_x - $this->y_label_width - $this->tick_length/2),
      ( -($this->small_font_height/2.0) + $y_pixels),$which_ylab, $this->ndx_text_color);
  }

  function DrawVerticalTicks() {

    if ($this->skip_top_tick != 1) { //If tick increment doesn't hit the top
      //Left Top
      //ImageLine($this->img,(-$this->tick_length+$this->xtr($this->plot_min_x)),
      //		$this->ytr($this->plot_max_y),$this->xtr($this->plot_min_x),$this->ytr($this->plot_max_y),$this->ndx_tick_color);
      //$ylab = $this->FormatYTickLabel($plot_max_y);

      //Right Top
      //ImageLine($this->img,($this->xtr($this->plot_max_x)+$this->tick_length),
      //		$this->ytr($this->plot_max_y),$this->xtr($this->plot_max_x-1),$this->ytr($this->plot_max_y),$this->ndx_tick_color);

      //Draw Grid Line at Top
      ImageLine($this->img,$this->plot_area[0]+1,$this->ytr($this->plot_max_y),
          $this->plot_area[2]-1,$this->ytr($this->plot_max_y),$this->ndx_light_grid_color);

    }

    if ($this->skip_bottom_tick != 1) {
      //Right Bottom
      //ImageLine($this->img,($this->xtr($this->plot_max_x)+$this->tick_length),
      //		$this->ytr($this->plot_min_y),$this->xtr($this->plot_max_x),
      //		$this->ytr($this->plot_min_y),$this->ndx_tick_color);

      //Draw Grid Line at Bottom of Plot
      ImageLine($this->img,$this->xtr($this->plot_min_x)+1,$this->ytr($this->plot_min_y),
          $this->xtr($this->plot_max_x),$this->ytr($this->plot_min_y),$this->ndx_light_grid_color);
    }

    // maxy is always > miny so delta_y is always positive
    if ($this->vert_tick_increment) {
      $delta_y = $this->vert_tick_increment;
    } elseif ($this->num_vert_ticks) {
      $delta_y = ($this->plot_max_y - $this->plot_min_y) / $this->num_vert_ticks;
    } else {
      $delta_y =($this->plot_max_y - $this->plot_min_y) / 10 ;
    }

    $y_tmp = $this->plot_min_y;
    SetType($y_tmp,'double');
    if ($this->skip_bottom_tick == 1) {
      $y_tmp += $delta_y;
    }

    while ($y_tmp <= $this->plot_max_y){
      //For log plots:
      if (($this->yscale_type == "log") && ($this->plot_min_y == 1) &&
        ($delta_y%10 == 0) && ($y_tmp == $this->plot_min_y)) {
        $y_tmp = $y_tmp - 1; //Set first increment to 9 to get: 1,10,20,30,...
      }

      $ylab = $this->FormatYTickLabel($y_tmp);

      $this->DrawVerticalTick($ylab,$y_tmp);

      $y_tmp += $delta_y;
    }

    return true;

  } // function DrawVerticalTicks

  function SetTranslation() {
    if ($this->xscale_type == "log") {
      $this->xscale = ($this->plot_area_width)/(log10($this->plot_max_x) - log10($this->plot_min_x));
    } else {
      $this->xscale = ($this->plot_area_width)/($this->plot_max_x - $this->plot_min_x);
    }
    if ($this->yscale_type == "log") {
      $this->yscale = ($this->plot_area_height)/(log10($this->plot_max_y) - log10($this->plot_min_y));
    } else {
      $this->yscale = ($this->plot_area_height)/($this->plot_max_y - $this->plot_min_y);
    }

    // GD defines x=0 at left and y=0 at TOP so -/+ respectively
    if ($this->xscale_type == "log") {
      $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * log10($this->plot_min_x) );
    } else {
      $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * $this->plot_min_x);
    }
    if ($this->yscale_type == "log") {
      $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * log10($this->plot_min_y));
    } else {
      $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * $this->plot_min_y);
    }

    $this->scale_is_set = 1;
  } // function SetTranslation

  function xtr($x_world) {
  //Translate world coordinates into pixel coordinates
  //The pixel coordinates are those of the ENTIRE image, not just the plot_area
    //$x_pixels =  $this->x_left_margin + ($this->image_width - $this->x_tot_margin)*(($x_world - $this->plot_min_x) / ($this->plot_max_x - $this->plot_min_x)) ;
    //which with a little bit of math reduces to ...
    if ($this->xscale_type == "log") {
      $x_pixels =  $this->plot_origin_x + log10($x_world) * $this->xscale ;
    } else {
      $x_pixels =  $this->plot_origin_x + $x_world * $this->xscale ;
    }
    return($x_pixels);
  }

  function ytr($y_world) {
    // translate y world coord into pixel coord
    if ($this->yscale_type == "log") {
      $y_pixels =  $this->plot_origin_y - log10($y_world) * $this->yscale ;  //minus because GD defines y=0 at top. doh!
    } else {
      $y_pixels =  $this->plot_origin_y - $y_world * $this->yscale ;
    }
    return ($y_pixels);
  }


  function DrawDataLabel($lab,$x_world,$y_world) {
    //Depreciated. Use DrawText Instead.
    //Data comes in in WORLD coordinates
    //Draw data label near actual data point
      //$y = $this->ytr($y_world) ;  //in pixels
      //$x = $this->xtr($x_world) ;
      //$this->DrawText($which_font,$which_angle,$which_xpos,$which_ypos,$which_color,$which_size,$which_text,$which_halign='left');
      if ($this->use_ttf) {
//ajjjo
        $lab_size = $this->TTFBBoxSize($this->axis_ttffont_size, $this->x_datalabel_angle, $this->axis_ttffont, $lab); //An array
        $y = $this->ytr($y_world) - $lab_size[1] ;  //in pixels
        $x = $this->xtr($x_world) - $lab_size[0]/2;
        ImageTTFText($this->img, $this->axis_ttffont_size, $this->x_datalabel_angle, $x, $y, $this->ndx_text_color, $this->axis_ttffont, $lab);
      } else {
        $lab_size = array($this->small_font_width*StrLen($lab), $this->small_font_height*3);
        if ($this->x_datalabel_angle == 90) {
          $y = $this->ytr($y_world) - $this->small_font_width*StrLen($lab); //in pixels
          $x = $this->xtr($x_world) - $this->small_font_height;
          ImageStringUp($this->img, $this->small_font,$x, $y ,$lab, $this->ndx_text_color);
        } else {
          $y = $this->ytr($y_world) - $this->small_font_height; //in pixels
          $x = $this->xtr($x_world) - ($this->small_font_width*StrLen($lab))/2;
          ImageString($this->img, $this->small_font,$x, $y ,$lab, $this->ndx_text_color);
        }
      }

  }

  function DrawXDataLabel($xlab,$xpos) {
    //xpos comes in in PIXELS not in world coordinates.
    //Draw an x data label centered at xlab
      if ($this->use_ttf) {
        $xlab_size = $this->TTFBBoxSize($this->axis_ttffont_size,
          $this->x_datalabel_angle, $this->axis_ttffont, $xlab); //An array
        $y = $this->plot_area[3] + $xlab_size[1] + 4;  //in pixels
        $x = $xpos - $xlab_size[0]/2;
        ImageTTFText($this->img, $this->axis_ttffont_size,
          $this->x_datalabel_angle, $x, $y, $this->ndx_text_color, $this->axis_ttffont, $xlab);
      } else {
        $xlab_size = array(ImageFontWidth($this->axis_font)*StrLen($xlab), $this->small_font_height*3);
        if ($this->x_datalabel_angle == 90) {
          $y = $this->plot_area[3] + ImageFontWidth($this->axis_font)*StrLen($xlab); //in pixels
          $x = $xpos - ($this->small_font_height);
          ImageStringUp($this->img, $this->axis_font,$x, $y ,$xlab, $this->ndx_text_color);
        } else {
          $y = $this->plot_area[3] + ImageFontHeight($this->axis_font); //in pixels
          $x = $xpos - (ImageFontWidth($this->axis_font)*StrLen($xlab))/2;
          ImageString($this->img, $this->axis_font,$x, $y ,$xlab, $this->ndx_text_color);
        }
      }

  }

  function DrawPieChart() {
    //$pi = '3.14159265358979323846';
    $xpos = $this->plot_area[0] + $this->plot_area_width/2;
    $ypos = $this->plot_area[1] + $this->plot_area_height/2;
    $diameter = (min($this->plot_area_width, $this->plot_area_height)) ;
    $radius = $diameter/2;

    ImageArc($this->img, $xpos, $ypos, $diameter, $diameter, 0, 360, $this->ndx_grid_color);

    $total = 0;
    reset($this->data_values);
    $tmp = $this->number_x_points - 1;
    while (list($j, $row) = each($this->data_values)) {
      //Get sum of each type
      $color_index = 0;
      $i = 0;
      //foreach ($row as $v)
      while (list($k, $v) = each($row)) {
        if ($k != 0) {
          if ($j == 0) {
            $sumarr[$i] = $v;
          } elseif ($j < $tmp) {
            $sumarr[$i] += $v;
          } else {
            $sumarr[$i] += $v;
          // NOTE!  sum > 0 to make pie charts
            $sumarr[$i] = abs($sumarr[$i]);
            $total += $sumarr[$i];
          }
        }
      $i++;
      }
    }

    $color_index = 0;
    $start_angle = 0;

    reset($sumarr);
    $end_angle = 0;
    while (list(, $val) = each($sumarr)) {
      if ($color_index >= count($this->ndx_data_color)) $color_index=0;  //data_color = array
      $label_txt = number_format(($val / $total * 100), $this->y_precision, ".", ",") . "%";
      $val = 360 * ($val / $total);

      $end_angle += $val;
      $mid_angle = $end_angle - ($val / 2);

      $slicecol = $this->ndx_data_color[$color_index];

//Need this again for FillToBorder
      ImageArc($this->img, $xpos, $ypos, $diameter, $diameter, 0, 360, $this->ndx_grid_color);

      $out_x = $radius * cos(deg2rad($end_angle));
      $out_y = - $radius * sin(deg2rad($end_angle));

      $mid_x = $xpos + ($radius/2 * cos(deg2rad($mid_angle))) ;
      $mid_y = $ypos + (- $radius/2 * sin(deg2rad($mid_angle)));

      $label_x = $xpos + ($radius * cos(deg2rad($mid_angle))) * $this->label_scale_position;
      $label_y = $ypos + (- $radius * sin(deg2rad($mid_angle))) * $this->label_scale_position;

      $out_x = $xpos + $out_x;
      $out_y = $ypos + $out_y;

      ImageLine($this->img, $xpos, $ypos, $out_x, $out_y, $this->ndx_grid_color);
      //ImageLine($this->img, $xpos, $ypos, $label_x, $label_y, $this->ndx_grid_color);
      ImageFillToBorder($this->img, $mid_x, $mid_y, $this->ndx_grid_color, $slicecol);

      if ($this->use_ttf) {
        ImageTTFText($this->img, $this->axis_ttffont_size, 0, $label_x, $label_y, $this->ndx_grid_color, $this->axis_ttffont, $label_txt);
      } else {
        ImageString($this->img, $this->small_font, $label_x, $label_y, $label_txt, $this->ndx_grid_color);
      }

      $start_angle = $val;

      $color_index++;
    }

  }

  function DrawLinesError() {
    //Draw Lines with Error Bars - data comes in as array("title",x,y,error+,error-,y2,error2+,error2-,...);
    $start_lines = 0;

    reset($this->data_values);
    while (list(, $row) = each($this->data_values)) {
      $color_index = 0;
      $i = 0;

      while (list($key, $val) = each($row)) {
//echo "$key, $i, $val<br>";
        if ($key == 0) {
          $lab = $val;
        } elseif ($key == 1) {
          $x_now = $val;
          $x_now_pixels = $this->xtr($x_now); //Use a bit more memory to save 2N operations.
        } elseif ($key%3 == 2) {
          $y_now = $val;
          $y_now_pixels = $this->ytr($y_now);

          //Draw Data Label
          if ( $this->draw_data_labels == 1) {
            $this->DrawDataLabel($lab,$x_now,$y_now);
          }

          if ($color_index >= count($this->ndx_data_color)) { $color_index=0;}
          $barcol = $this->ndx_data_color[$color_index];
          $error_barcol = $this->ndx_error_bar_color[$color_index];

//echo "start = $start_lines<br>";
          if ($start_lines == 1) {
            for ($width = 0; $width < $this->line_width; $width++) {
              ImageLine($this->img, $x_now_pixels, $y_now_pixels + $width,
                $lastx[$i], $lasty[$i] + $width, $barcol);
            }
          }

          $lastx[$i] = $x_now_pixels;
          $lasty[$i] = $y_now_pixels;
          $color_index++;
          $i++;
          $start_lines = 1;
        } elseif ($key%3 == 0) {
          $this->DrawYErrorBar($x_now,$y_now,$val,$this->error_bar_shape,$error_barcol);
        } elseif ($key%3 == 1) {
          $this->DrawYErrorBar($x_now,$y_now,-$val,$this->error_bar_shape,$error_barcol);
        }
      }
    }
  }

  function DrawDotsError() {
    //Draw Dots - data comes in as array("title",x,y,error+,error-,y2,error2+,error2-,...);
    reset($this->data_values);
    while (list(, $row) = each($this->data_values)) {
      $color_index = 0;
      //foreach ($row as $v)
      while (list($key, $val) = each($row)) {
        if ($key == 0) {
        } elseif ($key == 1) {
          $xpos = $val;
        } elseif ($key%3 == 2) {
          if ($color_index >= count($this->ndx_data_color)) $color_index=0;
          $barcol = $this->ndx_data_color[$color_index];
          $error_barcol = $this->ndx_error_bar_color[$color_index];
          $ypos = $val;

          $color_index++;
          $this->DrawDot($xpos,$ypos,$this->point_shape,$barcol);
        } elseif ($key%3 == 0) {
          $this->DrawYErrorBar($xpos,$ypos,$val,$this->error_bar_shape,$error_barcol);
        } elseif ($key%3 == 1) {
          $mine = $val ;
          $this->DrawYErrorBar($xpos,$ypos,-$val,$this->error_bar_shape,$error_barcol);
        }
      }
    }

  }

  function DrawDots() {
    //Draw Dots - data comes in as array("title",x,y1,y2,y3,...);
    reset($this->data_values);
    while (list($j, $row) = each($this->data_values)) {
      $color_index = 0;
      //foreach ($row as $v)
      while (list($k, $v) = each($row)) {
        if ($k == 0) {
        } elseif (($k == 1) && ($this->data_type == "data-data"))  {
          $xpos = $v;
        } else {
          if ($this->data_type == "text-data") {
            $xpos = ($j+.5);
          }
          if ($color_index >= count($this->ndx_data_color)) $color_index=0;
          $barcol = $this->ndx_data_color[$color_index];

          //if (is_numeric($v))  //PHP4 only
          if ((strval($v) != "") ) {   //Allow for missing Y data
            $this->DrawDot($xpos,$v,$this->point_shape,$barcol);
          }
          $color_index++;
        }
      }
    }

  } //function DrawDots

  function DrawDotSeries() {
    //Depreciated: Use DrawDots
    $this->DrawDots();
  }

  function DrawThinBarLines() {
    //A clean,fast routine for when you just want charts like stock volume charts
    //Data must be text-data since I didn't see a graphing need for equally spaced thin lines.
    //If you want it - then write to afan@jeo.net and I might add it.

    if ($this->data_type != "data-data") { $this->DrawError('Data Type for ThinBarLines must be data-data'); }
    $y1 = $this->ytr($this->x_axis_position);

    reset($this->data_values);
    while (list(, $row) = each($this->data_values)) {
      $color_index = 0;
      while (list($k, $v) = each($row)) {
        if ($k == 0) {
            $xlab = $v;
        } elseif ($k == 1) {
          $xpos = $this->xtr($v);
          if ( ($this->draw_x_data_labels == 1) )  { //See "labels_note1 above.
            $this->DrawXDataLabel($xlab,$xpos);
          }
        } else {
          if ($color_index >= count($this->ndx_data_color)) $color_index=0;
          $barcol = $this->ndx_data_color[$color_index];

          ImageLine($this->img,$xpos,$y1,$xpos,$this->ytr($v),$barcol);
          $color_index++;
        }
      }
    }

  }  //function DrawThinBarLines

  function DrawYErrorBar($x_world,$y_world,$error_height,$error_bar_type,$color) {
    $x1 = $this->xtr($x_world);
    $y1 = $this->ytr($y_world);
    $y2 = $this->ytr($y_world+$error_height) ;

    for ($width = 0; $width < $this->error_bar_line_width; $width++) {
      ImageLine($this->img, $x1+$width, $y1 , $x1+$width, $y2, $color);
      ImageLine($this->img, $x1-$width, $y1 , $x1-$width, $y2, $color);
    }
    switch ($error_bar_type) {
      case "line":
        break;
      case "tee":
        ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color);
        break;
      default:
        ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color);
        break;
    }
    return true;
  }

  function DrawDot($x_world,$y_world,$dot_type,$color) {
    $half_point = $this->point_size / 2;
    $x1 = $this->xtr($x_world) - $half_point;
    $x2 = $this->xtr($x_world) + $half_point;
    $y1 = $this->ytr($y_world) - $half_point;
    $y2 = $this->ytr($y_world) + $half_point;

    switch ($dot_type) {
      case "halfline":
        ImageFilledRectangle($this->img, $x1, $this->ytr($y_world), $this->xtr($x_world), $this->ytr($y_world), $color);
        break;
      case "line":
        ImageFilledRectangle($this->img, $x1, $this->ytr($y_world), $x2, $this->ytr($y_world), $color);
        break;
      case "rect":
        ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color);
        break;
      case "circle":
        ImageArc($this->img, $x1 + $half_point, $y1 + $half_point, $this->point_size, $this->point_size, 0, 360, $color);
        break;
      case "dot":
        ImageArc($this->img, $x1 + $half_point, $y1 + $half_point, $this->point_size, $this->point_size, 0, 360, $color);
        ImageFillToBorder($this->img, $x1 + $half_point, $y1 + $half_point, $color, $color);
        break;
      case "diamond":

        $arrpoints = array(
          $x1,$y1 + $half_point,
          $x1 + $half_point, $y1,
          $x2,$y1 + $half_point,
          $x1 + $half_point, $y2
        );

        ImageFilledPolygon($this->img, $arrpoints, 4, $color);
        break;
      case "triangle":
        $arrpoints = array( $x1, $y1 + $half_point,
          $x2, $y1 + $half_point,
          $x1 + $half_point, $y2
        );
        ImageFilledPolygon($this->img, $arrpoints, 3, $color);
        break;
      default:
        ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color);
        break;
    }
    return true;
  }

  function SetErrorBarLineWidth($which_seblw) {
    $this->error_bar_line_width = $which_seblw;
    return true;
  }


  function SetLineWidth($which_lw) {
    $this->line_width = $which_lw;
    if (!$this->error_bar_line_width) {
      $this->error_bar_line_width = $which_lw;
    }
    return true;
  }

  function DrawArea() {
    //Data comes in as $data[]=("title",x,y,...);
    //Set first and last datapoints of area
    $i = 0;
    while ($i < $this->records_per_group) {
      $posarr[$i][] =  $this->xtr($this->min_x);	//x initial
      $posarr[$i][] =  $this->ytr($this->x_axis_position); 	//y initial
      $i++;
    }

    reset($this->data_values);
    while (list($j, $row) = each($this->data_values)) {
      $color_index = 0;
      //foreach ($row as $v)
      while (list($k, $v) = each($row)) {
        if ($k == 0) {
          //Draw Data Labels
          $xlab = SubStr($v,0,$this->x_datalabel_maxlength);
        } elseif ($k == 1) {
          $x = $this->xtr($v);
          // DrawXDataLabel interferes with Numbers on x-axis
          //$this->DrawXDataLabel($xlab,$x);
        } else {
          // Create Array of points for later

          $y = $this->ytr($v);
          $posarr[$color_index][] = $x;
          $posarr[$color_index][] = $y;
          $color_index++;
        }
      }
    }

    //Final_points
    for ($i = 0; $i < $this->records_per_group; $i++) {
      $posarr[$i][] =  $this->xtr($this->max_x);			//x final
      $posarr[$i][] =  $this->ytr($this->x_axis_position); 	//y final
       }

    $color_index=0;

    //foreach($posarr as $row)
    reset($posarr);
    while (list(, $row) = each($posarr)) {
      if ($color_index >= count($this->ndx_data_color)) $color_index=0;
      $barcol = $this->ndx_data_color[$color_index];
//echo "$row[0],$row[1],$row[2],$row[3],$row[4],$row[5],$row[6],$row[7],$row[8],$row[9],$row[10],$row[11],$row[12], $barcol<br>";
      ImageFilledPolygon($this->img, $row, (count($row)) / 2, $barcol);
      $color_index++;
    }
//exit;

  }

  function DrawAreaSeries() {

    //Set first and last datapoints of area
    $i = 0;
    while ($i < $this->records_per_group) {
      $posarr[$i][] =  $this->xtr(.5);			//x initial
      $posarr[$i][] =  $this->ytr($this->x_axis_position); 	//y initial
      $i++;
    }

    reset($this->data_values);
    while (list($j, $row) = each($this->data_values)) {
      $color_index = 0;
      //foreach ($row as $v)
      while (list($k, $v) = each($row)) {
        if ($k == 0) {
          //Draw Data Labels
          $xlab = SubStr($v,0,$this->x_datalabel_maxlength);
          $this->DrawXDataLabel($xlab,$this->xtr($j + .5));
        } else {
          // Create Array of points for later

          $x = round($this->xtr($j + .5 ));
          $y = round($this->ytr($v));
          $posarr[$color_index][] = $x;
          $posarr[$color_index][] = $y;
          $color_index++;
        }
      }
    }

    //Final_points
    for ($i = 0; $i < $this->records_per_group; $i++) {
      $posarr[$i][] =  round($this->xtr($this->max_x + .5));	//x final
      $posarr[$i][] =  $this->ytr($this->x_axis_position); 		//y final
       }

    $color_index=0;

    //foreach($posarr as $row)
    reset($posarr);
    while (list(, $row) = each($posarr)) {
      if ($color_index >= count($this->ndx_data_color)) $color_index=0;
      $barcol = $this->ndx_data_color[$color_index];
//echo "$row[0],$row[1],$row[2],$row[3],$row[4],$row[5],$row[6],$row[7],$row[8],$row[9],$row[10],$row[11],$row[12], $barcol<br>";
      ImageFilledPolygon($this->img, $row, (count($row)) / 2, $barcol);
      $color_index++;
    }

  }

  function DrawLines() {
    //Data comes in as $data[]=("title",x,y,...);
    $start_lines = 0;
    if ($this->data_type == "text-data") {
      $lastx[0] = $this->xtr(0);
      $lasty[0] = $this->xtr(0);
    }

    //foreach ($this->data_values as $row)
    reset($this->data_values);
    while (list($j, $row) = each($this->data_values)) {

      $color_index = 0;
      $i = 0;
      //foreach ($row as $v)
      while (list($k, $v) = each($row)) {
        if ($k == 0) {
          $xlab = SubStr($v,0,$this->x_datalabel_maxlength);
        } elseif (($k == 1) && ($this->data_type == "data-data"))  {
            $x_now = $this->xtr($v);
        } else {
          //(double) $v;
          // Draw Lines
          if ($this->data_type == "text-data") {
            $x_now = $this->xtr($j+.5);
          }

          //if (is_numeric($v))  //PHP4 only
          if ((strval($v) != "") ) {   //Allow for missing Y data
            $y_now = $this->ytr($v);
            if ($color_index >= count($this->ndx_data_color)) { $color_index=0;} ;
            $barcol = $this->ndx_data_color[$color_index];

            if ($start_lines == 1) {
              for ($width = 0; $width < $this->line_width; $width++) {
                if ($this->line_style[$i] == "dashed") {
                  $this->DrawDashedLine($x_now, $y_now + $width, $lastx[$i], $lasty[$i] + $width, 4,4, $barcol);
                } else {
                  ImageLine($this->img, $x_now, $y_now + $width, $lastx[$i], $lasty[$i] + $width, $barcol);
                }
              }
            }
            $lastx[$i] = $x_now;
          } else {
            $y_now = $lasty[$i];
            //Don't increment lastx[$i]
          }
          //$bordercol = $this->ndx_data_border_color[$colbarcount];

          $lasty[$i] = $y_now;
          $color_index++;
          $i++;
        }
        //Now we are assured an x_value
        if ( ($this->draw_x_data_labels == 1) && ($k == 1) )  { //See "labels_note1 above.
          $this->DrawXDataLabel($xlab,$x_now);
        }
      } //while rows of data
      $start_lines = 1;
    }
  }

    //Data comes in as $data[]=("title",x,y,e+,e-,y2,e2+,e2-,...);

  function DrawLineSeries() {
    //This function is replaced by DrawLines
    //Tests have shown not much improvement in speed by having separate routines for DrawLineSeries and DrawLines
    //For ease of programming I have combined them
    return false;
  } //function DrawLineSeries

  function DrawDashedLine($x1pix,$y1pix,$x2pix,$y2pix,$dash_length,$dash_space,$color) {
    //Code based on work by Ariel Garza and James Pine
    //I've decided to have this be in pixels only as a replacement for ImageLine
    //$x1pix = $this->xtr($x1);
    //$y1pix = $this->ytr($y1);
    //$x2pix = $this->xtr($x2);
    //$y2pix = $this->ytr($y2);

    // Get the length of the line in pixels
    $line_length = ceil (sqrt(pow(($x2pix - $x1pix),2) + pow(($y2pix - $y1pix),2)) );

    $dx = ($x2pix - $x1pix) / $line_length;
    $dy = ($y2pix - $y1pix) / $line_length;
    $lastx	= $x1pix;
    $lasty	= $y1pix;

    // Draw the dashed line
    for ($i = 0; $i < $line_length; $i += ($dash_length + $dash_space)) {
      $xpix = ($dash_length * $dx) + $lastx;
      $ypix = ($dash_length * $dy) + $lasty;

      ImageLine($this->img,$lastx,$lasty,$xpix,$ypix,$color);
      $lastx = $xpix + ($dash_space * $dx);
      $lasty = $ypix + ($dash_space * $dy);
    }
  } // function DrawDashedLine

  function DrawBars() {

    if ($this->data_type != "text-data") {
      $this->DrawError('Bar plots must be text-data: use function SetDataType("text-data")');
    }

    $xadjust = ($this->records_per_group * $this->record_bar_width )/4;

    reset($this->data_values);
    while (list($j, $row) = each($this->data_values)) {

      $color_index = 0;
      $colbarcount = 0;
      $x_now = $this->xtr($j+.5);

      while (list($k, $v) = each($row)) {
        if ($k == 0) {
          //Draw Data Labels
          $xlab = SubStr($v,0,$this->x_datalabel_maxlength);
          $this->DrawXDataLabel($xlab,$x_now);
        } else {
          // Draw Bars ($v)
          $x1 = $x_now - $this->data_group_space + ($k-1)*$this->record_bar_width;
          $x2 = $x1 + $this->record_bar_width*$this->bar_width_adjust;

          if ($v < $this->x_axis_position) {
            $y1 = $this->ytr($this->x_axis_position);
            $y2 = $this->ytr($v);
          } else {
            $y1 = $this->ytr($v);
            $y2 = $this->ytr($this->x_axis_position);
          }

          if ($color_index >= count($this->ndx_data_color)) $color_index=0;
          if ($colbarcount >= count($this->ndx_data_border_color)) $colbarcount=0;
          $barcol = $this->ndx_data_color[$color_index];
          $bordercol = $this->ndx_data_border_color[$colbarcount];

          if ((strval($v) != "") ) {   //Allow for missing Y data
            if ($this->shading > 0) {
              for($i=0;$i<($this->shading);$i++) {
              //Shading set in SetDefaultColors
              ImageFilledRectangle($this->img, $x1+$i, $y1-$i, $x2+$i, $y2-$i, $this->ndx_i_light);
              }
            }

            ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $barcol);
            ImageRectangle($this->img, $x1, $y1, $x2, $y2, $bordercol);
            if ($this->draw_data_labels == '1') {  //ajo
              $y1 = $this->ytr($this->label_scale_position * $v);
              //$this->DrawDataLabel($v,$j + .5,$v*$this->label_scale_position);
              $this->DrawText($this->small_font, $this->x_label_angle,
                $x1+$this->record_bar_width/2, $y1, $this->ndx_label_color, $this->x_label_ttffont_size, $v,'center','top');
            }
          }

          $color_index++;
          $colbarcount++;
        }
      }
    }
  } //function DrawBars

  function DrawLegend($which_x1,$which_y1,$which_boxtype) {
    //Base code submitted by Marlin Viss
    $max_legend_length=0;
    reset($this->legend);
    while (list(,$leg) = each($this->legend)) {
      $len = strlen($leg);
      if ($max_legend_length < $len) {
        $max_legend_length = $len;
      }
    }

    $line_spacing = 1.25;
    $vert_margin = $this->small_font_height/2 ;
    $dot_height = $this->small_font_height*$line_spacing - 1;

  //Upper Left
    if ((!$which_x1) || (!$which_y1) ) {
      $box_start_x = $this->plot_area[2] - $this->small_font_width*($max_legend_length+4);
      $box_start_y = $this->plot_area[1] + 4;
    } else {
      $box_start_x = $which_x1;
      $box_start_y = $which_y1;
    }

  //Lower Right
    $box_end_y = $box_start_y + $this->small_font_height*(count($this->legend)+1) + 2*$vert_margin;
    //$box_end_x = $this->plot_area[2] - 5;
    $box_end_x = $box_start_x + $this->small_font_width*($max_legend_length+4) - 5;


  // Draw box for legend
    ImageFilledRectangle($this->img,
      $box_start_x, $box_start_y,$box_end_x,
      $box_end_y, $this->ndx_bg_color);
    ImageRectangle($this->img,
      $box_start_x, $box_start_y,$box_end_x,
      $box_end_y, $this->ndx_grid_color);

    $color_index=0;
    $i = 0;


    reset($this->legend);


    while (list(,$leg) = each($this->legend)) {
      $y_pos = $box_start_y + $this->small_font_height*($i)*($line_spacing) + $vert_margin;

      ImageString($this->img, $this->small_font,
      $box_start_x + $this->small_font_width*( $max_legend_length - strlen($leg) + 1 ) ,
      $y_pos,
      $leg, $this->ndx_text_color);

      if ($color_index >= count($this->ndx_data_color)) $color_index=0;
  // Draw a box in the data color
      ImageFilledRectangle($this->img,
        $box_end_x - $this->small_font_width*2,
        $y_pos + 1, $box_end_x - $this->small_font_width,
        $y_pos + $dot_height,
        $this->ndx_data_color[$color_index]);

      ImageRectangle($this->img,
        $box_end_x - $this->small_font_width*2,
        $y_pos + 1, $box_end_x - $this->small_font_width,
        $y_pos + $dot_height,
        $this->ndx_text_color);
      $i++;
      $color_index++;
    }
  } //function DrawLegend


  function DrawGraph() {

    if (($this->img) == "") {
      $this->DrawError('No Image Defined: DrawGraph');
            //$this->PHPlot();
        }

    if (! is_array($this->data_values)) {
      $this->DrawBackground();
      $this->DrawError("No array of data in \$data_values");
    } else {
      if (!$this->data_color) {
        $this->SetDataColors(array('blue','green','yellow','red','orange','blue'),array('black'));
      }

      $this->FindDataLimits();  //Get maxima and minima for scaling

      $this->SetXLabelHeight();		//Get data for bottom margin

      $this->SetYLabelWidth();		//Get data for left margin

      if (!$this->plot_area_width) {
        $this->SetPlotAreaPixels('','','','');		//Set Margins
      }

      if (!$this->plot_max_y) {  //If not set by user call SetPlotAreaWorld,
        $this->SetPlotAreaWorld('','','','');
      }

      if ($this->data_type == "text-data") {
        $this->SetEqualXCoord();
      }

      $this->SetPointSize($this->point_size);

      $this->DrawBackground();
      $this->DrawImageBorder();

      $this->SetTranslation();

      if ($this->draw_plot_area_background == 1) {
        $this->DrawPlotAreaBackground();
      }
//$foo = "$this->max_y, $this->min_y, $new_miny, $new_maxy, $this->x_label_height";
//ImageString($this->img, 4, 20, 20, $foo, $this->ndx_text_color);

      switch ($this->plot_type) {
        case "bars":
          $this->DrawPlotBorder();
          $this->DrawLabels();
          $this->DrawBars();
          $this->DrawXAxis();
          break;
        case "thinbarline":
          $this->DrawPlotBorder();
          $this->DrawLabels();
          $this->DrawThinBarLines();
          break;
        case "lines":
          $this->DrawPlotBorder();
          $this->DrawLabels();
          if ( $this->data_type == "text-data") {
            $this->DrawLines();
          } elseif ( $this->data_type == "data-data-error") {
            $this->DrawLinesError();
          } else {
            $this->DrawLines();
          }
          break;
        case "area":
          $this->DrawPlotBorder();
          $this->DrawLabels();
          if ( $this->data_type == "text-data") {
            $this->DrawAreaSeries();
          } else {
            $this->DrawArea();
          }
          break;
        case "linepoints":
          $this->DrawPlotBorder();
          $this->DrawLabels();
          if ( $this->data_type == "text-data") {
            $this->DrawLines();
            $this->DrawDots();
          } elseif ( $this->data_type == "data-data-error") {
            $this->DrawLinesError();
            $this->DrawDotsError();
          } else {
            $this->DrawLines();
            $this->DrawDots();
          }
          break;
        case "points";
          $this->DrawPlotBorder();
          $this->DrawLabels();
          if ( $this->data_type == "text-data") {
            $this->DrawDots();
          } elseif ( $this->data_type == "data-data-error") {
            $this->DrawDotsError();
          } else {
            $this->DrawDots();
          }
          break;
        case "pie":
          $this->DrawPieChart();
          $this->DrawLabels();
          break;
        default:
          $this->DrawPlotBorder();
          $this->DrawLabels();
          $this->DrawBars();
          break;
      }

      if ($this->legend) {
        $this->DrawLegend($this->legend_x_pos,$this->legend_y_pos,'');
      }

    }
    if ($this->print_image == 1) {
      $this->PrintImage();
    }
  } //function DrawGraph

 }

// $graph = new PHPlot;

// $graph->DrawGraph();

