// =============================================================================
//		Chart 
//		Copyright (c) 2001 Brian Burton
//
//		Based on Chart Builder by Michael Bostock @ Netscape
//		Minor modofications by Theo Heselmans, Xceed, 2005
// =============================================================================

Chart_Folder      = '../pages/Chart/$file/'
Chart_TickLength  = 8

Chart_Normal      = 0
Chart_Stacked     = 1
Chart_Percent     = 2
Chart_Single      = 3


function Chart(width, height, style, base) {

   this.width      = width  || 400
   this.height     = height || 200
   this.style      = style  || Chart_Normal
   this.base       = base   || 0
   this.rows       = new Array()
   this.borderBars = true
   this.outColour  = 'white'

   return this
}

Chart.prototype.addRow = function() {

   this.rows[this.rows.length] = new Array();
   var row = this.rows[this.rows.length - 1];
   for (var i = 0; i < arguments.length; i++)
      row[row.length] = arguments[i];
}

Chart.prototype.addDataset = function() {

   if (arguments.length < 3) return

   var r = this.rows.length

   if (!this.legends) this.legends = new Array()
   this.legends[r] = arguments[0]
   if (!this.colours) this.colours = new Array()
   this.colours[r] = arguments[1]

   this.rows[r] = new Array()
   var row = this.rows[r]
   for (var i = 2; i < arguments.length; i++)
      row[row.length] = arguments[i]
}

Chart.prototype.setXScale = function(start, skip, inc, centre) {
   this.showXScale = true;
   this.xStart  = start || 0;
   this.xSkip   = skip || 1;
   this.xInc    = inc || 1;
   this.xCentre = centre || false
   this.makeTags()
}

Chart.prototype.setXScaleValues = function() {
   this.showXScale = true;
   this.xStart = 0;
   this.xSkip = 1;
   this.xInc = 1;
   this.tags = arguments
}

Chart_Days   = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
Chart_Months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

Chart.prototype.makeTags = function() {

   this.tags = new Array();
   this.countData()
   for (var i = 0; i < this.count; i++)
      this.tags[i] = this.xStart + i * this.xInc;
}

Chart.prototype.setColours = function() {
   this.colours = arguments
}

Chart.prototype.setLegends = function() {

   this.legends = arguments;
}

// --- internals ---

Chart.prototype.countData = function() {

   var n = 0
   for (var i = 0; i < this.rows.length; i++)
      if (this.rows[i].length > n) n = this.rows[i].length
   this.count = n
}

Chart.prototype.calcRange = function() {

   this.ymax = Number.MIN_VALUE
   this.ymin = Number.MAX_VALUE
   for (var i = 0; i < this.rows.length; i++) {
      for (var j = 0; j < this.rows[i].length; j++) {
         if (this.rows[i][j] > this.ymax) this.ymax = this.rows[i][j];
         if (this.rows[i][j] < this.ymin) this.ymin = this.rows[i][j];
         }
      }
}

Chart.prototype.rescale = function() {

   if (this.ymin > 0) {
      if (this.ymin > this.base) {
         this.ymin = this.base
         this._base = this.base
         }
      else
         this.ymin = 0
      }

   if (this.ymax < 0) {
      if (this.ymax < this.base) {
         this.ymax = this.base
         this._base = this.base
         }
      else
         this.ymax = 0
      }

   this.vscale = this.height / (this.ymax - this.ymin);
   this.bscale = Math.floor((this.width / this.count - 1) / this.rows.length)
   this.hscale = this.bscale * this.rows.length
   this._width = (this.hscale + 1) * this.count

   this._style = this.style
   if (this._style == Chart_Single && this.rows.length > 1) this._style = Chart_Normal
}

Chart.prototype.rescaleStack = function() {
   var m
   this.ymin = 0
   this.ymax = 0
   for (var i = 0; i < this.count; i++) {
      m = 0
      for (var j = 0; j < this.rows.length; j++)
         if (i < this.rows[j].length) {
            if (this.rows[j][i] > 0) m += this.rows[j][i]
            }
      if (m > this.ymax) this.ymax = m;
      }
   this.vscale = this.height / (this.ymax - this.ymin);
   this.hscale = Math.floor(this.width / this.count) - 1;
   this.bscale = this.hscale
   this._style = Chart_Stacked
}

