///////////////////////////////////////////////////////////
//
// JavaScript Charts
// Written and (C). 2006 by KjM <kjm@inline.de>
//
// Eine Verwendung dieses Sourcecodes, auch auszugsweise
// ist eine Copyright Verletzung und wird bestraft.
//
///////////////////////////////////////////////////////////

// Document Shortcut
var dcm = document;

// Wrapper für getElementById
function gE(id) {return dcm.getElementById(id);};

// Wrapper für die createTextNode Funktion
function cN(tx) {return dcm.createTextNode(tx);};

// Wrapper für getElementsByTagName
function eB(o,t,e) {var r = o.getElementsByTagName(t); return (e==null)?r:r[e];};

// AppendChild wrapper
function aC(c,t) {c.appendChild(t);};

// Wrapper für die createElement Funtion
function cE(el) {return dcm.createElement(el);};

// Wrapper für setTimeout
function sT(f,v) {return setTimeout(f,v);};

// Chart Objekt
var Chart = {

  // Versionsnummer
  version: "1.01",

  // Maximalwert an der X-Achse
  maxX: 1000,
  maxXuchng: true,
  intv: 100,
  faktor: 2,
  elemwidth: 0,

  // Anzahl der Werte an der Y-Achse
  Yvalues: new Array(),
  autoval: new Array(),

  // Farben für die Darstellung
  plot_color: new Array(),
  plot_limit: new Array(),
  
  // Tage des jeweiligen Monats und Monatsname
  days: new Array(31,28,31,30,31,30,31,31,30,31,30,31),
  month: new Array("Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"),

  // Aktuelle Werte
  values: new Array(),

  // Diagramm Titel und Subtitel
  title: "Diagramm",
  subtitle: "Untertitel",
  metric: "",
  monthly: false,
  curmonth: -1,
  animate: new Array(),
  aniintv: "",
  anispeed: 2,
  nolabel: false,
  peryear: true,
  quaterly: true,

  // interne Variablen
  ismsie: false,
  initdone: false,
  state: false,
  lastq: 0,
  pixel: 0,
  daylimit: 0,
  pixperday: 0,
  printslow: false,

  // Referenz auf das DIV Element 'bar'
  bE: null,

  //
  // Compare function
  //
  compareFunc: function(a1, a2) {
    return a1[1] < a2[1] ? -1 :
           a1[1] > a2[1] ? 1 : 0;
  },

  //
  // Y-Achse manuell einteilen
  //
  yset: function(name,prio) {
    Chart.Yvalues[Chart.Yvalues.length] = new Array((prio==null)?0:parseInt(prio),name);
    Chart.Yvalues = Chart.Yvalues.sort(Chart.compareFunc);
  },

  //
  // DIV Container verstecken
  //
  invisible: function(n,on) {
    var c = gE(n); if (c) {
      c.style.display = (on!=null && on==true)?"block":"none";
      return c;
    } else return null;
  },

  //
  // Limits und Farben für die Balken setzen
  //
  setlimits: function(l,f) {
    Chart.plot_limit[Chart.plot_limit.length] = parseInt(l);
    Chart.plot_color[Chart.plot_color.length] = f;
  },

  //
  // Farbe für den Balken wählen
  //
  inColor: function(wert) {
    for (var i=0;i<Chart.plot_limit.length;i++) {
      if (parseInt(wert) <= Chart.plot_limit[i]) {
        return (Chart.plot_color.length>i)?Chart.plot_color[i]:"#00ff00";
      }
    }
    return (Chart.plot_limit.length==0)?"#00ff00":Chart.plot_color[Chart.plot_color.length-1];
  },

  //
  // Werte ins Diagramm eintragen
  //
  addvalue: function(x,value) { 
    var isset = false; 
    for (var i=0;i<Chart.values.length;i++) {
      var a = Chart.values[i].split("-");
      if (parseInt(a[0])==x) {
        Chart.values[i] = x+"-"+value;
        isset = true; break;
      } 
    }

    // Daten eintragen
    if (!isset) Chart.values[Chart.values.length] = x+"-"+value; 

    // Y-Achse modifizieren?
    if (parseInt(value) > Chart.maxX) {

      // Maximum anpassen
      Chart.maxX = parseInt(value)+10; Chart.maxXuchng = false;
      Chart.intv = parseInt(Chart.maxX / 10);
      Chart.faktor = Chart.maxX / 500;
    } 
  },

  //
  // Einen einzelnen Wert ohne feste Y Position setzen
  //
  addauto: function(value) {
    Chart.autoval[Chart.autoval.length] = value;
  },

  //
  // Mehrere Werte hinzufügen
  //
  addvalues: function(r) {
    var w = r.split(",");
    for (var i = 0;i<w.length;i++) {
      var xy = w[i].split("-"); 
      if (xy.length==2) Chart.addvalue(xy[0],xy[1]);
      else Chart.addauto(parseInt(xy[0]));
    }
  },

  //
  // Anzeige für einen Monat
  //
  showmonth: function(m) {

    // Links tauschen
    Chart.curmonth = m; Chart.invisible("mview");
    var d = Chart.invisible("vonly",true);
    if (d) {
      Chart.monthly = true;
      d.innerHTML = "Monatsdiagramm für: <b>1. bis "+Chart.days[m]+". "+Chart.month[m]+"</b> &nbsp; &nbsp; [<a href='javascript:Chart.yearview()'>zurück zur Jahresansicht</a>]";
    }

    // Wieviel Pixel = 1 Tag?
    Chart.pixperday = parseInt(730/Chart.days[m])-1; Chart.daylimit = 0;
    for (var i=0;i<m;i++) Chart.daylimit+=Chart.days[i];

    // Daten anzeigen
    Chart.printcontent(); 
  },

  //
  // Das ganze Jahr anzeigen
  //
  yearview: function() { 
    if (Chart.lastq!=0) gE("quart_"+Chart.lastq).style.background = "#fafafa";
    Chart.monthly = Chart.lastq = 0; Chart.printcontent(); 
  },

  //
  // Anzeige für ein Quartal
  //
  quartal: function(q) {

    // Infotext tauschen
    Chart.invisible("mview");
    var d = Chart.invisible("vonly",true); 
    if (d) {
      Chart.monthly = 2;
      d.innerHTML = "Quartalsdiagramm für das <b>"+q+"te Quartal</b> &nbsp; &nbsp; [<a href='javascript:Chart.yearview()'>zurück zur Jahresansicht</a>]";
    }

    // Wieviel Pixel = q Quartal?
    Chart.pixel = 0; var o = (q-1)*3;
    Chart.pixel+=Chart.days[o]+Chart.days[o+1]+Chart.days[o+2];
    Chart.pixperday = parseInt(730/Chart.pixel);

    // Tageslimit berechnen
    Chart.daylimit = 0;
    for (var i=0;i<(q-1);i++) 
      Chart.daylimit+=Chart.days[i*3]+Chart.days[i*3+1]+Chart.days[i*3+2];

    // Daten updaten
    Chart.printcontent(); 

    // Quartal hervorheben
    if (Chart.lastq>0) 
      gE("quart_"+Chart.lastq).style.background = "#fafafa";
    gE("quart_"+q).style.background = "#e7e7e7";
    Chart.lastq = q;
  },

  //
  // Inhalt aus dem Diagramm löschen
  //
  clearcontent: function() {

    // Y-Achse updaten
    Chart.yupdate();

    // Main DIV holen
    var b = gE("bar");

    // Gibt es eine alte Anzeige?
    var old = gE("india");
    if (old) old.parentNode.removeChild(old);

    // inneren Container erzeugen
    var c = cE("div"); c.id = "india"; aC(b,c);
    c.style.position="absolute";
    c.style.width="730px"; c.style.height="500px";
    return c;
  },

  //
  // Daten anzeigen
  //
  updatecontent: function() {
    if (Chart.monthly==2) Chart.quartal(Chart.lastq);
    else if (Chart.monthly==1) Chart.showmonth(Chart.curmonth);
    else Chart.printcontent();
  },

  //
  // Y-Achsen Position automatisch berechnen
  //
  calcy: function() {

    // Breit der Y-Achse holen
    var w = gE("bar").offsetWidth-2;
    
    // Breite pro Element berechnen
    Chart.elemwidth = parseInt((w/(Chart.autoval.length))/2);
    Chart.values = new Array(); var p = 0;
    for (var i=0;i<Chart.autoval.length;i++) {
      Chart.addvalue(p,Chart.autoval[i]);
      p+=Chart.elemwidth;
    }
  },

  //
  // Elemente in den Chart eintragen
  //
  printcontent: function() {

    // Noch nicht initialisiert
    if (Chart.initdone != true) {
      Chart.initdone = -1; return;
    }

    // Laufende Animation stoppen
    if (Chart.aniintv.length) clearTimeout(Chart.aniintv);
    Chart.aniintv = ""; Chart.animate = new Array();

    // Y-Achse Positionen automatisch berechnen
    if (Chart.autoval.length) Chart.calcy();

    // Titel und Subtitel setzen
    var d = gE("dianame");
    if (d && Chart.title.length) {
      d.innerHTML = Chart.title+" &nbsp;";
      if (Chart.subtitle.length)
        d.innerHTML += "["+Chart.subtitle+"]";
    }

    // Inhalt löschen
    var b = Chart.clearcontent();

    // Keine Einzelübersicht
    if (!Chart.monthly) {
      Chart.invisible("vonly");
      Chart.invisible("mview",true);
    }

    // Gespeicherte Daten anzeigen
    for (var i = 0;i<Chart.values.length;i++) {
      var xy = Chart.values[i].split("-"); if (xy[1]==0) continue;      

      // Tag bzw. Wert an der X-Achse berechnen
      if (Chart.monthly) {
        var day = parseInt(xy[0]);

        if ((Chart.monthly==1) && (day < Chart.daylimit || day > Chart.daylimit+Chart.days[Chart.curmonth])) continue;
        else if ((Chart.monthly==2) && (day < Chart.daylimit || day > Chart.daylimit+Chart.pixel)) continue;

        // Tag berechnen
        var dp = (day-Chart.daylimit+1)*Chart.pixperday;
        var d = cE("div"); d.id = "bar_"+i;
        d.style.bottom = (!Chart.ismsie)?2:0+"px";
        d.style.borderTop = "1px solid #2c2c2c";
        d.style.borderRight = "1px solid #2c2c2c";
        d.style.left = (dp-Chart.pixperday)+"px"; 
        d.style.width = (Chart.pixperday-2)+"px";
        d.style.height = ((Chart.printslow)?1:((xy[1]-1)/Chart.faktor))+"px"; 

        // Animierte Darstellung
        if (Chart.printslow)
          Chart.animate[Chart.animate.length] = new Array(i,1,((xy[1]-1)/Chart.faktor),dp-Chart.pixperday,Chart.pixperday-2,xy[1]);
      } else {
        var d = cE("div"); d.id = "bar_"+i;
        d.style.bottom = ((xy[1]-1)/Chart.faktor)+"px"; 
        d.style.left = ((xy[0]*2)-1)+"px"; 
        d.style.border = "1px solid #2c2c2c";
        if (Chart.elemwidth) {
          d.style.width = (2*Chart.elemwidth-3)+"px";
          d.style.height = ((Chart.printslow)?1:xy[1]/Chart.faktor)+"px"; 
          d.style.bottom = (!Chart.ismsie)?2:0+"px";
          if (Chart.printslow)
            Chart.animate[Chart.animate.length] = new Array(i,1,((xy[1]-1)/Chart.faktor),0,0,xy[1]);
        }
      }

      // Infoelemente
      d.style.cursor = "help";
      d.title = xy[1]+" "+Chart.metric;

      // Farbe anhand der Position
      d.style.background = Chart.inColor(xy[1]);
      Chart.setclass(d,"point"); aC(b,d);
    }

    // Langsame, animierte Anzeige?
    if (Chart.printslow) Chart.aniintv = sT(Chart.growup,Chart.anispeed);
  },

  //
  // Balken langsam wachsen lassen
  //
  growup: function() {

    // Alle Balken um 1 Pixel wachsen lassen
    var u = false;
    for (var i=0;i<Chart.animate.length;i++) {
      var a = Chart.animate[i];
      if (a[1]==-1 || a[1]+2 >= a[2]) {
        if (a[1]!=-1 && !Chart.nolabel && Chart.monthly==1) {
          var d = cE("div"); d.id="info_"+a[0];
          d.style.bottom= ((Chart.ismsie)?2:0)+(a[1]-8)+"px";
          d.style.left = a[3]+"px"; d.style.width = a[4]+"px";
          Chart.setclass(d,"vline"); d.innerHTML = a[5];
          aC(gE("india"),d); a[1] = -1;
        }
        continue;
      }
      var d = gE("bar_"+a[0]); a[1]+=5;
      if (d) d.style.height = a[1]+"px"; u = true;
    }

    // Es gibt noch Updates
    if ((u && Chart.monthly) || (Chart.elemwidth))
      Chart.aniintv = sT(Chart.growup,Chart.anispeed);
    else Chart.aniintv = "";
  },

  //
  // Diagramm einblenden / ausblenden
  //
  visibility: function(m) {
    if (Chart.initdone!=true) {
      Chart.state = m; return;
    }

    // Anzeigen / nicht anzeigen
    Chart.state = m; var d = Chart.invisible("bcon",Chart.state);
//    Chart.width = d.offsetWidth-60;
  },

  //
  // Gitternetzlinien zeichnen
  //
  network: function(withmonth) {

    // Get Referenz
    var b = gE("bar");

    // X/Y Achse - zeichnen
    for (var i=0;i<=10;i++) {
      var k = i*50; if (!i && !this.ismsie) k--;
      var p = i*Chart.intv;
      if (i==10 && !this.ismsie) k-=2;

      // Neues Element erzeugen
      var d = cE("div"); d.style.bottom = k+"px"; aC(b,d);
      Chart.setclass(d,"iline"); aC(b,cN("\n"));
      d = cE("div"); Chart.setclass(d,"hinfo"); d.id="yp_"+i;
      d.style.bottom = k+"px"; d.innerHTML = p+"&nbsp;"+Chart.metric; 
      aC(b,d); aC(b,cN("\n"));

      // Dicke Linien alle 10?
      if (i && i<10) {
        d = cE("div"); this.setclass(d,"gline"); 
        d.style.bottom = (i*50)+"px"; aC(b,d); aC(b,cN("\n"));
      }

      // Dünne gepunktete Linien 5 pro Segment
      if (i < 10 ) {
        for (var j = 10;j<50;j+=10) {
          d = cE("div"); d.style.bottom = (i*50+j)+"px"; aC(b,d);
          Chart.setclass(d,"gline2"); aC(b,cN("\n"));
        }
      }
    }

    // Monate und jeweils 10 Tages Balken zeichnen
    if (withmonth == true) {
      c = cE("div"); c.id = "mview"; aC(b,c); aC(c,cN("\n"));
      var p = 0; var m = 1;
      for (var i=0;i<Chart.days.length;i++) {
        p+=Chart.days[i]*2;
        d = cE("div"); Chart.setclass(d,"hline2");
        d.style.left = (p-40)+"px"; aC(b,d); aC(b,cN("\n"));
        d = cE("div"); Chart.setclass(d,"hline2");
        d.style.left = (p-20)+"px"; aC(b,d); aC(b,cN("\n"));
        d = cE("div"); Chart.setclass(d,"hline");
        d.style.left = p+"px"; aC(b,d); aC(b,cN("\n"));
        d = cE("div"); d.style.left = m+"px"; aC(c,d); 
        Chart.setclass(d,"vinfo");
        d.innerHTML = "<a href='javascript:Chart.showmonth("+i+")'>"+Chart.month[i]+"</a>";
        m+=Chart.days[i]*2;
      }

      // Vierteljährliche Anzeige
      if (Chart.quaterly) {
        var q = 0; var f = 0;
        for (var i=0;i<12;i+=3) {
          var l = 0; q++;
          for (var j=i;j<(i+3);j++) l+=Chart.days[j];

          // Links mit den Quartalen
          d = cE("div"); d.id = "quart_"+q; Chart.setclass(d,"quarter");
          d.style.left = f+"px"; d.style.width = (l*2)+"px";
          d.innerHTML = "<a href='javascript:Chart.quartal("+q+")'>"+q+"tes Quartal</a>";
          aC(b,d);
          f+=l*2;
        }
      }
    } else if (Chart.Yvalues.length) {
      var s = (gE("bar").offsetWidth-2) / Chart.Yvalues.length;
      var p = 0;
      for (var i=0;i<Chart.Yvalues.length;i++) {
        p+=s;
        for (var j=0;j<10;j++) {
          d = cE("div"); Chart.setclass(d,"hline2");
          d.style.left = (p-(j*(s/10)))+"px"; aC(b,d);
        }
        d = cE("div"); Chart.setclass(d,"hline");
        d.style.left = p+"px"; aC(b,d);
      }
    }
  },

  //
  // Y-Achse neu beschriften
  //
  yupdate: function() {

    // Y-Achse updaten
    var max = 0;
    for (var i=0;i<Chart.values.length;i++) {
      var a = Chart.values[i].split("-");
      if (parseInt(a[1]) > max) max = parseInt(a[1]);
    }
  
    // Y-Achse verkleinern
    if (Chart.maxX > max) {
      Chart.maxXuchng = false; Chart.maxX = max+10;
      Chart.intv = parseInt(Chart.maxX / 10);
      Chart.faktor = Chart.maxX / 500;
    }

    if (!Chart.maxXuchng) {
      var s = 0;
      for (var i=0;i<=10;i++) {
        var d = gE("yp_"+i);
        d.innerHTML = s+"&nbsp;"+Chart.metric;
        s+=Chart.intv;
      }
    }
  },

  //
  // Chart Objekt initialisieren
  //
  load: function() {

    // Kein DOM Support
    if (!dcm.getElementById) {
      alert("Ihr Browser kann die Charts nicht verarbeiten"); return;
    }

    // Referenz auf den Muttercontainer holen
    this.bE = gE("bar"); if (!this.bE) {
      this.bE = cE("bar"); aC(eB(dcm,"body",0),this.bE);
    }

    // MSIE Fix
    if (!window.opera && navigator.userAgent.indexOf("MSIE") ==-1) {
      this.bE.style.width="730px"; 
      this.ismsie = true;
    }

    // Gitternetz zeichnen
    Chart.network(Chart.peryear);

    // Diagramm zeichnen
    if (Chart.initdone<0) {
      var w = (Chart.initdone==-2)?true:false;
      Chart.initdone = true;
      Chart.printcontent(w);
    }
 
    // System ist initialisiert
    Chart.initdone = true;
    Chart.visibility(Chart.state);
  },

  //
  // Klasse zuweisen (Crossbrowser Version)
  //
  setclass: function(o,c) { o.className = c; },

  // 
  // Event programmieren
  //
  eH: function(obj, evType, fn, useCapture) {

    // Objekt existiert nicht
    if (!obj) {
      alert("Assign fail for "+evType); return;
    }
    if (obj.addEventListener) {
      obj.addEventListener(evType, fn, useCapture);
      return true;
    } else if (obj.attachEvent) {
      var r = obj.attachEvent('on'+evType,fn);
      return r;
    } else {
      obj['on'+evType] = fn;
    }
  }
};

//
// Chart nach dem Laden anzeigen
//
Chart.eH(window,'load',Chart.load,false);