// Module PI : Peida Interactive  PIBarGraph
// Drawer Y=f(X)      R. Ansari  2004
// (C) LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include "sopnamsp.h"
#include "machdefs.h"
#include <stdlib.h>
#include <iostream>
#include "pibargraph.h"

// --------------------------------------------------------------------------
// ----------------------------------------------------------
//  Classe de representation d'une serie de valeurs sous 
//  forme de bar-graph  
// ----------------------------------------------------------
// --------------------------------------------------------------------------

//++
// Class	PIBarGraph
// Lib		PI
// include	pibargraph.h
//
//	Classe de representation d'une serie de valeur sous forme de bar-graph
//--
//++
// Links	Parents
// PIDrawer
//--
//++
// Titre	Constructeur
// PIBarGraph::PIBarGraph()
//--


/* --Methode-- */
PIBarGraph::PIBarGraph(bool horiz, bool fill)
    : PIDrawer()
{
  idMin = 0.; idMax = 1.;
  mMin = 0.; mMax = 1.;
  //DEL  aColIdx = 0;
  fgFill = fill;
  fgHoriz = horiz;
  fgValLabel = false;
  packFrac = 0.5;
  GetGraphicAtt().SetColAtt(PI_Black, PI_White);
  GetGraphicAtt().SetFontAtt(PI_DefaultFont, PI_NormalSizeFont, PI_RomanFont);
  GetGraphicAtt().SetLineAtt(PI_NormalLine);
  SetName("BarGraph");
} 

/* --Methode-- */
PIBarGraph::~PIBarGraph()
{
}

/* --Methode-- */
int PIBarGraph::AddBar(double id_, double val_, string const& lab_, PIColors col_)
{
  struct _bgdata bgd;
  bgd.id = id_;
  bgd.val = val_;
  bgd.lab = lab_;
  bgd.col = col_;
  if (mBars.size() == 0) { mMin = mMax = val_; idMin = idMax = id_; }
  else {
    if (val_ < mMin)  mMin = val_;
    if (val_ > mMax)  mMax = val_;
    if (id_ < idMin)  idMin = id_;
    if (id_ > idMax)  idMax = id_;
  }
  mBars.push_back(bgd);
  return mBars.size();
}

/* --Methode-- */
int PIBarGraph::AddBar(double val)
{
  string lab = "";
  double id = mBars.size()+0.5;
  return  AddBar(id, val, lab, PI_NotDefColor);
}


static inline void swap_ifhoriz(double& a, double& b) 
{
  double tmp = a;
  a = b;  b = tmp;
}

/* --Methode-- */
void PIBarGraph::UpdateLimits()
{
  if (mBars.size() < 1)  return;
  double xmin, xmax, ymin, ymax;
  xmin = idMin-packFrac*(idMax-idMin)/mBars.size(); 
  xmax = idMax+packFrac*(idMax-idMin)/mBars.size();
  if (mMin*mMax >= 0.) {
    ymin = 0.; ymax = mMax*1.1;
  }
  else {
    ymin = mMin*1.1;  ymax = mMax*1.1;
  }
  if (fgHoriz) {
    swap_ifhoriz(xmin, ymin);
    swap_ifhoriz(xmax, ymax);
  }
  PIAxes::ReSizeMinMax(isLogScaleX(),xmin,xmax);
  PIAxes::ReSizeMinMax(isLogScaleY(),ymin,ymax);
  SetLimits(xmin,xmax,ymin,ymax);
  //  SetAxesFlags(kBoxAxes | kExtTicks | kLabels);  Ne pas faire - Reza 05/04->11/99
}

static inline void swap_ifhoriz_g(PIGrCoord& a, PIGrCoord& b) 
{
  PIGrCoord tmp = a;
  a = b;  b = tmp;
}