Chart.prototype.rescaleRel = function() {
/*
   var m
   for (var i = 0; i < this.count; i++) {
      m = 0;
      for (var j = 0; j < this.rows.length; j++) {
         if (i < this.rows[j].length) m += this.rows[j][i]
         }
      var s = 100 / m; var k = 0;
      for (var j = 1; j < this.rows.length; j++) {
         if (i < this.rows[j].length) {
            this.rows[j][i] *= s;
            this.rows[j][i] = Math.round(10 * this.rows[j][i]) / 10;
            if (j != 0) k += this.rows[j][i] * this.vscale;
            }
         }
//      this.rows[0][i] = Math.round(10 * (this.height - k) / this.vscale) / 10;
      }
*/
   this.ymin = 0
   this.ymax = 100

   this.vscale = this.height / 100;
   this.hscale = Math.floor(this.width / this.count) - 1;
   this.bscale = this.hscale
   this._style = Chart_Percent

}

Chart.prototype.genClearImg = function(w, h, x) {
   return '<img src="' + Chart_Folder + 'clear.gif" width="' + w + '" height="' + h + ' border=0"' +
      ((x) ? (' ' + x) : '') + '>'
}

Chart.prototype.genBlackImg = function(w, h) {
   return '<img src="' + Chart_Folder + 'black.gif" width="' + w + '" height="' + h + '">'
}

Chart.prototype.genNumImg = function(n, w, h, x) {

   var g = (n < 0) ? 'clear' : (n % 11);
   //return '<img src="' + Chart_Folder + g + '.gif" width="' + w + '" height="' + h + '"' +
   //   ((x) ? (' ' + x) : '') + '>'
   //return '<img src="' + Chart_Folder + '1.gif" class=gBar' + g + ' width="' + w + '" height="' + h + '"' + 
   //   ((x) ? (' ' + x) : '') + '>' //changed by Theo, to prevent coloring, and adding a class
   return '<img src="' + Chart_Folder + g + '.gif" class=gBar' + g + ' width="' + w + '" height="' + h + '"' + 
     ((x) ? (' ' + x) : '') + '>' //changed by Theo, with color images, and adding a class

}

Chart.prototype.genLeftSpan = function(s) {
   var t = '<tr>'
   var n = 1
//   if (this.yLabel) n++
   if (this.scale)  n += s
   if (n > 0) t += '<td colspan="' + n + '">' + this.genClearImg(1, 1) + '</td>'
   return t
}

Chart.prototype.writeXScale = function() {

   function genTag(c, s, t) {
      return '<td valign="top" align="' + ((c) ? 'center' : 'left') + '" colspan="' + s + '">' +
         '<span class="chartScales">' + (t || '') + '</span></td>\n'
   }

   var n = Math.floor(this.count / this.xSkip)

   var tt = "";
   tt += this.genLeftSpan(2)
   tt += "<td valign=top colspan=" + (1 + this.count * 2)+ ">";
   tt += this.genBlackImg(1, Chart_TickLength)
   tt += this.genClearImg(1, 1)
   var w = (this.hscale + 1) * this.xSkip - 1
   for (var i = 0; i < n; i++) {
      tt += this.genClearImg(w, 1)
      tt += this.genBlackImg(1, Chart_TickLength)
      }
   tt += '</td>'
   tt += this.genFillRight()
   tt += '</tr>\n'

   tt += this.genLeftSpan(3)
   var s = 2 * this.xSkip, t = 0;
   for (var i = 0; i < n; i++) {
      tt += genTag(this.xCentre, s, this.tags[i * this.xSkip]); t += s;
      }
   if (i < Math.ceil(this.count / this.xSkip))
      tt += genTag(this.xCentre, 2 * this.count - t, this.tags[i * this.xSkip]);
   tt += this.genFillRight()
   tt += '</tr>\n'

   return tt;
}

Chart.prototype.genYScale = function(pv, al, ht) {

   var h = this.height / (this.ymax - this.ymin) * this.scale
   if (h < 15) {
      if (!this.err)
         alert("Warning! Scale is too small! Please make\nthe scale larger or make the graph taller.");
      this.err = true
      return "<td rowspan=2></td><td rowspan=2></td><td rowspan=2></td>\n"
      }

   var t = ''
   var n = Math.floor(ht / h)

   t += '<td valign="' + al + '" align="right" class="chartScales">'
   var d = 0
   for (var i = 1; i <= n; i++) {
      if (pv) {
         t += (this._base + this.scale * (n - i))
         if (this._style == Chart_Percent) t += "%"
         }
      else
         t += (this._base - this.scale * i )
      t += this.genClearImg(1, Math.round(i * h - d - 2)) + '<br>\n';
      d += h
      }
   t += '</td>\n'

   t += '<td valign="' + al + '">'  // rowspan=2>'
   var d = 0
   for (var i = 1; i <= n; i++) {
      if ( pv) t += this.genBlackImg(Chart_TickLength, 1) + '<br>\n'
      t += this.genClearImg(1, Math.round(i * h - d - 1)) + '<br>\n'
      if (!pv) t += this.genBlackImg(Chart_TickLength, 1) + '<br>\n'
      d += h
      }
   t += '</td>\n'

   t += '<td valign="' + al + '">'  // rowspan=2>'
   t += this.genBlackImg(1, ht)
   t += this.genClearImg(1, ht)
   t += '</td>\n'
   return t
}

