/*
 * Google Visualization API Wrapper --  v1.0
 * Published : 25/05/2009
 * http://www.smallmeans.com/apps/googleVizAPI
 * Copyright (c) 2009 smallmeans.com
 * Dual licensed under MIT and GPL.
 */

if(typeof googleVizAPI == 'undefined')
  googleVizAPI = {
};

googleVizAPI = {  
  timeValueIndex:1,
  bubbles:[],
  config:{
    width :700,	     //size in pixels	
    height:400,	    //uhmm.. me, too!
    showBubbles:true,
    showTrails:false,
    playDuration:2,
    stateVersion:3,
    xLambda:0,       // 1 for linear scale
    yLambda:0,       // 0 for LOG scale
    defaults:{
    }
  },
  $: function(id) {
    return document.getElementById(id);
  },
  $E: function(tag) {
    return document.getElementsByTagName(tag);
  },
  // once the module is loaded, this function is called and we're good to go        
  onload: function() {
   (function(){
     this.draw();    
     }
    ).call(googleVizAPI);  
  },
  draw: function(chartElement) {
    var data=this.data;
    var items=data.rows.length;
    var table = new google.visualization.DataTable(),c=0;
    var chartElement=chartElement||this.$(this.config.containerID);
    if(!chartElement){
      chartElement=document.getElementsByTagName("div")[0];
    }

    table.addRows(items);
    for(column in data.columns){
      try{
        table.addColumn(data.columns[column].toString(),column);
        if(data.columns[column].equals('date')){
          this.isNativeDate=true;
        }
      }
      catch(aarrrrghh){
        this.appendText(chartElement,'could not add column: '+aarrrrghh);
      }
    }
    isFiltered=typeof this.config.filterBubbles === "object" && this.config.filterBubbles.fieldNr>=0;
    hasThreshold=typeof this.config.filterData === "object" && this.config.filterData.fieldNr>=0;
    var _native=['function','object'];
    //psst.. 'native' is a keyword in Google Chrome, now I/U know..  
    for(row in data.rows){
      for(column in data.rows[row]){
        if(_native.contains(typeof data.rows[row][column])){
          continue;
        }
        if(c==this.timeValueIndex && this.isNativeDate){
          value=this.parseDate(data.rows[row][column]);
        }
        else{
          value=data.rows[row][column];
        }
        if(c==0){
            name=value;
        }
        /*if(hasThreshold&&this.config.filterData.fieldNr==c+1){
         if(!eval(value+this.config.filterData.expr)){
           continue;
         }
        }*/
        if(this.config.charttype.equals('MotionChart')){
          if(isFiltered){
            if(this.config.filterBubbles.fieldNr==c+1 && eval(value+this.config.filterBubbles.expr)){
              this.bubbles.push('{"key":{"dim0":"'+name+'"}}');
            }
          }else{
            this.bubbles.push('{"key":{"dim0":"'+name+'"}}');
          }          
        }
        try{
          table.setValue(row*1, c++, value);
        }
        catch(ohhhScheisse){
          this.appendText(chartElement,'Could not set value at row '+row+' --- '+ohhhScheisse);
          this.debug('choked on row: '+row+", field:"+c+", containing ->"+value);           
          return;
        }
      }
      c=0;
    }
    this.debug('..throwing '+items+' paintballs at the canvas..');
    this.chart = this.getConstructor(chartElement);
    this.table=table;
    this.render();  
  },
  setVal: function(key,val) {
    this.config[key]=val;
    this.render();
  },
  render: function() {
    var vars=[];
    var icons=[];
	delete this.config.state;

    for(i in this.config){
      vars.push('"'+i+'":'+'"'+this.config[i]+'"');  
    }
    if(this.config.charttype.equals('MotionChart') &&
      this.config.showBubbles){
      icons=this.bubbles;
      vars.push('"iconKeySettings":['+icons+']');
      this.config.state='{'+vars+'}';
    }
    this.chart.draw(this.table, this.config);
    google.visualization.events.addListener(this.chart, 'select', this.selectHandler);
  },
  selectHandler: function(s,t,u) {    
  },
  parseDate: function(s) {
    m=s.split("/");
    with(d=new Date()){   
      setDate(m[0]);
      setMonth(m[1]-1);
      setYear(m[2]);
    }
    return d;
  },
  getConstructor: function(container) {
    return eval('new google.visualization.'+googleVizAPI.config.charttype + '(container)');
  },
  parseConfig: function(type) {
    var configs=[];
    for(i in this.config){
      configs.push(i+'='+this.config[i])    
    }
    return configs.join('&');
  },
  loadChart: function() {
    if(!this.isModuleLoaded()){
      google.load("visualization", "1", {packages:[googleVizAPI.config.charttype,"table"], "callback" : googleVizAPI.onload});
    }
    else{
      this.onload();
    }
  },
  appendText: function(parent,string) {
    (e=document.createElement("p")).appendChild(document.createTextNode(string));
    e.setAttribute("style","color:red;background-color:#FFF6BF;border:1px solid #FFD324;padding:6px;margin:4px");
    e.id='googleChartInfo';
    parent.appendChild(e);
  },
  require: function(src) {
    var script = document.createElement("script");
    script.src = src;
    script.type = "text/javascript";
    document.getElementsByTagName("head")[0].appendChild(script);
  },
  isModuleLoaded: function() {
    return (window.google && window.google.visualization && eval('window.google.visualization.'+googleVizAPI.config.charttype));
  },
  reset: function() {
    if(window.google){
      delete window.google;
    }
  },
  debug : function(s, isError) {
    if(typeof(console) != 'undefined'){
      isError? console.error(s):console.log(s);
    }
    else{//no Firebug?.. gahh!
    }
  },
  setup: function(data,conf) {
    this.data=arguments[0][0]||data;
    options=arguments[0][1]||conf;
    if(options && typeof options === "object"){
      if(options.overwrite){
        this.config=options;
      }else{
       for(i in options){
        this.config[i]=options[i];
       }
      }
    }
    switch(options.charttype){
      case 'timeline':
        this.timeValueIndex=0;
        this.config.charttype='AnnotatedTimeLine';
      break;     
      case 'area':
        this.config.charttype='AreaChart';
      break;
      case 'column':
        this.config.charttype='ColumnChart';
      break;
      case 'line':
        this.config.charttype='LineChart';
      break;
      case 'bar':
        this.config.charttype='BarChart';
      break;
      case 'motion':     
      default:
            this.config.charttype='MotionChart';
      break;
    }
    // window.onload=function(){
    //  this.appendText(this.$(this.config.containerID),"Loading..");
    // }.bind(this);
    if(this.isModuleLoaded()){
      this.loadChart();
    }
    else{
      this.require('http://www.google.com/jsapi?&callback=googleVizAPI.loadChart');
    }
  }
}
String.prototype.equals = function (s) {
  return String(this) === s;
};
Function.prototype.bind = function(object) {
  var newbind = this;
  return function() {
    return newbind.apply(object);
  };
};
Array.prototype.contains = function ( obj ) {
  var len = this.length;
  for ( var x = 0 ; x <= len ; x++ ) {
    if ( this[x] == obj )
      return true;
  }
  return false;
}
googleVizAPI.init = function() {
  with(googleVizAPI){
    setup(arguments);
  }
};