/* --Methode-- */
void PIBarGraph::Draw(PIGraphicUC* g, double xmin, double ymin, double xmax, double ymax)
{
  if (mBars.size() < 1) return;
  PIGrCoord x,y,dx,dy;
  double larg = packFrac*(idMax-idMin)/mBars.size();
  for(unsigned int k=0; k<mBars.size(); k++) {
    PIColors dcol = g->GetForeground();
    x = mBars[k].id-0.5*larg; dx = larg;
    y = 0.; dy = mBars[k].val;
    if (mBars[k].col != PI_NotDefColor) g->SelForeground(mBars[k].col);
    if (fgHoriz) {
      swap_ifhoriz_g(x, y);
      swap_ifhoriz_g(dx, dy);
    }  
    if (fgFill) g->DrawFBox(x,y,dx,dy);
    else  g->DrawBox(x,y,dx,dy);
    if ((mBars[k].lab.length() == 0 ) && !fgValLabel ) continue;
    string lab = mBars[k].lab;
    if (fgValLabel) {
      char buff[32];
      sprintf(buff, " %g ", mBars[k].val);
      lab = buff;
    }
    x = mBars[k].id;
    y = mBars[k].val;
    double fy = y;
    bool fgneg = false;
    bool fgin = false;
    if (fy > 0.) {
      if (fy > mMax/2.)  { fgin = true;  fy *= 0.95; }
      else fy *= 1.05;
    }
    else {
      fgneg = true;
      if (fy < mMin/2.)  { fgin = true;  fy *= 0.95; }
      else fy *= 1.05;
    }
    y  = fy;
    unsigned long pflg = PI_VerticalCenter|PI_HorizontalLeft;
    if ( (fgin && !fgneg) || (!fgin && fgneg) ) pflg = PI_VerticalCenter|PI_HorizontalRight;
    if (fgHoriz)  pflg |= PI_TextDirectionHorizontal;
    else pflg |= PI_TextDirectionVerticalUp;
    if (fgHoriz)  swap_ifhoriz_g(x, y);
     if (fgin) g->DrawOpaqueString(x, y, lab.c_str(), pflg);
    else g->DrawString(x, y, lab.c_str(), pflg);

    if (mBars[k].col != PI_NotDefColor) g->SelForeground(dcol);
  }
}


/* --Methode-- */
int PIBarGraph::DecodeOptionString(vector<string> & opt, bool rmdecopt)
{
  int optsz1 = opt.size();
  if(optsz1<1)  return(0);  
  // On appelle d'abord le decodage de la classe PIDrawer de laquelle
  // on herite. (Pas obligatoire) on decode donc ici les attributs de
  // couleur, fontes ...
  int ndec1 = PIDrawer::DecodeOptionString(opt, rmdecopt);
  if(optsz1-ndec1<1) return(ndec1);  // si tout a ete decode

  vector<string> udopt;  // On gardera ici les options non decodees
  unsigned int k = 0;
  int ndec = opt.size();
  for( k=0; k<opt.size(); k++ ) {
    string opts = opt[k];
    if (opts=="horizontalbars") SetHorizontalBars(); 
    else if (opts=="verticalbars") SetVerticalBars();
    else if (opts=="fill")  SetFill(true);
    else if (opts=="nofill")  SetFill(false);
    else if (opts.substr(0,9)=="packfrac=") {
      double frac = atof(opts.substr(9).c_str()); 
      SetPacking(frac);
    }
    else if (opts=="barvaluelabel")  UseBarValueAsLabel(true);
    else if (opts=="nobarvaluelabel")  UseBarValueAsLabel(false);
    else {
      // Si option non decode
      ndec--;
      // S'il faut supprimer les options decodees
      if (rmdecopt)  udopt.push_back(opts);
    }
  }  
  // S'il faut supprimer les options decodees, on remplace l'argument opt
  // par le vecteur des options non decodees.
  if (rmdecopt)  opt = udopt;
  return(ndec+ndec1);  
}

/* --Methode-- */
int PIBarGraph::OptionToString(vector<string> & opt) const
{
 PIDrawer::OptionToString(opt);
 if (fgHoriz) opt.push_back("horizontalbars"); else opt.push_back("verticalbars");
 if (fgFill) opt.push_back("fill");  else opt.push_back("nofill");
 if (fgValLabel) opt.push_back("barvaluelabel");  else opt.push_back("nobarvaluelabel");
 char buff[64];
 sprintf(buff,"packfrac=%g", packFrac);
 opt.push_back(buff);
 return 1;
}

/* --Methode-- */
void PIBarGraph::GetOptionsHelpInfo(string& info)
{
info += " ---- PIBarGraph options help info : \n" ;
info += "  fill/nofill: set bar fill option \n";
info += "  horizontalbars/verticalbars: set bar orientation \n";
info += "  packfrac=value : set bar packing fraction (0..1) \n";
info += "  barvaluelabel/nobarvaluelabel: Use/Don't use bar value as labels \n";
info += " --- + Usual colr/line/font  attribute decoding ... \n";
PIDrawer::GetOptionsHelpInfo(info);
return;
}