Chart.prototype.genNegScale = function(min, max) {

   return this.genYScale(false, 'top', this.height * (this._base - this.ymin) / (this.ymax - this.ymin))
}

Chart.prototype.genPosScale = function(min, max) {

   return this.genYScale(true, 'bottom', this.height * (this.ymax - this._base) / (this.ymax - this.ymin))
}

Chart.prototype.genFillRight = function(s) {

   var c = 0
   if (s != null) c += s
   c += ((this.legends) ? 3 : 1)
   if (c <= 0) return ''

   var t = '<td'
   if (c > 1) t += ' colspan="' + c + '"'
   return t + '>' + this.genClearImg(1, 1) + '</td>'
}

Chart.prototype.genTop = function() {

   this.ycells = 3
   if (this.ymin < 0) this.ycells++
   if (this.ymin < 0 && this.ymax > 0) this.ycells++

   var t = '<table bgcolor="' + this.outColour + '"'
   if (this.bgimage) t += ' background="' + this.bgimage + '"'
   t += ' border="0" cellpadding="0" cellspacing="0"><tr><td>\n'
   t += '<table border="0" cellpadding="0" cellspacing="0">\n'

   t += this.genLeftSpan(3)
   t += '<th valign="middle" height=30 colspan=' + (this.count * 2) + ' class="chartTitle">'
   t += (this.title) ? this.title : '&nbsp'
   t += '</th>'
   t += this.genFillRight()
   t += '</tr>\n'

   t += '<tr><th rowspan=' + this.ycells + ' align=center nowrap width=20 class="chartLabels">'
   if (this.yLabel)
      t += (this.yLabel.split('')).join('<br>\n')
   else
      t += '&nbsp'
   t += '</th>'
   var c = this.count * 2
   if (this.scale) c += 3
   t += '<td colspan="' + c + '">' + this.genClearImg(1, 1) + '</td>'
   t += this.genLegend()
   t += '</tr>\n'

   return t
}

Chart.prototype.genBottom = function() {

   var t = ''
   if (this.showXScale) t += this.writeXScale();

   t += this.genLeftSpan(3)
   t += '<th colspan=' + (this.count * 2) + ' height=25 valign="middle" class="chartLabels">'
   if (this.xLabel)
      t += this.xLabel
   else
      t += '&nbsp'
   t += '</th>'
   t += this.genFillRight()
   t += '</tr>\n'
   t += "</table>\n"
   t += "</td></tr></table>\n"
   return t
}

Chart.prototype.genXAxis = function(z) {

   var t = ''
   var c = this.count * 2
   var w = this._width
   if (this.scale) {
      t += '<tr><td>' + this.genClearImg(1, 1) + '</td><td>'
      if (z)
         t += this.genBlackImg(Chart_TickLength, 1)
      else
         t += this.genClearImg(1, 1)
      t += '</td>'
      c++
      w += 2
      }
   t += "<td BGCOLOR=#000000 colspan=" + c + ">";
   t += this.genBlackImg(w, 1)
   t += '</td>'
   t += '</tr>\n'
   return t
}

Chart.prototype.genLegend = function() {

   var t = ''
   t += '<td width=8 nowrap rowspan=' + this.ycells + '>' + this.genClearImg(1, 1) + '</td>'

   if (!this.legends) return t

   t += '<td rowspan=' + this.ycells + '>\n'
   t += '<table border=1 CELLSPACING=0 CELLPADDING=4><tr><td class="chartLegends">\n'
   for (var i = 0; i < this.legends.length; i++) {
      if (!this.legends[i]) continue;
      if (i >= this.rows.length) break;
      var n = (this.colours && i < this.colours.length) ? this.colours[i] : i
      if (n < 0) continue
      t += this.genNumImg(n, 5, 5, "border=1 HSPACE=3") + this.legends[i] + '<br>\n';
      }
   t += '</td></tr></table>\n'
   t += "</td>\n";
   t += '<td width=8 nowrap rowspan=' + this.ycells + '>' + this.genClearImg(1, 1) + '</td>'

   return t
}

