/*
  Defines ActiveInterface if it doesn’t already exist, using the boolean OR operator
  to provide a default value if one isn’t found.
  Could also use
    if(!window.ActiveInterface) ActiveInterface = {};
*/
var ActiveInterface = window.ActiveInterface || {};

ActiveInterface.IndicatorViews = (function() {

   // Private members
   var privateMember1 = false;
   var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
   function privateMethod1() {
      ;
   }

   // -------------------------------------------------------------------------
   function makeHtmlTitle(csettings, mid, charttitle) {

      var cstitle = csettings.title.replace("|","<br/>");
      var mover = csettings.measureOverrides["m"+mid];
      if (typeof(mover) != "undefined" && mover.length > 0 && mover[0].length > 0) { 
         cstitle = cstitle.replace("?",mover[0]);
      }
      if (charttitle)
         cstitle += "<br/>" + charttitle;
      return cstitle;
   }

   // -------------------------------------------------------------------------
   function addCommas(nStr, precision) {
      nStr += '';
      if (nStr.indexOf('.') != -1 && precision) {
         nStr = parseFloat(nStr).toFixed(precision).toString();
      }
      x = nStr.split('.');
      x1 = x[0];
      x2 = x.length > 1 ? '.' + x[1] : '';
      var rgx = /(\d+)(\d{3})/;
      while (rgx.test(x1)) {
         x1 = x1.replace(rgx, '$1' + ',' + '$2');
      }
      return x1 + x2;
   }

   // -------------------------------------------------------------------------
   function singleRecentColumn(indata,tsettings) {

      var mrv, mrfv;
      var region;
      var col;
      var rc = indata.getNumberOfRows();
      var cc = indata.getNumberOfColumns();

      // build new horizontally flattened table
      var outdata = new google.visualization.DataTable();
      outdata.addColumn('string', 'Region');
      outdata.addColumn('number', 'Value');

      outdata.addRows(rc);

      var c1 = indata.getColumnLabel(cc-1);

      if (typeof(tsettings) != "undefined") {
         if (tsettings.columnFormat == "year") {
            c1 = c1.substring(0,4);
         } else if (tsettings.columnFormat.length > 0) {
            c1 = tsettings.columnFormat;
         } else {
            // default HACK: use latest period for new table column
            c1 = c1.substring(0,4)
         }
      } else {
         // default HACK: use latest period for new table column
         c1 = c1.substring(0,4)
      }

      outdata.setColumnLabel(1,c1);

      for (var i = 0; i < rc; i++) {
         col = cc-1;

         do {
            mrv = indata.getValue(i, col);
            mrfv = indata.getFormattedValue(i, col);
         } while (mrv == null && --col >= 0 );
         if (mrv == null) {
            mrv = 0;
            mrfv = "0";
         }

         outdata.setValue(i, 1, mrv);
         outdata.setFormattedValue(i, 1, mrfv);

         region = indata.getValue(i, 0);
         // HACK - only works for years
         if (col != cc-1)
            region += " (" + indata.getColumnLabel(col).substring(0,4) + ")";
         outdata.setValue(i, 0, region);
      }
      return outdata;

   }

   // -------------------------------------------------------------------------
   function addBenchmarkRow(data, numfmt, benchmark) {

      var rc = data.getNumberOfRows();
      var s = 0; // non pgh sum
      var hadBench = false;
      var dv;

      for (var i = 0; i < rc; i++) {
         dv = data.getValue(i, 0);
         if (dv.substring(0,5) == "Bench") {
            hadBench = true;
            break;
         } else if (dv.indexOf(benchmark) == -1) {
            s += data.getValue(i, 1);
         }
      }

      if (!hadBench) {
         rc--;
         // add benchmark row
         data.insertRows(rc,1);
         data.setValue(rc, 0, "Benchmark avg");
         // set value to average
         dv = s/(rc+1);
         data.setValue(rc, 1, dv);
         data.setFormattedValue(rc, 1, dv.numberFormat(numfmt));
      }
   }

   // -------------------------------------------------------------------------
   function addBenchmarkRow2(data,benchmark) {

      var rc = data.getNumberOfRows();
      var s1 = 0; // non pgh col1 sum
      var s2 = 0; // non pgh col2 sum
      var dv;

      for (var i = 0; i < rc; i++) {
         dv = data.getValue(i, 0);
         if (dv.indexOf(benchmark) == -1) {
            s1 += data.getValue(i, 1);
            s2 += data.getValue(i, 2);
         }
      }

      rc--;
      // add benchmark row
      data.insertRows(rc, 1);
      data.setValue(rc, 0, "Benchmark avg");
      // set value to average
      data.setValue(rc, 1, s1/(rc+1));
      data.setValue(rc, 2, s2/(rc+1));

   }

   // -------------------------------------------------------------------------
   function bestscale(umin,umax)
   {

      var PENALTY = 0.02;
      var retval = {};

      var ulow = [];
      var uhigh = [];
      var uticks = [];

      goodscales(umin,umax,ulow,uhigh,uticks);

      var udelta = umax - umin;

      var ufit = [];
      var fit = [];
      var k = 0;

      for (var i=0; i<=8; i++) {
         ufit[i] = ((uhigh[i] - ulow[i]) - udelta)/(uhigh[i] - ulow[i]);
         fit[i] = 2*ufit[i] + PENALTY * Math.pow( ((uticks[i] - 6.0)>1.0)?(uticks[i] - 6.0):1.0 ,2.0);
         if (i > 0) {
            if (fit[i] < fit[k]) {
               k = i;
            }
         }
      }

      var ticks = uticks[k];
      if (ticks < 2) {
         ticks = 2;
      }
      retval.low = ulow[k];
      retval.high= uhigh[k];
      retval.ticks = ticks;

      return retval;

   }

   //------------------------------------------------------------------------
   function goodscales(xmin, xmax, low, high, ticks)
   { 
      var bestDelta = [0.1, 0.2, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0];

      var i;
      if (xmin == xmax) {
         for (i=0; i<=8; i++) {
            low[i] = xmin;
            high[i] = xmax+1;
            ticks[i] = 1;
         }
         return;
      }

      var xdelta = xmax - xmin;
      var delta = new Array(9);

      for (var i=0; i<=8; i++) {
         delta[i] = Math.pow(10,Math.round(log10(xdelta)-1)) * bestDelta[i];
         high[i] = delta[i] * Math.ceil(xmax/delta[i]);
         low[i] = delta[i] * Math.floor(xmin/delta[i]);
         ticks[i] = Math.round((high[i]-low[i])/delta[i]) + 1;
      }
   }

   //------------------------------------------------------------------------
   function log10(v)
   {
      return Math.log(v) / Math.log(10);
   }

   // -------------------------------------------------------------------------
   function log(func, msg) {
      try {
         ; //console.info('ActiveInterface.IndicatorViews::' + func + '(): ' + msg);
      } catch(e) {}
   }


   // Everything returned in the object literal is public, but can access the
   // members in the closure created above.
   return {
      
      // Public members
      dataTables : null,
      viewElements : null,
      viewSettings : null,
      viewType: 'table',
      
      // Methods
      
      init : function(vsettings) {
         this.viewSettings = vsettings;
         this.dataTables = new Object();
         log('init', 'Begin initiation');
      },

      // ---------------------------------------------------------------
      setDataSourceInfo: function(csettings, mid)
      {
         var mover = csettings.measureOverrides["m"+mid];
         // if measure overrides
         if (typeof(mover) != "undefined") {
            // if override has a "source label"
            if (mover[3].length > 0 ) {
               // if override has a "source url"
               if (mover[4].length > 0 ) {
                  $("#subbody .datasourceinfo").html("<a href='" +mover[4]+ " '>" +mover[3]+ "</a>");
               } else {
                  $("#subbody .datasourceinfo").text(mover[3]);
               }
            }
         }
      },

      // ---------------------------------------------------------------
      showRawTable : function(dataname, target1, target2, tsettings, csettings, mid, type) {

         var data = this.dataTables[dataname];
         var rh;
         var dv;
         var nf;
         var s;
         var pghrow = -1;
         var comprow = -1;

         var cc = data.getNumberOfColumns();
         var rc = data.getNumberOfRows();

         if (tsettings.columnFormat == "year") {
            var c1;
            for (var j = 1; j < cc; j++) {
               c1 = data.getColumnLabel(j);
               data.setColumnLabel(j,c1.substring(0,4));
            }
         }
         if (tsettings.rowFormat == "month") {
            data.insertColumn(0, "string", "Month");
            for (var i = 0; i < rc; i++) {
               rh = data.getValue(i, 1);
               data.setValue(i, 0, months[parseInt(rh)-1]);
            }
            data.removeColumn(1);

            // add total row at bottom
            data.insertRows(rc,1);
            data.setValue(rc, 0, "Year to date");
            for (var j = 1; j < cc; j++) {
               nf = data.getColumnPattern(j);
               s = 0;
               for (var i = 0; i < rc; i++) {
                  s += data.getValue(i, j);
               }
               data.setValue(rc, j, s);
               data.setFormattedValue(rc, j, s.numberFormat(nf));
            }

         } else {

            // add benchmark row (if needed)
            if (this.viewSettings.calcAvg) {
               for (var i = 0; i < rc; i++) {
                  dv = data.getValue(i, 0);
                  if (dv.substring(0,5) == "Bench") {
                     comprow = i;
                     break;
                  }
               }
               // no bench found - add one
               if (comprow == -1) {
                  data.insertRows(rc,1);
                  data.setValue(rc, 0, "Benchmark avg");
                  for (var j = 1; j < cc; j++) {
                     nf = data.getColumnPattern(j);
                     // sum across regions
                     s = 0;
                     for (var i = 0; i < rc; i++) {
                        dv = data.getValue(i, 0);
                        if (dv.indexOf(this.viewSettings.benchmarkCity) == -1 && dv.substring(0,2) != "US") {
                           s += data.getValue(i, j);
                        }
                     }
                     dv = s/rc;
                     data.setValue(rc, j, dv);
                     data.setFormattedValue(rc, j, dv.numberFormat(nf));
                  }
                  comprow = rc;
               }
            } //if (calcAvg)
            
         } //rowformat == "month"

         var t = new google.visualization.Table(document.getElementById(target1));
         t.draw(data, {showRowNumber: false});


         if (target2 == null) {

            var title = makeHtmlTitle(csettings, mid, null);
            $("#chart_title").html(title);

         } else {

            // find benchmark - first in array will be selected
            for (var i = 0; i < rc; i++) {
               region = data.getValue(i, 0);
               if (region.indexOf(this.viewSettings.benchmarkCity) != -1 || region.indexOf(this.viewSettings.benchmarkCounty) != -1) {
                  pghrow = i;
               }

            }


            $("#"+target2).empty();

            if (pghrow == -1) return;

            var data2 = new google.visualization.DataTable();
            data2.addRows(cc-1);

            nf = data.getColumnPattern(1);

            data2.addColumn('string', 'Period');
            data2.addColumn('number', data.getValue(pghrow, 0));
            if (type == "std" && comprow != -1) {
               data2.addColumn('number', data.getValue(comprow, 0));
            }


            var vstitle = data.getValue(pghrow, 0);

            if (type == "std" && comprow != -1)
               vstitle += " vs. " + data.getValue(comprow, 0);

            if (type == "index") vstitle += " index";

            var title = makeHtmlTitle(csettings, mid, vstitle);
            $("#chart_title").html(title);

            /*
              8/26/10: the current use of index chart (school enrollment) doesn't need
              benchmark in chart. May eventually need to make this driven by a separate
              chart setting (e.g "show benchmark))
            */
            
            if (type == "std") {
               for (var j = 1; j < cc; j++) {
                  data2.setValue(j-1, 0, data.getColumnLabel(j));

                  dv = data.getValue(pghrow, j);
                  data2.setValue(j-1, 1, dv);
                  data2.setFormattedValue(j-1, 1, dv.numberFormat(nf));

                  dv = data.getValue(comprow, j);
                  data2.setValue(j-1, 2, dv);
                  data2.setFormattedValue(j-1, 2, dv.numberFormat(nf));
               }

            } else {
               // index chart. see http://www.dallasfed.org/data/basics/indexing.html
               var d0 = data.getValue(pghrow, 1);
               for (var j = 1; j < cc; j++) {
                  data2.setValue(j-1, 0, data.getColumnLabel(j));
                  // enter data as indexed to first data point
                  dv = data.getValue(pghrow, j);
                  dv = (dv/d0)*100;
                  data2.setValue(j-1, 1, dv);
               }
            }


            /*
            // test code
            // This seems to have same effect as doing a setFormattedValue and
            // in fact takes precedence over it. But it doesn't change the y-axis
            // formatting
            var formatter = new google.visualization.NumberFormat(
            {
            groupingSymbol:',', 
            decimalSymbol: '.',
            fractionDigits: 1,
            suffix: '%'
            }
            );
            formatter.format(data2, 1);
            formatter.format(data2, 2);
            */
            //
            var config = {pointSize:5,colors:['#cb2027','#686868'],backgroundColor:'#ebebeb',legendBackgroundColor:'#ebebeb',axisFontSize:12,legendFontSize:12,titleFontSize:12,width:csettings.width,height:csettings.height,is3D:false,reverseAxis:false,legend:'bottom',vAxis:{format:nf},chartArea: {top:10, left:60,height:csettings.height-60, width:csettings.width-60}};

            var c = new google.visualization.LineChart(document.getElementById(target2));
            c.draw(data2, config);

            google.visualization.events.addListener(t, 'select', 
                                                    function () {

                                                       comprow = t.getSelection()[0].row;
                                                       vstitle = data.getValue(pghrow, 0) + " vs. " + data.getValue(comprow, 0);
                                                       title = makeHtmlTitle(csettings, mid, vstitle);
                                                       $("#chart_title").html(title);

                                                       // if there was only one column (was "std") add a 2nd
                                                       if (data2.getNumberOfColumns() == 2)
                                                          data2.addColumn('number', data.getValue(comprow, 0));

                                                       data2.setColumnLabel(2,data.getValue(comprow, 0));

                                                       var d0 = data.getValue(pghrow, 1);
                                                       var d1 = data.getValue(comprow, 1);
                                                       for (var j = 1; j < cc; j++) {
                                                          data2.setValue(j-1, 0, data.getColumnLabel(j));
                                                          if (type == "std") {
                                                             data2.setValue(j-1, 1, data.getValue(pghrow, j));
                                                             data2.setValue(j-1, 2, data.getValue(comprow, j));
                                                          } else {
                                                             data2.setValue(j-1, 1, (data.getValue(pghrow, j)/d0)*100);
                                                             data2.setValue(j-1, 2, (data.getValue(comprow, j)/d1)*100);
                                                          }
                                                       }
                                                       c.draw(data2, config);

                                                    }
                                                   );
            
         } // if (target2)

      },

      // ---------------------------------------------------------------
      showChangeTable : function(dataname, target1, target2, tsettings, csettings, mid) {
         var data = this.dataTables[dataname];

         var rc = data.getNumberOfRows();
         var cc = data.getNumberOfColumns();
         var c1, t1, t2, ac, pc;
         var pghrow;
         var comprow;
         var region;
         var formatter;
         var s;
         var nf;
         var dv;

         // since we calculate delta, new table will have one fewer value columns
         var newcc = cc - 1; 

         // add benchmark row
         data.insertRows(rc,1);
         data.setValue(rc, 0, "Benchmark avg");
         for (var j = 1; j < cc; j++) {
            //nf = data.getColumnPattern(j);
            // sum across regions
            s = 0;
            for (var i = 0; i < rc; i++) {
               s += data.getValue(i, j);
            }
            dv = s/rc;
            data.setValue(rc, j, dv);
            //data.setFormattedValue(rc, j, dv.numberFormat(nf));
         }

         var data2 = new google.visualization.DataTable();
         data2.addRows(rc+1); // add one for benchmark

         data2.addColumn('string', 'Region');
         for (var j = 1; j < newcc; j++) {
            c1 = data.getColumnLabel(j+1);
            if (tsettings.columnFormat == "year") {
               c1 = c1.substring(0,4);
            } else if (tsettings.columnFormat == "month") {
               c1 = months[parseInt(c1)-1];
            }
            data2.addColumn('number', c1);
         }

         for (var i = 0; i < rc+1; i++) {
            region = data.getValue(i, 0);
            if (region.indexOf(this.viewSettings.benchmarkCity) != -1)
               pghrow = i;
            data2.setValue(i, 0, region);
            for (var j = 1; j < newcc; j++) {
               t1 = data.getValue(i, j);
               t2 = data.getValue(i, j+1);
               if (t1 != null && t2 != null && t1 != 0) {
                  ac = (t2-t1);
                  pc = ac / t1 * 100;
                  data2.setValue(i, j, pc);
                  data2.setFormattedValue(i, j, pc.toFixed(1) + "%");
               }
            }
         }

         if (tsettings.showBar == true) {
            formatter = new google.visualization.TableBarFormat({width:40,showValue:false});
         } else {
            formatter = new google.visualization.NumberFormat(
               {fractionDigits:1, suffix: '%', negativeColor: 'firebrick', negativeParens: false}
            );
         }

         for (var j = 1; j < newcc; j++) {
            formatter.format(data2, j);
         }

         $("#"+target1).empty();
         var t = new google.visualization.Table(document.getElementById(target1));
         t.draw(data2, {allowHtml: true, showRowNumber: false});

         if (target2 != null) {

            $("#"+target2).empty();
            //jQuery('<span>').attr("id","cmsg").appendTo("#table2_div").text("Click on a region to see chart of values");

            var data3 = new google.visualization.DataTable();
            data3.addRows(newcc-1);

            // default to comparing to added benchmark row
            comprow = rc;

            data3.addColumn('string', 'Period');
            data3.addColumn('number', data2.getValue(pghrow, 0));
            data3.addColumn('number', data2.getValue(comprow, 0));

            var vstitle = data2.getValue(pghrow, 0) + " vs. " + data2.getValue(comprow, 0);
            var title = makeHtmlTitle(csettings, mid, vstitle);
            $("#chart_title").html(title);

            for (var j = 1; j < newcc; j++) {
               data3.setValue(j-1, 0, data2.getColumnLabel(j));
               data3.setValue(j-1, 1, data2.getValue(pghrow, j)/100);
               data3.setValue(j-1, 2, data2.getValue(comprow, j)/100);
            }

            var c = new google.visualization.LineChart(document.getElementById(target2));
            var config = {pointSize:5,colors:['#cb2027','#686868'],backgroundColor:'#ebebeb',legendBackgroundColor:'#ebebeb',axisFontSize:12,legendFontSize:12,titleFontSize:12,width:csettings.width,height:csettings.height,is3D:false,reverseAxis:false,legend:'bottom',vAxis:{format:'#%'},chartArea:{top:10, left:40,height:csettings.height-60, width:csettings.width-10}};
            c.draw(data3, config);

            google.visualization.events.addListener(t, 'select', 
                                                    function () {
                                                       //$("#"+target2+ " #cmsg").empty();
                                                       comprow = t.getSelection()[0].row;

                                                       vstitle = data2.getValue(pghrow, 0) + " vs. " + data2.getValue(comprow, 0);
                                                       title = makeHtmlTitle(csettings, mid, vstitle);
                                                       $("#chart_title").html(title);

                                                       data3.setColumnLabel(2,data2.getValue(comprow, 0));
                                                       for (var j = 1; j < newcc; j++) {
                                                          data3.setValue(j-1, 0, data2.getColumnLabel(j));
                                                          data3.setValue(j-1, 1, data2.getValue(pghrow, j)/100);
                                                          data3.setValue(j-1, 2, data2.getValue(comprow, j)/100);
                                                       }

                                                       c.draw(data3, config);

                                                    }
                                                   );

         } // if (target2)

      },

      // ---------------------------------------------------------------
      showStandardTable : function(dataname, target, tsettings) {
         var indata = this.dataTables[dataname];
         var rc = indata.getNumberOfRows();
         if (rc == 0) {
            $("#"+target).empty();
            return;
         }

         var numfmt = indata.getColumnPattern(1);

         var data = singleRecentColumn(indata,tsettings);

         if (this.viewSettings.calcAvg) {
            addBenchmarkRow(data,numfmt,this.viewSettings.benchmarkCity);
         }

         var rc = data.getNumberOfRows();

         if (tsettings.showBar == true) {
            data.addColumn('number', '');
         }

         if (tsettings.showBar == true) {
            data.addColumn('number', '');
            for (var i = 0; i < rc; i++) {
               data.setValue(i, 2, data.getValue(i, 1));
            }
            var formatter = new google.visualization.TableBarFormat({width:120,showValue:false});
            formatter.format(data, 2);
         }

         var t = new google.visualization.Table(document.getElementById(target));
         var sortAsc = tsettings.sort != "desc";
         var sortCol = tsettings.sort == "label" ? 0 : 1;
         t.draw(data, {sortColumn:sortCol, sortAscending:sortAsc, allowHtml: true, showRowNumber: false});

      },

      // ---------------------------------------------------------------
      showMonthYearLineChart : function(dataname, charttarget, tabletarget, csettings, tsettings) {
         var data = this.dataTables[dataname];

         var rc = data.getNumberOfRows();
         var cc = data.getNumberOfColumns();

         var data2 = new google.visualization.DataTable();

         var seriescolors = new Array();

         data2.addColumn('string', 'Month');
         for (var j = 1; j < cc; j++) {
            data2.addColumn('number', data.getColumnLabel(j).substring(0,4));
         }

         data2.addRows(rc);

         for (var i = 0; i < rc; i++) {
            data2.setValue(i, 0, months[i]);
            for (var j = 1; j < cc; j++) {
               data2.setValue(i, j, data.getValue(i, j));
            }
         }

         var data3 = new google.visualization.DataTable();
         data3.addColumn('string', 'Year');
         data3.addColumn('number', 'Total Traffic');
         data3.addRows(cc-1);

         var s;
         for (var j = 1; j < cc; j++) {
            data3.setValue(j-1, 0, data.getColumnLabel(j).substring(0,4));
            s = 0;
            for (var i = 0; i < rc; i++) {
               s += data.getValue(i, j);
            }
            data3.setValue(j-1, 1, s);
         }

         $("#"+charttarget).empty();
         var c = new google.visualization.LineChart(document.getElementById(charttarget));
         var config = {pointSize:5,colors:seriescolors, axisFontSize:12, legendFontSize:12, titleFontSize:12, width:csettings.width, height:csettings.height, title:csettings.title, is3D: false, reverseAxis: false, legend:'bottom',chartArea: {top:10, left:40,height:csettings.height-40, width:csettings.width-10}};
         c.draw(data2, config);
         $("#"+tabletarget).empty();

         var t = new google.visualization.Table(document.getElementById(tabletarget));
         t.draw(data3, {sortAscending:true, allowHtml: true, showRowNumber: false});

      },

      // ---------------------------------------------------------------
      showYearMonthColumnChart : function(dataname, target, csettings) {

         var data1 = this.dataTables[dataname];

         var rc = data1.getNumberOfRows();
         var cc = data1.getNumberOfColumns();

         var data3 = new google.visualization.DataTable();
         var seriescolors = new Array();

         data3.addColumn('string', 'Year');
         for (var j = 1; j < cc; j++) {
            data3.addColumn('number', months[j]);
            seriescolors[j-1] = '#336798';
         }

         data3.addRows(rc);

         for (var i = 0; i < rc; i++) {
            data3.setValue(i, 0, data1.getValue(i, 0).toString());
            for (var j = 1; j < cc; j++) {
               data3.setValue(i, j, data1.getValue(i, j));
            }
         }

         $("#"+target).empty();
         var c = new google.visualization.ColumnChart(document.getElementById(target));
         var config = {colors:seriescolors, axisFontSize:12, titleFontSize:12, width:csettings.width, height:csettings.height, title:csettings.title, is3D: false, reverseAxis: false, titleX:'yyyy-mm', legend:'none',chartArea: {top:10, left:40,height:csettings.height-40, width:csettings.width-10}};
         c.draw(data3, config);

      },

      // ---------------------------------------------------------------
      showPackedColumnChart : function(dataname, target, csettings) {

         var data1 = this.dataTables[dataname];
         var rc = data1.getNumberOfRows();
         var cc = data1.getNumberOfColumns();

         var data2 = new google.visualization.DataTable();
         data2.addColumn('string', 'Year');

         for (var j = 1; j < cc; j++) {
            data2.addColumn('number', data1.getColumnLabel(j));
         }
         data2.addRows(rc);
         for (var i = 0; i < rc; i++) {
            data2.setValue(i, 0, data1.getValue(i, 0).toString());
            for (var j = 1; j < cc; j++) {
               data2.setValue(i, j, data1.getValue(i, j));
            }
         }

         $("#"+target).empty();
         var c = new google.visualization.ColumnChart(document.getElementById(target));
         var config = {axisFontSize:12, legendFontSize:12, titleFontSize:12, width:csettings.width, height:csettings.height, title:csettings.title, is3D: false, reverseAxis: false, legend:'right',chartArea: {top:10, left:40,height:csettings.height-40, width:csettings.width-10}};
         c.draw(data2, config);
      },

      // ---------------------------------------------------------------
      showPghVsBenchChart : function(dataname, charttarget, tabletarget, csettings, tsettings) {

         var data = this.dataTables[dataname];
         var numfmt = data.getColumnPattern(1);

         var rc = data.getNumberOfRows();
         var cc = data.getNumberOfColumns();
         var s = 0; // non pgh sum
         var p = 0; // pgh value
         var ac = 0; // actual regions in avg
         var dv;
         var l;

         data2 = new google.visualization.DataTable();
         data2.addColumn('string', 'Year');
         data2.addColumn('number', this.viewSettings.benchmarkCity);
         if (this.viewSettings.calcAvg) {
            data2.addColumn('number', 'Benchmark avg');
         }

         data2.addRows(rc);

         for (var i = 0; i < rc; i++) {
            data2.setValue(i, 0, data.getValue(i, 0).toString());
            s = 0;
            ac = 0;
            dv = 0;

            for (var j = 1; j < cc; j++) {
               l = data.getColumnLabel(j);
               dv = data.getValue(i, j);
               if (dv != 0) {
                  if (l.indexOf(this.viewSettings.benchmarkCity) == -1) {
                     s += dv;
                     ac++;
                  } else {
                     p = dv;
                  }
               }
            }

            data2.setValue(i, 1, p);
            data2.setFormattedValue(i, 1, p.numberFormat(numfmt));
            if (this.viewSettings.calcAvg) {
               dv = s/ac;
               data2.setValue(i, 2, dv);
               data2.setFormattedValue(i, 2, dv.numberFormat(numfmt));
            }
         }

         var rc = data.getNumberOfRows();

         var chdsval = csettings.range;

         // build labels string
         var chxlval = "0:";
         for (var i = 0; i < rc; i++) {
            chxlval += "|" + data2.getValue(i, 0);
         }
         chxlval += "|1:" + csettings.labels;

         var seriescolors = new Array();
         var legendpos = "none";
         seriescolors[0] = csettings.colors[1];
         if (this.viewSettings.calcAvg) {
            seriescolors[1] = csettings.colors[2];
            legendpos = "bottom";
         }

         $("#"+charttarget).empty();
         var c = new google.visualization.ImageChart(document.getElementById(charttarget));
         c.draw(data2, {cht:'lc', chds: chdsval, chxl: chxlval, colors:seriescolors, width:csettings.width, height:csettings.height, title:csettings.title, legend:legendpos});
         $("#"+tabletarget).empty();

         var t = new google.visualization.Table(document.getElementById(tabletarget));
         t.draw(data2, {sortAscending:true, allowHtml: true, showRowNumber: false});

      },

      // ---------------------------------------------------------------
      showStandardBarChart : function(dataname, target, csettings) {
         var indata = this.dataTables[dataname];
         var data = singleRecentColumn(indata);
         var numfmt = indata.getColumnPattern(1);

         if (this.viewSettings.calcAvg) {
            addBenchmarkRow(data,numfmt,this.viewSettings.benchmarkCity);
         }

         var data2 = new google.visualization.DataTable();
         data2.addColumn('string', 'Region');
         data2.addColumn('number', 'bench');
         data2.addColumn('number', 'pgh');
         data2.addColumn('number', 'avg');


         // sort and split region/pgh/bench into 3 columns for coloring bars

         var ria = data.getSortedRows([{column: 1}]);
         var rc = ria.length;

         data2.addRows(data.getNumberOfRows());

         var dv;
         var dv2;
         data.addColumn('number', 'Value');
         data.addColumn('number', 'Value');
         data.addColumn('number', 'Value');
         for (var i = 0; i < rc; i++) {
            dv = data.getValue(ria[i], 0);
            dv2 = data.getValue(ria[i], 1);

            data2.setValue(i, 0, dv);

            if (dv.substring(0,5) == "Bench") {
               data2.setValue(i, 1, 0);
               data2.setValue(i, 2, 0);
               data2.setValue(i, 3, dv2);
            } else if (dv.indexOf(this.viewSettings.benchmarkCity) != -1) {
               data2.setValue(i, 1, 0);
               data2.setValue(i, 2, dv2);
               data2.setValue(i, 3, 0);
            } else {
               data2.setValue(i, 1, dv2);
               data2.setValue(i, 2, 0);
               data2.setValue(i, 3, 0);
            }

         }


         $("#"+target).empty();

         var c = new google.visualization.BarChart(document.getElementById(target));
         var config = {width:csettings.width, height:csettings.height, title: csettings.title, isStacked:true,legend:'none', colors:csettings.colors, axisFontSize:12, titleFontSize:12, reverseAxis:false,chartArea: {top:10, left:40,height:csettings.height-40, width:csettings.width-10}};
         c.draw(data2,config);

      },

      // ---------------------------------------------------------------
      showStandardChart : function(dataname, target, csettings, mid) {

         var indata = this.dataTables[dataname];
         var rc = indata.getNumberOfRows();
         if (rc == 0) {
            $("#"+target).empty();
            return;
         }

         var data = singleRecentColumn(indata);
         var numfmt = indata.getColumnPattern(1);

         if (this.viewSettings.calcAvg) {
            addBenchmarkRow(data,numfmt,this.viewSettings.benchmarkCity);
         }

         // add column for colors 
         data.addColumn('number', 'Color');

         // bar colors
         var rc = data.getNumberOfRows();
         var s = 0;
         var dv;
         for (var i = 0; i < rc; i++) {
            dv = data.getValue(i, 0);
            if (dv.indexOf(this.viewSettings.benchmarkCity) != -1) {
               data.setValue(i, 2, 1);
            } else if (dv.substring(0,5) == "Bench") {
               data.setValue(i, 2, 2);
            } else {
               data.setValue(i, 2, 0);
            }
         }

         var colors = csettings.colors;

         // get sorted 
         var sortAsc = csettings.sort != "desc";
         var sortCol = csettings.sort == "label" ? 0 : 1;
         var ria = data.getSortedRows([{column: sortCol, desc: sortAsc}]);
         var rc = ria.length;

         // build labels string
         var chxl = "1:";
         for (var i = 0; i < rc; i++) {
            chxl += "|" + data.getValue(ria[i], 0);
         }

         // build values and colors strings
         // also find min and max values to autoscale
         var low = Number.MAX_VALUE;
         var high = Number.MIN_VALUE;
         var chd = "t:";
         var chco = "";
         var v;
         for (var i = rc-1; i >= 0; i--) {
            // value
            v = data.getValue(ria[i], 1);
            if (v > high) high = v;
            if (v < low) low = v;
            if (v != null)
               chd += v.toFixed(3);
            else
               chd += "0";
            // color
            chco += colors[data.getValue(ria[i], 2)];
            if (i > 0) {
               chd += ",";
               chco += "|";
            }
         }

         // autoscaling logic
         var scaleObj = bestscale(low,high);
         var ticks = scaleObj.ticks;
         var low = scaleObj.low;
         var high = scaleObj.high;
         var spacing = (high-low)/(ticks-1.0);

         // deal with measure specific settings

         // first try with view
         var mover = csettings.measureOverrides["m"+mid+"imagechartandtable"];
         if (typeof(mover) == "undefined")
            // then without
            mover = csettings.measureOverrides["m"+mid];

         var title = csettings.title;
         var axisVal;
         if (typeof(mover) != "undefined" && mover.length > 0 && mover[0].length > 0) { 
            title = title.replace("?",mover[0]);
         }
         if (typeof(mover) != "undefined" && mover[1].length > 0 && csettings.force != "yes") { 
            chxl += "|0:" + mover[1];
         } else if (csettings.labels.length > 0) {
            chxl += "|0:" + csettings.labels;
         } else {
            //autoscale
            chxl += "|0:";
            for (var i=0; i<=ticks-1; i++) {
               axisVal = (low + spacing*i);
               chxl += "|" + axisVal.numberFormat(numfmt);
            }

         }


         var range;
         if (typeof(mover) != "undefined" && mover[2].length > 0 && csettings.force != "yes") { 
            range = mover[2];
         } else if (csettings.range.length > 0) {
            range = csettings.range;
         } else {
            range = "" + low + "," + high;
         }

         var url = "http://chart.apis.google.com/chart";
         url += "?cht=bhg";
         url += "&chs=" + csettings.width +"x"+csettings.height;
         url += "&chds=" + range;
         url += "&chd=" + chd;
         url += "&chxt=" + "x,y";
         url += "&chxr=" + "0,"+range;
         url += "&chtt=" + encodeURIComponent(title);
         url += "&chxl=" + encodeURIComponent(chxl);
         url += "&chco=" + chco;
         url += "&chbh=" + csettings.barsize;

         var imgchart = document.getElementById(target).getElementsByTagName("IMG")[0];

         imgchart.setAttribute("src", url);
         imgchart.setAttribute("title", csettings.title);


         //jQuery('<img>').attr("src",url).appendTo("#chart_div");

      },

      // ---------------------------------------------------------------
      showChange : function(dataname, charttarget, tabletarget, csettings, tsettings, type, mid) {
         var data = this.dataTables[dataname];
         var numfmt = data.getColumnPattern(1);

         if (this.viewSettings.calcAvg) {
            addBenchmarkRow2(data,this.viewSettings.benchmarkCity);
         }

         // add table for absolute change and relative change
         // this way we have option to sort both charts the same
         var data2 = new google.visualization.DataTable();
         data2.addColumn('string', 'Region');

         // basically hard-code to assume is year for now
         data2.addColumn('number', data.getColumnLabel(1).substring(0,4));
         data2.addColumn('number', data.getColumnLabel(2).substring(0,4));

         data2.addColumn('number', 'Change');
         data2.addColumn('number', '%Change');

         // color column
         data2.addColumn('number', 'Color');

         data2.addRows(data.getNumberOfRows());

         // do the change calc
         var rc = data2.getNumberOfRows();

         var t1, t2, ac, pc;
         var ri;
         var city;

         for (var i = 0; i < rc; i++) {

            city = data.getValue(i, 0);
            data2.setValue(i, 0, city);
            t1 = data.getValue(i, 1);
            t2 = data.getValue(i, 2);

            data2.setValue(i, 1, t1);
            if (t1 != null)
               data2.setFormattedValue(i, 1, t1.numberFormat(numfmt));
            data2.setValue(i, 2, t2);
            if (t2 != null)
               data2.setFormattedValue(i, 2, t2.numberFormat(numfmt));

            if (t1 != null && t2 != null) {

               ac = (t2-t1);
               data2.setValue(i, 3, ac);
               data2.setFormattedValue(i, 3, ac.numberFormat(numfmt));

               if (t1 != 0) {
                  pc = ac / t1 * 100;
                  data2.setValue(i, 4, pc);
                  data2.setFormattedValue(i, 4, pc.toFixed(2) + "%");
               }

            } // if (t1 && t2)

            if (city.indexOf(this.viewSettings.benchmarkCity) != -1) {
               data2.setValue(i, 5, 1);
            } else if (city == "Benchmark avg") {
               data2.setValue(i, 5, 2);
            } else {
               data2.setValue(i, 5, 0);
            }

         }

         // deal with measure specific settings
         // first try with view
         var view = "";
         switch (type) {
         case "pct":
            view = "percentchange";
            break;
         case "abs":
            view = "absolutechange";
            break;
         case "both":
            view = "absoluteandpercentchange";
            break;
         case "vchartptable":
            view = "valuechartpercenttable";
            break;
         case "vchartatable":
            view = "valuechartabsolutetable";
            break;
         }
         var mover = csettings.measureOverrides["m"+mid+view];
         if (typeof(mover) == "undefined")
            // then without
            mover = csettings.measureOverrides["m"+mid];

         var title = csettings.title;
         if (typeof(mover) != "undefined" && mover.length > 0 && mover[0].length > 0) { 
            title = title.replace("?",mover[0]);
         }

         var low = Number.MAX_VALUE;
         var high = Number.MIN_VALUE;

         // new generic version

         var sortAsc = csettings.sort != "desc";
         var ria;
         if (type == "vchartptable" || type == "vchartatable") 
            ria = data.getSortedRows([{column: 2, desc: sortAsc}]);
         else if (type != "pct")
            ria = data2.getSortedRows([{column: 3, desc: sortAsc}]);
         else
            ria = data2.getSortedRows([{column: 4, desc: sortAsc}]);

         rc = ria.length;

         var chd = "t:";
         var chco = "";
         var v;
         for (var i = 0; i < rc; i++) {
            if (type == "vchartptable" || type == "vchartatable") 
               v = data.getValue(ria[i], 2)
            else if (type != "pct")
               v = data2.getValue(ria[i], 3)
            else
               v = data2.getValue(ria[i], 4);

            if (v == null) v = 0;

            if (v > high) high = v;
            if (v < low) low = v;

            chd += v.toFixed(3);

            chco += csettings.colors[data2.getValue(ria[i], 5)];
            if (i < rc-1) {
               chd += ",";
               chco += "|";
            }
         }

         // autoscaling logic
         var scaleObj = bestscale(low,high);
         var ticks = scaleObj.ticks;
         var low = scaleObj.low;
         var high = scaleObj.high;
         var spacing = (high-low)/(ticks-1.0);

         var chxl = "1:";
         for (var i = rc-1; i >= 0; i--) {
            if (type == "vchartptable" || type == "vchartatable") 
               chxl += "|" + data.getValue(ria[i], 0);
            else
               chxl += "|" + data2.getValue(ria[i], 0);
         }

         if (typeof(mover) != "undefined" && mover[1].length > 0 && csettings.force != "yes") { 
            chxl += "|0:" + mover[1];
         } else if (csettings.labels.length > 0) {
            chxl += "|0:" + csettings.labels;
         } else {
            //autoscale
            chxl += "|0:";
            for (var i=0; i<=ticks-1; i++) {
               axisVal = (low + spacing*i);
               chxl += "|" + axisVal.numberFormat(numfmt);
            }
         }

         var range;
         if (typeof(mover) != "undefined" && mover[2].length > 0 && csettings.force != "yes") { 
            range = mover[2];
         } else if (csettings.range.length > 0) {
            range = csettings.range;
         } else {
            range = "" + low + "," + high;
         }

         // build image chart url
         url = "http://chart.apis.google.com/chart";
         url += "?cht=bhg";
         url += "&chs=" + csettings.width +"x"+csettings.height;
         url += "&chds=" + range;
         url += "&chd=" + chd;
         url += "&chxt=" + "x,y"
         url += "&chxr=" + "0,"+range;
         url += "&chtt=" + encodeURIComponent(title);
         url += "&chxl=" + encodeURIComponent(chxl);
         url += "&chco=" + chco;
         url += "&chbh=" + csettings.barsize;

         var imgchart = document.getElementById(charttarget).getElementsByTagName("IMG")[0];

         imgchart.setAttribute("src", url);
         imgchart.setAttribute("title", csettings.title);
         
         // remove color column
         data2.removeColumn(5);

         if (type == "abs" || type == "vchartatable")
            data2.removeColumn(4);
         else if (type == "pct" || type == "vchartptable")
            data2.removeColumn(3);

         /*
           var formatter = new google.visualization.NumberFormat(
           {fractionDigits:0, negativeColor: 'red', negativeParens: false});
           formatter.format(data2, 1);
           formatter.format(data2, 2);
           formatter.format(data2, 3);
         */

         var formatter = new google.visualization.ColorFormat();
         formatter.addRange(null, 0, 'firebrick');
         formatter.addRange(0, null, 'black');
         formatter.format(data2, 3);

         if (type == "pct" || type == "both") {
            formatter = new google.visualization.NumberFormat(
               {suffix: '%', negativeColor: 'firebrick', negativeParens: false});
            formatter.format(data2, (type=="pct"?3:4));
         }

         var sc = (type == "vchartptable" || type == "vchartatable") ? 2 : 3;

         var sortAsc = tsettings.sort == "desc";
         var t = new google.visualization.Table(document.getElementById(tabletarget));
         t.draw(data2, {sortColumn:sc, sortAscending:sortAsc, allowHtml: true, showRowNumber: false});

      }

   };

})();