Chart.prototype.genBarImg = function(i, j, y, h, x) {

   var a = ''
   if (this.legends && this.legends[i]) a += this.legends[i] + ': '
   if (this.tags) a += this.tags[j] + ', '
   a += y
   if (this._style == Chart_Percent) a += '%'

   var n = (this._style == Chart_Single) ? j : i
   if (this.colours && n < this.colours.length) n = this.colours[n]

   var b = (this.borderBars && n > -1) ? 1 : 0 //was > 0

   return this.genNumImg(n, this.bscale - 2 * b, h - 2 * b,
      x + ' class=gBar alt="' + a + '"') //changed by Theo, to have a class for the bars
   //was   x + ' border="' + b + '" alt="' + a + '"')
}

Chart.prototype.genColTD = function(al) {

   var t = '<td valign="' + al + '"'
   if (this.inColour) t += ' bgcolor="' + this.inColour + '"'
   t += '>'
   return t
}

Chart.prototype.genBars = function(al, dv) {

   var t = '', h, y
   for (var j = 0; j < this.count; j++) {
      t += this.genColTD(al)
      for (var i = 0; i < this.rows.length; i++) {
         if (j < this.rows[i].length)
            y = this.rows[i][j]
         else
            y = 0
         h = dv * this.vscale * (y - this._base)
         if (h > 0)
            t += this.genBarImg(i, j, y, h, 'vspace=0 hspace=0 align="' + al + '"')
         else
            t += this.genClearImg(this.bscale, 5, 'border=0 align="' + al + '"')
         }
      t += '</td>'
      t += this.genColTD(al)
      t += this.genClearImg(1, 5, 'border=0 align="' + al + '"')
      t += '</td>\n'
      }
   return t
}

Chart.prototype.buildReg = function() {

   var t = this.genTop()

// above axis
   if (this.ymax > 0) {
      t += "<tr>"
      if (this.scale) t += this.genPosScale(0, this.ymax);
      t += this.genBars('bottom', 1)
      t += "</tr>"
      }

   if (this.ymax >= 0) t += this.genXAxis((this.ymin <= 0))

// below axis
   if (this.ymin < 0) {
      t += "<tr>\n";
      if (this.scale) t += this.genNegScale(this.ymin, 0);
      t += this.genBars('top', -1)
//      if (this.ymax == 0) t += this.genLegend(2)
      t += "</tr>\n";
      t += this.genXAxis(false)
      }

   t += this.genBottom()
   return t
}

Chart.prototype.buildStack = function() {

   var t = this.genTop()
   t += "<tr>\n";
   if (this.scale) t += this.genPosScale(0, this.ymax);
   for (var j = 0; j < this.count; j++) {
      t += this.genColTD('bottom')

      var i1 = 0, s = 1, drawn = false
      if (this._style == Chart_Percent) {
         var k = 0, s = 0
         for (var i = 0; i < this.rows.length; i++) {
            if (j < this.rows[i].length) s += this.rows[i][j]
            }
         if (s > 0) s = 100 / s

         i1--
         for (var i = 0; i < this.rows.length; i++) {
            if (j < this.rows[i].length) {
               this.rows[i][j] = Math.round(s * this.rows[i][j] * 10) / 10
               if (i1 < 0 && this.rows[i][j] > 0)
                  i1 = i
               else
                  k += Math.round(this.vscale * this.rows[i][j])
               }
            }
         if (i1 >= 0 && k < this.height) {
            t += this.genBarImg(i1, j, Math.round((this.height - k) / this.vscale * 10) / 10,
               this.height - k)
            t += '<br>\n';
            i1++
            drawn = true;
            }
         }

      for (var i = i1; i < this.rows.length; i++) {
         if (i < this.rows[i].length) {
            t += this.genBarImg(i, j, this.rows[i][j], Math.round(this.vscale * this.rows[i][j]))
            t += '<br>\n';
            drawn = true;
            }
         }
      if (!drawn) t += this.genClearImg(parseInt(this.hscale), 1)
      t += '</td>\n'
      t += this.genColTD('top') + this.genClearImg(1, 5) + '</td>\n'
      }

   t += "</tr>\n";

   t += this.genXAxis((this.ymin <= 0))

   t += this.genBottom()
   return t
}

Chart.prototype.build = function() {

   if (!this.rows) return ''

   if (this.rows.length == 0)
      return '<table><tr><td><TT>[empty graph]</TT></td></tr></table>\n'

   this.countData()
   this.calcRange()

   this._base  = 0
   this._width = this.width
   this.err    = false

   if (this.style == Chart_Percent && this.ymin >= 0) {
      this.rescaleRel();
      return this.buildStack()
      }
   if (this.style == Chart_Stacked && this.ymin >= 0) {
      this.rescaleStack();
      return this.buildStack()
      }
   this.rescale();
   return this.buildReg()
}

Chart.prototype.writeTo = function(d) {

   var doc = d || document
   doc.write(this.build())
}


