/*
 ** #####################################################################################
 ** Gmess.java
 ** grafische Darstellung von Messwerten  
 **  
 ** Copyright (C) 2010 Reinhard Alfons Lidzba
 ** 
 ** Bei Fragen und Verbesserungen wendet euch per EMail an
 ** 
 ** reinhard@ralidzba.de
 ** 
 ** Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen der 
 ** GNU General Public License, wie von der Free Software Foundation veroeffentlicht, 
 ** weitergeben und/oder modifizieren, entweder gemaess Version 2 der Lizenz oder 
 ** (nach Ihrer Option) jeder spaeteren Version. 
 ** 
 ** Die Veroeffentlichung dieses Programms erfolgt in der Hoffnung, 
 ** dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, 
 ** sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT 
 ** FUER EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. 
 ** 
 ** Sie sollten eine Kopie der GNU General Public License zusammen mit diesem 
 ** Programm erhalten haben. 
 ** Falls nicht, schreiben Sie an die Free Software Foundation, 
 ** Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 
 ** #####################################################################################
 *
 * applet Parameter:
 * 
 * param name=titleFontSize value="20"     = Titel Font Size
 * param name=titleColor value="black"     = Titel Font Color
 * param name=titleColor value="0,255,0"   = Farbangabe in RGB Werten
 * param name=titleFont value="TimesRoman" = Titel Font
 * param name=labelFont value="Courier"    = Beschriftungen
 * param name=labelColor value="black"     = Farbe der Beschriftungen
 * param name=labelFontSize value="12"     = Beschriftung Font Size
 * param name=gridColor value="200,0,0"    = Farbe der Hilfslinien 
 * param name=gridType value="3"           = Hilfslinien Typ, 0=aus,1=Strich, 2=gestrichelt, 3=gepunktet
 * param name=plotAreas value="yes"        = Areas yes / no
 * param name=backColor value="gray"       = background Color
 * 
 *                                         werte für die Übersicht 
 * param name=gtitle value="abcde"         = Titelzeile
 * param name=gfootnote value=text"        = Letzte Zeile
 * param name=gxywerte value="114,8"       = Angabe: 8 y-Werte bei je 114 x-Werten
 * param name=gpointg value="1,1,1,1,1,2,2,3"  = Gruppenzuordnung y-werte, eigener y-massstab
 * param name=glegend1 value="text"        = Legende für den Plot 1.
 * param name=gykomma1 value="0"           = komma fuer gruppe1 0,1,2 = Komma, 4=Datum
 * param name=gxkomma value="0"            = Aufbereitung
 * param name=gplot_color1 value="blue"    = Plot Farbe 1 usw. je y wert
 * param name=gxy1 value="4,2"             = Punkt x,y
 * param name=gbold value="yes"            = fette linie plotten
 * param name=gymax1 value="123"           = ymax Vorgabe fuer Gruppe1
 * param name=gymin1 value="123"           = ymin Vorgabe fuer Gruppe1
 * param name=gxmax value="123"            = xmax Vorgabe 
 * param name=gxmin value="123"            = xmin Vorgabe 
 * param name=gxticks value="yes"          = tickmarken je x-Wert
 * param name=gyrefline value="123"        = Referenz Linie Zeichnen  
 * param name=gxlabel value="text"         = x Achse Label 
 * param name=gylabel1 value="text"        = y Achse gruppe1, Label 
 *
 *                                         Analyse Werte 
 * param name=agridType value="3"          = Hilfslinien Typ, analyse
 * param name=atitle value="abcde"         = Titelzeile
 * param name=afootnote value=text"        = Letzte Zeile
 * param name=axywerte value="114,8"       = Angabe: 8 y-Werte bei je 114 x-Werten
 * param name=apointg value="1,1,1,1,1,2,2,3"  = Gruppenzuordnung y-werte, eigener y-massstab
 * param name=alegend1 value="text"        = Legende für den Plot 1.
 * param name=aykomma1 value="0"           = komma fuer gruppe1 0,1,2 = Komma, 4=Datum
 * param name=axkomma value="0"            = Aufbereitung
 * param name=aplot_color1 value="blue"    = Plot Farbe 1 usw. je y wert
 * param name=axy1 value="4,2"             = Punkt x,y
 * param name=abold value="yes"            = fette linie plotten
 * param name=aymax1 value="123"           = ymax Vorgabe fuer Gruppe1
 * param name=aymin1 value="123"           = ymin Vorgabe fuer Gruppe1
 * param name=axmax value="123"            = xmax Vorgabe 
 * param name=axmin value="123"            = xmin Vorgabe 
 * param name=axticks value="yes"          = tickmarken je x-Wert
 * param name=ayrefline value="123"        = Referenz Linie Zeichnen  
 * param name=axlabel value="text"         = x Achse Label 
 * param name=aylabel1 value="text"        = y Achse gruppe1, Label 
 * param name=ainflate value="123"         = ziel laenge inflate 
 */

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.zip.*;


public class Gmess extends java.applet.Applet implements MouseListener
{
   Image    img ;
   Graphics gb;
   Font      titleFont;
   Font      labelFont;
   FontMetrics   titleFontMetrics;
   FontMetrics   labelFontMetrics;
      
   int auswahl;
   
   long      xmass_old; 
   int      yall;
   int      maxLegendWidth = 0;
   Rectangle[] legendeTerms = new Rectangle[64]; 
   
   int       mdragged = 0;
   int       ValueAuswahl= -1 ;
   int       oldValue = -1 ;
  
   int       titleHeight=15;
   int       titleFontSize=12 ;
   int       labelFontSize=12 ;
   int       xwerte[];
   int       graf_xwerte[];
   int       ywerte[];
   int       xkomma[];
   int       gtype[];
   
   int       ytab[];  
   int       mtabn[]; 
   int       mtabs[];
      
   int       i, n, gv, target;
   int       xgrafSize, ygrafSize;
   int       x, y, x0, y0, xend;
   int       maxLabelWidth = 0;
   int       legendLines, plotLines, legendsPerLine;

   long      gxvalues[];
   long      gyvalues[][];
   
   long      axvalues[];
   long      ayvalues[][];   
   
   long      xvalues[];
   long      yvalues[][];
   
   int       xpixels[], ypixels[];
      
   Object    legends[][];
   Object    plotColor[][];
   
   Color     titleColor = Color.black;
   Color     backColor  = Color.gray;
   Color     labelColor = Color.black;
   Color     gridColor  = Color.black;
      
   String    fontName ;
   String    etxt = "";
   String    labelFontName ;  
   Object    title[];
   Object    footnote[];
   String    b64werte = "";
   Object    dimx[];
         
   double    xscale, w1, w2 ;
   double    yscale[][];
   
   boolean   bplotAreas = false;
   boolean   legend[];
   boolean   bfoot[];
   boolean   drag       = false;
   boolean   ygrid      = false;
   boolean   ygrid2     = false;
   boolean   zgrid      = false;
   boolean   bdimx[];
   boolean   bbold[];
   boolean   bxticks[];
   
                           
   int       ana = 0 ;                        
                           // group vars
   int       groups[]; 
   int       groupindex[][]; 
   int       ykomma[][]; 
   Object    ylabel[][];
   boolean   bCompyMax[][];
   boolean   bCompyMin[][];
   long      maxYValue[][];
   long      minYValue[][];
   
   boolean   bCompxMax[];
   boolean   bCompxMin[]; 
   long      maxXValue[];
   long      minXValue[];
   
   long      yRefLine[];
   boolean   byRefLine[];
   
   byte bmess[];           // Ergebnis aus base64 String 
   byte bout[];

   //****************************************************************
   //*  Init, Auswertung der Parameter
   //****************************************************************
   public synchronized void init()
   {
      String rs, rs2, rsub ;
      int array[ ] ;
      int rest;
      int rxwerte = 0;
      int jahr;      
      
      ytab = new int[ 70 ];  
      mtabn = new int[ 14 ]; 
      mtabs = new int[ 14 ]; 
      
                            // Zeittabellen, Sekundenanzahl je Monat
                            // Monat 13 = Jahres Wert                            
                            // Monats Tabelle berechnen
      n = 0;
      for( i = 1; i < 13; i++ )
      {
         switch ( i )
         {  
           case 2:        
            n += (28 * 24 * 3600);
            break;
                   
           case 4: case 6:  case 9:  case 11:
            n += (30 * 24 * 3600);
            break; 
           
           default:
            n += (31 * 24 * 3600);
            break;
         }
         mtabn[i+1] = n;       
      }
        
                                      // mtabs berechnen (Schaltjahr)
      n = 0;
      for( i = 1; i < 13; i++ )
      {
         switch ( i )
         {         
           case 2:
            n += (29 * 24 * 3600);
            break;
                   
           case 4: case 6: case 9: case 11:
            n += (30 * 24 * 3600);
            break;
             
           default:
            n += (31 * 24 * 3600);
            break; 
         }
         mtabs[i+1] = n;       
      }
      
                                       // Jahres Tabelle berechnen
                                       // Jahr 2010 startet mit 0 Sekunden                                    
      n = 0;
      ytab[0] = 0;
      for( i = 0; i < 68; i++ )
      {
         jahr = i + 10;
         if ( jahr % 4  == 0 )  // schaltjahr ??
            n += mtabs[13] ;
         else
            n += mtabn[13] ;   
         ytab[i+1] = n;             
      }    
      
      addMouseListener( this ); 
       
                          // Erweiterung wegen dynamischer Anzeige
      x=0;
      y=0;
      img = createImage( getSize().width, getSize().height );
      gb = img.getGraphics();

      array = new int[ 66 ];
	   	    
                       // ---------------------------- Title ----
      title = new String[2];
      rs = getParameter("gtitle");
      if (rs == null)
         rs = "LinePlot";
      title[0] = rs;   
      rs = getParameter("atitle");
      if (rs == null)
         rs = "LinePlot";
      title[1] = rs;   
                       // ---------------------------- Foot note ----
      footnote = new String[2];
      bfoot = new boolean[2];
      bfoot[0] = false;
      bfoot[1] = false;
      footnote[0] = getParameter("gfootnote");
      if (footnote[0] != null)
         bfoot[0] = true ;
      footnote[1] = getParameter("afootnote");
      if (footnote[1] != null)
         bfoot[1] = true ;   
                       // ---------------------------- Title Font Size ----
      rs = getParameter("titleFontSize");
      if (rs == null)
         titleFontSize = 12;
      else
         titleFontSize = Integer.parseInt(rs);
                      // ---------------------------- Title Font Color ----
      rs = getParameter("titleColor");
      if (rs == null)
         titleColor = Color.black;
      else
         titleColor = farbAuswahl( rs );
                      // ---------------------------- Title Font  ----
      rs = getParameter("titleFont");
      if (rs == null)
         fontName = "Courier";
      else
         fontName =  rs ;
                      // ---------------------------- label Font  ----
      rs = getParameter("labelFont");
      if (rs == null)
         labelFontName = "Courier";
      else
         labelFontName =  rs ;
                      // ---------------------------- label Color ----
      rs = getParameter("labelColor");
      if (rs == null)
         labelColor = Color.black;
      else
         labelColor = farbAuswahl( rs );
                      // ---------------------------- backgrund Color ----
      rs = getParameter("backColor");
      if (rs == null)
         backColor = Color.lightGray;
      else
         backColor = farbAuswahl( rs );
                      // ---------------------------- Grid Color ----
      rs = getParameter("gridColor");
      if (rs == null)
         gridColor = Color.black;
      else
         gridColor = farbAuswahl( rs ); 
      
      gtype = new int[2];
      gtype[0] = 0;
      gtype[1] = 0;
      rs = getParameter("gridType");
      if (rs == null)
      {
         gtype[0] = 0;
         ygrid = false;
      }
      else
      {
         gtype[0] = Integer.parseInt(rs);
         gtype[1] = gtype[0];
         ygrid = true;         
      }
      rs = getParameter("agridType");
      if ( rs != null )
         gtype[1] = Integer.parseInt(rs);
      
      // ---------------------------- Beschriftung Font Size ----
      rs = getParameter("labelFontSize");
      if (rs == null)
         labelFontSize = 12;
      else
         labelFontSize = Integer.parseInt(rs);
         
                // ---------------------------- Plot mit gefuellten Areas ----
      rs = getParameter("plotAreas");
      if (rs == null)
         bplotAreas = false;
      else
      {
         if ( rs.toLowerCase().equals("yes") && groups[0] == 1 )
            bplotAreas = true;
      }   
      
      titleFont = new java.awt.Font(fontName, Font.BOLD, titleFontSize );
      titleFontMetrics = getFontMetrics(titleFont);

      labelFont = new java.awt.Font( labelFontName, Font.BOLD, labelFontSize );
      labelFontMetrics = getFontMetrics(labelFont);
      
      //############################################################
      // ---------------------------- g... oder a... Werte             
         
                    // ---------------------------- xkomma ----
      xkomma = new int[2];
      xkomma[0] = 0;
      xkomma[1] = 0;      
      rs = getParameter("gxkomma");
      if (rs != null)
         xkomma[0] = Integer.parseInt(rs);
      rs = getParameter("axkomma");
      if (rs != null)
         xkomma[1] = Integer.parseInt(rs);   
         
                   // ---------------------------- xlabel ----
      bdimx = new boolean[2];   
      bdimx[0] = false;
      bdimx[1] = false;           
      dimx = new String[2];
      dimx[0] = getParameter("gxlabel");
      if ( dimx[0] == null)
         dimx[0] = "";
      else
         bdimx[0] = true;
      dimx[1] = getParameter("axlabel");
      if ( dimx[1] == null)
         dimx[1] = "";
      else
         bdimx[1] = true;   
                   // ---------------------------- xmax ----
      bCompxMax = new boolean[2];  
      maxXValue = new long[2];
      maxXValue[0] = 0;
      maxXValue[1] = 0;      
      bCompxMax[0] = true;
      bCompxMax[1] = true;       
      rs = getParameter("gxmax");
      if (rs != null)
      {
         maxXValue[0] = Integer.parseInt(rs);
         bCompxMax[0] = false;
      } 
      rs = getParameter("axmax");
      if (rs != null)
      {
         maxXValue[1] = Integer.parseInt(rs);
         bCompxMax[1] = false;
      }         
                   // ---------------------------- xmin ----
      bCompxMin = new boolean[2];  
      minXValue = new long[2];
      bCompxMin[0] = true;
      bCompxMin[1] = true;                    
      rs = getParameter("gxmin");
      if (rs != null)
      {
         minXValue[0] = Integer.parseInt(rs);
         bCompxMin[0] = false;
      }
      rs = getParameter("axmin");
      if (rs != null)
      {
         minXValue[1] = Integer.parseInt(rs);
         bCompxMin[1] = false;
      }
      
                // ---------------------------- Plot fette Linien ----
      bbold = new boolean[2];  
      bbold[0] = false;
      bbold[1] = false;
      rs = getParameter("gbold");
      if (rs != null)
      {
         if ( rs.toLowerCase().equals("yes") )
            bbold[0] = true;
      } 
      rs = getParameter("abold");
      if (rs != null)
      {
         if ( rs.toLowerCase().equals("yes") )
            bbold[1] = true;
      } 
                // ---------------------------- x ticks ----
      bxticks = new boolean[2];  
      bxticks[0] = true;
      bxticks[1] = true;      
      rs = getParameter("gxticks");
      if (rs != null)
      {
         if ( rs.toLowerCase().equals("no") )
            bxticks[0] = false;
      }
      rs = getParameter("axticks");
      if (rs != null)
      {
         if ( rs.toLowerCase().equals("no") )
            bxticks[1] = false;
      }
      
                  // ---------------------------- yrefline ----
      byRefLine = new boolean[2];  
      yRefLine  = new long[2];  
      byRefLine[0] = false;
      byRefLine[1] = false;         
      rs = getParameter("gyrefline");
      if (rs != null)
      {
         yRefLine[0] = Integer.parseInt(rs);
         byRefLine[0] = true;
      } 
      rs = getParameter("ayrefline");
      if (rs != null)
      {
         yRefLine[1] = Integer.parseInt(rs);
         byRefLine[1] = true;
      } 
                   // ---------------------------- Anzahl der Wertepaare ----
      xwerte  = new int[2]; 
      graf_xwerte  = new int[2]; 
      ywerte  = new int[2]; 
      xwerte[0] = 0;
      ywerte[0] = 1;
      xwerte[1] = 0;
      ywerte[1] = 1;
      
      rs = getParameter("gxywerte");
      if (rs != null)
      {
         array = parseInteger( rs, 2) ;
         xwerte[0] = array[ 0 ];
         graf_xwerte[0] = array[ 0 ];
         ywerte[0] = array[ 1 ];
         if ( ywerte[0] > 64 ) 
            ywerte[0] = 1;
      }      
      rs = getParameter("axywerte");
      if (rs != null)
      {
         array = parseInteger( rs, 2) ;
         xwerte[1] = array[ 0 ];
         ywerte[1] = array[ 1 ];
         if ( ywerte[1] > 64 ) 
            ywerte[1] = 1;
      }       
      
                  // ---------------------------- Gruppen Zuordnungen  ----
      groupindex = new int[2][65];  
      groups = new int[2];  
      rs = getParameter("gpointg");
      if (rs != null)
      {
         groups[0] = 1;
         array = parseInteger( rs, ywerte[0]+1 ) ;
         for ( n=0; n < ywerte[0]; n++ )
         {
            groupindex[0][n] = array[ n ] - 1 ;
            if ( groups[0] < array[ n ] )
               groups[0] = array[ n ];
         }
      }
      else
      {
         groups[0] = 1;
         for ( n=0; n < ywerte[0]; n++ )
         {         
            groupindex[0][n] = 1;
         }
      }
      rs = getParameter("apointg");
      if (rs != null)
      {
         groups[1] = 1;
         array = parseInteger( rs, ywerte[1]+1 ) ;
         for ( n=0; n < ywerte[1]; n++ )
         {
            groupindex[1][n] = array[ n ] - 1 ;
            if ( groups[1] < array[ n ] )
               groups[1] = array[ n ];
         }
      }
      else
      {
         groups[1] = 1;
         for ( n=0; n < ywerte[1]; n++ )
         {         
            groupindex[1][n] = 1;
         }
      }
                  // ----------------------------- Fonts einstellen --
      
      gyvalues   = new long[xwerte[0]+1][ywerte[0]+1];
      gxvalues   = new long[xwerte[0]+1];
      
      legend    = new boolean[2];
      legends   = new String[2][65];
      plotColor = new Color[2][ 65];

            // ---------------------------- Farbe definieren ----
      for( i=0; i < 2; i++)
      {
         for (n=0; n < ywerte[i] ; n++)
         {
            if ( i == 0 )
               rs =  getParameter("gplot_color" + (n+1));
            else 
                rs =  getParameter("aplot_color" + (n+1));            
            if (rs != null)
               plotColor[i][ n ] = farbAuswahl( rs );
            else
            {
               rest = n % 8 ;        // default werte
               switch ( rest )
               {
                  case 0:  plotColor[i][ n ] = Color.blue;    break;
                  case 1:  plotColor[i][ n ] = Color.yellow;  break;
                  case 2:  plotColor[i][ n ] = Color.green;   break;
                  case 3:  plotColor[i][ n ] = Color.red;     break;
                  case 4:  plotColor[i][ n ] = Color.cyan;    break;
                  case 5:  plotColor[i][ n ] = Color.orange;  break;
                  case 6:  plotColor[i][ n ] = Color.pink;    break;
                  case 7:  plotColor[i][ n ] = Color.magenta; break;
                  default: break; 
               }   
            }
                                   // ---------------- Legende anfordern -----
            if ( i == 0 )
               rs =  getParameter("glegend" + (n+1));
            else
               rs =  getParameter("alegend" + (n+1));
            if (rs != null)
            {
               legend[i] = true ;
               legends[i][ n ] = rs;
            }
            else
               legends[i][ n ] = "";       
         }
      }      
      // ---------------- Gruppen spezifische Werte anfordern -----
      n = Math.max( groups[0], groups[1] ) + 1;   // maximal wert nehmen
      ylabel    = new String[2][ n ];
      ykomma    = new int[2][ n ];
      bCompyMax = new boolean[2][ n ];
      bCompyMin = new boolean[2][ n ];
      maxYValue = new long[2][ n ];
      minYValue = new long[2][ n ];
      yscale    = new double[2][ n ];
      
      for (n=0; n < groups[0] ; n++)
      {
         rs =  getParameter("gykomma" + (n+1));
         if (rs != null)
            ykomma[0][n] = Integer.parseInt(rs);
         else
            ykomma[0][n] = 1;  
            
         rs =  getParameter("gymax" + (n+1));
         if (rs != null)
         {
            maxYValue[0][n] = Integer.parseInt(rs);
            bCompyMax[0][n] = false;
         }
         else
         {
            bCompyMax[0][n] = true;
            maxYValue[0][n] = 0;  
         }
         
         rs =  getParameter("gymin" + (n+1));
         if (rs != null)
         {
            minYValue[0][n] = Integer.parseInt(rs);
            bCompyMin[0][n] = false; 
         }
         else
         {
            minYValue[0][n] = 2147483647; 
            bCompyMin[0][n] = true;            
         }   

         rs =  getParameter("gylabel" + (n+1));
         if (rs != null)
            ylabel[0][n] = rs;
         else
            ylabel[0][n] = "";                     
      }
      
            
      for (n=0; n < groups[1] ; n++)
      {
         rs =  getParameter("aykomma" + (n+1));
         if (rs != null)
            ykomma[1][n] = Integer.parseInt(rs);
         else
            ykomma[1][n] = 1;  
            
         rs =  getParameter("aymax" + (n+1));
         if (rs != null)
         {
            maxYValue[1][n] = Integer.parseInt(rs);
            bCompyMax[1][n] = false;
         }
         else
         {
            bCompyMax[1][n] = true;
            maxYValue[1][n] = 0;  
         }
         
         rs =  getParameter("aymin" + (n+1));
         if (rs != null)
         {
            minYValue[1][n] = Integer.parseInt(rs);
            bCompyMin[1][n] = false; 
         }
         else
         {
            minYValue[1][n] = 2147483647; 
            bCompyMin[1][n] = true;            
         }   

         rs =  getParameter("aylabel" + (n+1));
         if (rs != null)
            ylabel[1][n] = rs;
         else
            ylabel[1][n] = "";                     
      }       

               // ------------- g X Y Werte holen
      for (i=0; i < xwerte[0]; i++)
      {
         rs = getParameter("gxy" + (i+1));
         if (rs != null)
         {
            rxwerte = i+1;
            array = parseInteger( rs, ywerte[0]+1 );
            gxvalues[ i ] = array[ 0 ];
            
            for( n = 0 ;  n < ywerte[0] ; n++ )
            {
               gyvalues[ i ][ n ] = array[ n + 1 ];              
            }                        
         }
      }      
      xwerte[0] = rxwerte ;   // gelesene x Werte
      
               // ------------- a X Y Werte holen
      for (i=0; i < xwerte[1]; i++)
      {
         rs = getParameter("axy" + (i+1));
         if (rs != null)
         {
            b64werte = b64werte + rs;            
         }
      }      
       
      xwerte[1] = b64werte.length() ;   // laenge b64 Datenstrom
      bmess = decodiere( b64werte );    // to byte array
      
      target = 0;
      i=0;
      rs = getParameter("ainflate");
      if (rs != null)
      {
         target = Integer.parseInt(rs);            
      }
      
      if ( target > 0 )                 // inflate byte array to messwerte
      {
         Inflater decompressor = new Inflater();
         decompressor.setInput( bmess, 0, bmess.length );
         bout = new byte[ target ] ; 
         try
         {
            i = decompressor.inflate( bout );
         }
         catch ( DataFormatException ee )
         { 
            etxt = "Error "+ ee;  
         }                
         decompressor.end();
      }      
           
      xwerte[1] = i / 28;   // anzahl der Gruppen
      ywerte[1] = 9;        // ywerte
              
      ayvalues   = new long[ xwerte[1]+1][ywerte[1]];
      axvalues   = new long[ xwerte[1]+1];
      
      i = 0;
      for ( int pos=0; pos <  xwerte[1]; pos++)
      { 
         int i1,i2,i3,i4; 
              
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++] & 0xff ;
         i3 = bout[i++] & 0xff ;
         i4 = bout[i++] & 0xff ;         
         axvalues[pos] = (i4<<24) + (i3<<16) + (i2<<8) + i1;     // timestamp
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++] & 0xff ;
         i3 = bout[i++] & 0xff ;
         i4 = bout[i++] & 0xff ;         
         ayvalues[pos][6] = (i4<<24) + (i3<<16) + (i2<<8) + i1;  // gas
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++] & 0xff ;
         i3 = bout[i++] & 0xff ;
         i4 = bout[i++] & 0xff ;
         ayvalues[pos][7] = (i4<<24) + (i3<<16) + (i2<<8) + i1;  // gas ww
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++] & 0xff ;
         i3 = bout[i++] & 0xff ;
         i4 = bout[i++] & 0xff ;
         ayvalues[pos][5] = (i4<<24) + (i4<<16) + (i2<<8) + i1;  // Strom
         ayvalues[pos][5] /= 10;
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++];
         ayvalues[pos][0] = ((i2<<8) + i1) + 400;                // temperatur Vorlauf
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++];
         ayvalues[pos][1] = ((i2<<8) + i1) + 400;                // temperatur Rücklauf
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++];
         ayvalues[pos][2] = ((i2<<8) + i1) + 400;                // temperatur Warm Wasser
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++] ;
         ayvalues[pos][3] = ((i2<<8) + i1) + 400;                // temperatur Aussen
         
         i1 = bout[i++] & 0xff ;
         i2 = bout[i++];
         ayvalues[pos][4] = ((i2<<8) + i1) + 400;                // temperatur GWH
         
         i += 2;                                                 // skip
      }
      
      int cp = 0;                                                // mittlere Leistung der Therme je 5 Minuten  
      double power = 0.0;
      for ( int pos=0; pos <  xwerte[1]; pos++)
      { 
         if ( cp == pos )
         {
            if ( (pos+5) < xwerte[1] )
            {
               long sekunden = axvalues[pos+5] - axvalues[pos];
               if ( sekunden > 0 )
               {
                  power = (( ayvalues[pos+5][6] - ayvalues[pos][6] ) * 0.9534 * 11.227 * 3600) / sekunden;
                  // System.err.println( "Diff=" + ( ayvalues[pos+5][6] - ayvalues[pos][6] ));
               }
            }
            cp += 5;               
         }
         ayvalues[pos][8] = (long)power;                         // Ergebnis       
      }
      
      ana = 0;
      init_plot( 0 );         // g Werte Zeichnen      

      do_plot( gb, -1 );      // bild zeichnen mit allen Werten
   }

   
   /***************************************************************
   **  decodiere base64 to Byte[] 
   */    
   byte[] decodiere( String s )
   {
      char c;
      byte work[];
      int len, ergebnis,i,j,v,p=0;
      
      len = s.length();   
      if ( (len & 0x03) > 0 )   // durch 4 teilbar ?? 
      {       
         work = new byte[0];    // ergebnis == 0 
      }
      else
      {
         ergebnis = (len / 4) * 3;  
         if ( s.charAt( len-2 ) == '=' )
         {
            len -= 2;
            ergebnis -= 2;
         }
         else if ( s.charAt( len-1 ) == '=' )
         {
            len -= 1;
            ergebnis -= 1;
         }
         work = new byte[ergebnis];   
        
         j = 0;
         v = 0;
         for ( i=0; i < len; i++ )
         {           
            j <<= 6;
            c = s.charAt( i );
            switch ( c )
            {         
               case 'A': j += 0; break;
               case 'B': j += 1; break;
               case 'C': j += 2; break;
               case 'D': j += 3; break;
               case 'E': j += 4; break;
               case 'F': j += 5; break;
               case 'G': j += 6; break;
               case 'H': j += 7; break;
               case 'I': j += 8; break;
               case 'J': j += 9; break;
               case 'K': j += 10; break;
               case 'L': j += 11; break;
               case 'M': j += 12; break;
               case 'N': j += 13; break;
               case 'O': j += 14; break;
               case 'P': j += 15; break;
               case 'Q': j += 16; break;
               case 'R': j += 17; break;
               case 'S': j += 18; break;
               case 'T': j += 19; break;
               case 'U': j += 20; break;
               case 'V': j += 21; break;
               case 'W': j += 22; break;
               case 'X': j += 23; break;
               case 'Y': j += 24; break;
               case 'Z': j += 25; break;
               case 'a': j += 26; break;
               case 'b': j += 27; break;
               case 'c': j += 28; break;
               case 'd': j += 29; break;
               case 'e': j += 30; break;
               case 'f': j += 31; break;
               case 'g': j += 32; break;
               case 'h': j += 33; break;
               case 'i': j += 34; break;
               case 'j': j += 35; break;
               case 'k': j += 36; break;
               case 'l': j += 37; break;
               case 'm': j += 38; break;
               case 'n': j += 39; break;
               case 'o': j += 40; break;
               case 'p': j += 41; break;
               case 'q': j += 42; break;
               case 'r': j += 43; break;
               case 's': j += 44; break;
               case 't': j += 45; break;
               case 'u': j += 46; break;
               case 'v': j += 47; break;
               case 'w': j += 48; break;
               case 'x': j += 49; break;
               case 'y': j += 50; break;
               case 'z': j += 51; break;
               case '0': j += 52; break;
               case '1': j += 53; break;
               case '2': j += 54; break;
               case '3': j += 55; break;
               case '4': j += 56; break;
               case '5': j += 57; break;
               case '6': j += 58; break;
               case '7': j += 59; break;
               case '8': j += 60; break;
               case '9': j += 61; break;
               case '+': j += 62; break;
               case '/': j += 63; break;         
            }
            v++;
            if ( v == 4 )
            {
               v = 0;
               work[ p++ ] = (byte)((j >> 16) & 0xFF) ;
               work[ p++ ] = (byte)((j >> 8) & 0xFF) ; 
               work[ p++ ] = (byte)(j & 0xFF);
               j=0;               
            }
         }                           
         if ( v == 3 )
         {
            work[ p++ ] = (byte)((j >> 8) & 0xFF) ; 
            work[ p++ ] = (byte)(j & 0xFF) ;
         }  
         if ( v == 2 )
         {
            work[ p++ ] = (byte)(j & 0xFF);
         }                  
      }
      return work; 
   }
   
   

   //****************************************************************
   //*  Vorbereitung der Plot werte 
   //****************************************************************
   void  init_plot( long date )
   {  
      String rs, rs2;    
      long wert;
      long wk0[];
           
            
      boolean date_ok = false;
      long datex = date / 86400 ;
      
      auswahl=0;
      wk0 = new long[ ywerte[ana] ];
      for ( int u=0; u < ywerte[ana] ; u++ )
         wk0[u] = 0;     
      
      
      
      yvalues = new long[xwerte[ana]+1][ywerte[ana]];
      xvalues = new long[xwerte[ana]+1];    
                     // werte neu eistellen
      for ( i=0; i < xwerte[ana]; i++)
      {
         if ( ana == 0 )
         {
            date_ok = true; 
            auswahl = i;
            xvalues[auswahl] = gxvalues[i];
         }
         else
         {
            date_ok = false; 
            wert =  axvalues[i] / 86400 ;
            if ( wert == datex )
            {
               xvalues[auswahl] = axvalues[i];
               date_ok = true; 
            }
         }
         if ( date_ok )
         {          
            
            if ( auswahl == 0 )
            {
               minXValue[ana] = xvalues[auswahl];
               maxXValue[ana] = xvalues[auswahl];
               if ( ana == 1 )
               {
                  wk0[5] = ayvalues[ i ][ 5 ] ;
                  wk0[6] = ayvalues[ i ][ 6 ] ;
                  wk0[7] = ayvalues[ i ][ 7 ] ;
               }
            }
            else
            {
               minXValue[ana] = Math.min( xvalues[auswahl], minXValue[ana] );
               maxXValue[ana] = Math.max( xvalues[auswahl], maxXValue[ana] );
            }
            
            for( n = 0 ;  n < ywerte[ana] ; n++ )
            {
               if ( ana == 0 )
               {
                  yvalues[ auswahl ][ n ] = gyvalues[ i ][ n ];
               }
               else  
               {
                  yvalues[ auswahl ][ n ] = ayvalues[ i ][ n ] - wk0[n] ;
               }
               
               gv = groupindex[ana][n];
               
               if ( bCompyMax[ana][gv] )
               {
                  if ( auswahl == 0 )
                     maxYValue[ana][gv] = 0;
                  maxYValue[ana][gv] = Math.max( yvalues[ auswahl ][ n ] , maxYValue[ana][gv] );
               }
               if ( bCompyMin[ana][gv] )
               {
                  if ( auswahl == 0  )
                     minYValue[ana][gv] = yvalues[ auswahl ][ n ] ;
                  minYValue[ana][gv] = Math.min( yvalues[ auswahl ][ n ] , minYValue[ana][gv] );                   
               }                            
            }
            auswahl++;  
         }          
      }
      graf_xwerte[ana] = auswahl;
      
      xpixels = new int[ auswahl+10 ];
      ypixels = new int[ auswahl+10 ];

         // ------------ Alle Parameter da, Ausrichtung der Pixel
         // Anpassung min und maxima Werte
      for( n = 0 ;  n < groups[ana] ; n++ )
      {
         if ( bCompyMax[ana][n] )
            maxYValue[ana][n] = trick( maxYValue[ana][n], maxYValue[ana][n] - minYValue[ana][n], true );
         if ( bCompyMin[ana][n] )
            minYValue[ana][n] = trick( minYValue[ana][n], maxYValue[ana][n] - minYValue[ana][n], false );
      }
                  
           // Justage der Pixel x-achse
      xgrafSize = getSize().width - 2;
      rs = EditWert( (long)Math.round( maxYValue[ana][0] ), ykomma[ana][0] );
      x0 = labelFontMetrics.stringWidth( rs ) + 5 ;
      xgrafSize -= x0 ;
      
      if ( groups[ana] > 1 )
      {
         xend = 0;
         for ( n=1; n < groups[ana]; n++ )
         {
            rs = EditWert( (long)Math.round( maxYValue[ana][n] ), ykomma[ana][n] );
            rs2 = (String)ylabel[ana][n];            
            xend += (Math.max( labelFontMetrics.stringWidth( rs ), labelFontMetrics.stringWidth( rs2 )) + 10) ;
         }
         xgrafSize -= xend;
         xend = x0 + xgrafSize;    // Ende x-Achse         
      }
      else
      {
         xend = x0 + xgrafSize;    // Ende x-Achse 
      }
      
      
      if ( maxXValue[ana] > 0 )
      {
         w1 = xgrafSize  ;
         w2 = maxXValue[ana]  - minXValue[ana] ;
         xscale  = w1 / w2 ;
      }
      else
         xscale  = 1;
      
           // Justage der Pixel y-achse
      ygrafSize = getSize().height - 5 ;
      y0 = getSize().height;
      yall = y0 - 1 - labelFontSize ;
      ygrafSize -= ( titleFont.getSize() + 8 + labelFont.getSize() );
      y0 -= (labelFontSize + 4 );
      
      if ( legend[ana] )
      {
         int lpixel;
         plotLines = ywerte[ana];
         for ( i=0; i < plotLines; i++ )
         {
            maxLegendWidth = Math.max ( labelFontMetrics.stringWidth((String) (legends[ana][i])), maxLegendWidth );
         }
         lpixel  = labelFontSize + 8 + maxLegendWidth ;
         legendsPerLine = ( getSize().width * 9/10 ) / lpixel ;
         legendLines = plotLines / legendsPerLine ;
         if ( ( plotLines % legendsPerLine ) > 0 )
            legendLines += 1;
         y0 -= labelFontMetrics.getHeight() * legendLines ;
         ygrafSize -= labelFontMetrics.getHeight() * legendLines ; 
      }
      
      if ( bfoot[ana] )
      {
         y0 -= labelFontMetrics.getHeight();
         ygrafSize -= labelFontMetrics.getHeight();
      }
      
      for ( gv=0; gv < groups[ana]; gv++)
      {      
         if ( maxYValue[ana][ gv ] > 0 )
         {
            w1 = ygrafSize ;
            w2 = maxYValue[ana][ gv ] - minYValue[ana][ gv ] ;
            yscale[ana][ gv ] = w1 / w2 ;
         }
         else
            yscale[ana][ gv ] = 1;
      }         
   }
   
   //****************************************************************
   //*  Umwandlung String => Color
   //****************************************************************
   Color farbAuswahl( String s)
   {
     int kopo;
     int rgb[];

     if (s.equals("red"))
        return Color.red;
     else if (s.equals("green"))
        return Color.green;
     else if (s.equals("blue"))
        return Color.blue;
     else if (s.equals("pink"))
        return Color.pink;
     else if (s.equals("orange"))
        return Color.orange;
     else if (s.equals("magenta"))
        return Color.magenta;
     else if (s.equals("cyan"))
        return Color.cyan;
     else if (s.equals("white"))
        return Color.white;
     else if (s.equals("yellow"))
        return Color.yellow;
     else if (s.equals("gray"))
        return Color.gray;
     else if (s.equals("lightGray"))
        return Color.lightGray;
     else if (s.equals("darkGray"))
        return Color.darkGray;
     else if (s.equals("black"))
        return Color.black;
     else
     {
       kopo = s.indexOf( ",", 0 );
       if ( kopo < 0 )
          return Color.black;
       else
       {
         rgb = new int[3];
         rgb = parseInteger( s, 3 ) ;
         Color farbe = new Color( rgb[0],rgb[1],rgb[2]);
         return farbe;
       }
     }
   }


   //****************************************************************
   //*  umwandlung string mit kommaunterteilungen => array
   //****************************************************************
   int[] parseInteger( String s, int anzahl)
   {
      int pos1, pos2, i;
      String rsub;
      int    param[];

      param = new int[anzahl];
      pos1 = 0;
      pos2 = 0;
      for( i = 0 ;  i < anzahl ; i++ )
      {
         if ( pos2 < 0 )
            param[ i ] = 0 ;
         else
         {
            pos2 = s.indexOf( ",", pos1 );
            if (pos2 > 0 )
            {
               rsub = s.substring( pos1, pos2 );
               pos1 = pos2 + 1;
            }
            else
               rsub = s.substring( pos1 );

            try { param[ i ] = Integer.parseInt( rsub ); }
            catch (NumberFormatException e) { param[ i ] = 0; }
         }
      }
      return param;
   }


   /*****************************************************************
   **  umwandlung Zahl ==> string mit kommawerten
   **  Formatierungen:
   **  komma = 0    Zahl ohne Komma
   **  komma = 1    Zahl mit einer Kommastelle
   **  komma = 2    Zahl mit zwei  Kommastellen
   **  komma = 3    Temperatur, eine Kommastelle, werte * 16 + 400    
   **  komma = 4    Umwandeln als Datum ( 2010 = 0)
   **  komma = 5    Sekunden: Umwandeln als hh:mm:ss
   **  komma = 6    Umwandeln als Datum und hh ( 2010 = 0)
   **
   ** 17.2.2012 li Korrektur negative Temperatur Werte 
   */
   String EditWert( long value, int komma )
   {
      String rs = "";
      String Hour;
      String Minute;
      long rest;
      int n,m;
      long j = 2000; 
      long tag,h,mm,ss; 
      boolean neg0 = false;        

      switch(komma)
      {
        default:
        case 0:
         rs = "" + value ;
         break;

        case 1:
         rs = "" + value/10 + "," + (value - (value/10)*10) ;
         break;

        case 2:                       // 17.2.2012 Korrektur negative Werte 
         rs = "" + value/100 + ",";
         rest = value - (value/100)*100;
         if ( rest > 9 )
           rs = rs + rest;
         else
           rs = rs + "0" + rest;
         break;
         
        case 3:         // Temperatur 
         value -= 400;  // - 400 Pixel = 25°C 
         value *= 10;   
         value /= 16;
         if ( value < 0 )
         {
            neg0 = true;
            rest = value * -1;
            rest = rest % 10;
            value /= 10;
            if ( value < 0 )
               neg0 = false; 
         }
         else
         {
            rest = value % 10;
            value /= 10;
         }
         rs = "" + value + "," + rest; 
         if ( neg0 )
            rs = "-" + rs;            
         break;         
                  
                  // datetime erzeugen
        case 4:                
        case 5: 
        case 6:               
         for ( n=0; n < 67; n++)
         {
            if ( value >= ytab[n] && value < ytab[n+1] )
            {
               j = n + 2010;
               value -= ytab[n];
               break;
            }
         }
               
         if ( j % 4 == 0 )
         {
            for ( m=1; m < 13; m++)
            {
               if ( value >= mtabs[m] && value < mtabs[m+1] )
               {
                  value -= mtabs[m] ;
                  break;
               } 
            }  
         }
         else
         {
            for ( m=1; m < 13; m++)
            {
               if ( value >= mtabn[m] && value < mtabn[m+1] )       // 1.4.2010
               {
                  value -= mtabn[m] ;
                  break;
               } 
            }
         }
         tag = (value / 86400);
         tag += 1; 
         h = value % 86400;
         h /= 3600 ;
         mm = value % 3600 ;
         ss = mm % 60 ;
         mm /= 60;
         if ( h < 10 )
            Hour = "0"+h;
         else 
            Hour = ""+h ;
         if ( mm < 10 )
            Minute = "0"+mm ;
         else
            Minute = ""+mm ;       
                  
         rs = "" + tag +"."+ m +"." + j; 
         if ( komma == 6 )                   
            rs += " " + Hour + ":" + Minute + ":" + ss;  
                  
         if ( komma == 5 )
            rs = "" + Hour + ":" + Minute + ":" + ss; 
         break;
        
      }
      return rs;
   }

   //****************************************************************
   //*  auf oder abrunden zum Maßstab zeichnen
   //****************************************************************
   long trick( long wert , long diff, boolean auf )
   {
      long mas, multi, md , kor ;

      md = 1;
      while ( (md * 10 ) < diff )
         md = md * 10 ;

      mas = diff / md ;
      if ( mas <= 2)
         mas = 2 ;
      else if ( mas <= 5)
         mas = 5 ;
      else if ( mas <= 10 )
         mas = 10 ;
      kor = mas * md / 10 ;
      if ( kor > 0)
      {
         multi = wert / kor;
         if ( auf )
         {
            if ( (multi * kor) < wert )
            {
               wert = wert + kor ;
               multi = wert / kor ;
               wert = multi * kor ;
            }
         }
         else
            wert = multi * kor ;
      }
      return wert;
   }
   
   
   /****************************************************************
   ** Zeichnen
   */
   void do_plot(Graphics g, int SelValue )
   {
      String rs, rs2;
      String ttxt;
      int v, i, n, pixel_summe, j , offset ;
      int px1, py1, px2;
      long ymgrid;
      long summe;
      float fGx ,fGy ;
      long intervall;
      long ymass, xmass, wmass;
      int cx, cy;
      int cxOffset ;
      int xP[ ] = new int[ 7 ];
      int yP[ ] = new int[ 7 ];
      Color logoColor = new Color( 0,160,0);
      oldValue = SelValue; // sichere Auswahl 

                           //-- fill with backgrund color
      g.setColor(backColor);
      g.fillRect(0, 0, getSize().width, getSize().height );
                      
                           // draw the title centered at the top of the bar graph
      g.setFont(titleFont);
      i = titleFont.getSize();
      if ( ana == 0 )
         ttxt = (String)title[ana];
      else      
         ttxt = (String)title[ana] + " " + EditWert( xvalues[ 0 ],4);
      cx = ( getSize().width - titleFontMetrics.stringWidth( ttxt ) ) / 2 ;
      if ( cx <= ( i + 12 ))
         cx = i + 12 ;
      if ( i >= 50 )        // wenn size >=  50, title mit Schatten malen
      {
         g.setColor(Color.darkGray);
         g.drawString( ttxt, cx+2 , i+2 );
      }
      g.setColor(titleColor);
      g.drawString( ttxt, cx, i );
      g.setColor(labelColor);
      g.setFont(labelFont);

      if( graf_xwerte[ana] > 1 )
      {
         if ( bplotAreas )        // ------------------------- gefuellte Areas zeichnen
         {
            for ( n=ywerte[ana]-1; n >= 0; n--)
            {
               gv = groupindex[ana][n]; 
               if ( SelValue == -1 || SelValue == n )
               {
                  for (i=0; i < graf_xwerte[ana]; i++)
                  {
                     xpixels[ i ] = (int)Math.round( (xvalues[ i ] - minXValue[ana]) * xscale ) + x0 ;
                     ypixels[ i ] = y0 - (int)Math.round((yvalues[ i ][ n ] - minYValue[ana][gv]) * yscale[ana][gv]);
                     if ( SelValue == n )
                     {
                        if ( n > 0 )
                        {
                           ypixels[ i ] += (int)Math.round((yvalues[ i ][ n-1 ] - minYValue[ana][gv]) * yscale[ana][gv]); 
                        }   
                     }                        
                  }
                  xpixels[ i   ] = xpixels[ i-1 ];   // letzter x-wert
                  ypixels[ i++ ] = y0 ;
                  xpixels[ i   ] = xpixels[ 0 ];     // erster x-wert
                  ypixels[ i++ ] = y0 ;
                  xpixels[ i ] = xpixels[0];
                  ypixels[ i ] = ypixels[0];
                  g.setColor( (Color)plotColor[ana][ n ] );
                  g.fillPolygon( xpixels, ypixels, xwerte[ana] + 3 );                  
               }
            }
         }
         else                    // -------------------------- linien plotten
         {                                   
            for ( n=0; n < ywerte[ana]; n++)
            {
               gv = groupindex[ana][n];  
   			   if ( SelValue == -1 || (SelValue == n && SelValue < ywerte[ana] ))      /* mouse Auswahl */
   			   {
                  for (i=0; i < graf_xwerte[ana]; i++)
                  {
                     xpixels[ i ] = (int)Math.round( (xvalues[ i ] - minXValue[ana]) * xscale ) + x0 ;
                     ypixels[ i ] = y0 - (int)Math.round((yvalues[ i ][ n ] - minYValue[ana][gv]) * yscale[ana][gv]);
                  }
                  g.setColor( (Color)plotColor[ana][ n ] );
                  for (i=0; i < graf_xwerte[ana]-1 ; i++)
                  {
                     g.drawLine(xpixels[i], ypixels[i],xpixels[i+1], ypixels[i+1]);
                     if ( bbold[ana] )
                     {
                        g.drawLine(xpixels[i]+1, ypixels[i],xpixels[i+1]+1, ypixels[i+1]);
                        g.drawLine(xpixels[i], ypixels[i]+1,xpixels[i+1], ypixels[i+1]+1);
                     }   
                  }
   			   }
            }            
         }
      }

      g.setColor(labelColor);
      if ( xwerte[ana] > 0 )
      {                                //---- x - Achse zeichnen ----------------
         cy = y0 ;
         cx = x0 ;
         g.drawRect( cx , cy - ygrafSize, xgrafSize , ygrafSize );   // --- Rahmen
         xmass = minXValue[ana];
         switch (xkomma[ana])
         {                                    
            case 4:                                       // datumsformat + Zeit
              if ( ( maxXValue[ana] - minXValue[ana] ) <= 7200 )
                 intervall = 900;
              else
              {
                 intervall = (maxXValue[ana] - minXValue[ana]) / 6 ;
                 intervall += 3599 ;
                 intervall /= 3600 ;
                 intervall *= 3600 ;
              }    
              break;
            
            case 5:                                       //  Zeit hh:mm:ss
              if ( ( maxXValue[ana] - minXValue[ana] ) <= 7200 )
                 intervall = 900;
              else
              {
                 intervall = (maxXValue[ana] - minXValue[ana]) / 12 ;
                 intervall += 3599 ;
                 intervall /= 3600 ;
                 intervall *= 3600 ;
              }    
              break;  

            default:
              intervall = (maxXValue[ana] - minXValue[ana]) / 10 ;
              break;
         }
         if ( intervall == 0 )
            intervall = 1;
         do
         {
            cx = x0  + (int)Math.round((xmass - minXValue[ana]) * xscale);
            g.drawLine(cx,cy,cx, cy+4 );
            rs = EditWert( (long)Math.round( xmass ), xkomma[ana] );
            g.drawString( rs , cx - 5 , cy + labelFontSize + 3 );
            xmass += intervall;
         } while( xmass <= maxXValue[ana] ) ;

                                       // fuer jeden Zeitwert eine tickmark
         if ( bxticks[ana] )
         {
            for (i=0; i < graf_xwerte[ana]; i++)
            {
               cx = x0  + (int)Math.round(( xvalues[ i ] - minXValue[ana]) * xscale);
               g.drawLine(cx,cy,cx, cy+2 );
            }
         }
                                       //---- y - Achse zeichnen ----------------
         cy = y0 ;
         cx = x0 ;
         ymass = minYValue[ana][0];

         if (ykomma[ana][0] == 3 )
            intervall = ( maxYValue[ana][0] - minYValue[ana][0]) / 4 ;
         else
            intervall = ( maxYValue[ana][0] - minYValue[ana][0]) / 10 ;

         if ( intervall == 0 )
            intervall = 1;
         do
         {
            cy = y0  - (int)Math.round((ymass - minYValue[ana][0]) * yscale[ana][0]);
            g.drawLine(cx-3, cy,cx, cy );
            rs = EditWert( (long)Math.round( ymass ), ykomma[ana][0] );
            g.drawString( rs , 0 , cy + labelFontSize/2 );
            ymass += intervall;
         } while( ymass <= maxYValue[ana][0] ) ;
         
         if ( byRefLine[ana] )              // referenz Linie
         {
            cy = y0 - (int)Math.round((yRefLine[ana] - minYValue[ana][0]) * yscale[ana][0]);
            g.setColor( (Color)plotColor[ana][0] );
            g.drawLine( x0, cy, xend, cy);            
         }         
         
         rs = (String)ylabel[ana][0];
         if ( labelFontMetrics.stringWidth(rs) > 1 )         // y label
         {
            g.setColor( labelColor );
            cy = titleFont.getSize();
            g.drawString( rs, 0, cy );
         }  
         
         if ( gtype[ana] > 0 )                  // Hilfslinien zeichnen waagrecht
         {
            g.setColor( gridColor );
            px1 = x0 ;
            px2 = x0 + xgrafSize ;
            py1 = y0 ;
            ymass  = minYValue[ana][0] + intervall;
            ymgrid = maxYValue[ana][0] - intervall;
            do
            {
               py1 = y0 -(int)Math.round( (ymass-minYValue[ana][0]) * yscale[ana][0] );
               switch( gtype[ana] )
               {
                  default:
                  case 1:              // Linie
                  g.drawLine( px1, py1, px2, py1 );
                  break;
                   
                  case 2:              // gestrichelt 
                  for ( i = px1; i < px2 ; i += 12 )
                  {
                     g.drawLine( i, py1, i+6, py1 );
                  }
                  break;
                    
                  case 3:              // gepunktet 
                  for ( i = px1; i < px2 ; i += 6 )
                  {
                     g.drawLine( i, py1, i+1, py1 );
                  }
                  break;    
               }
               ymass += intervall ;                  
            } while( ymass <= ymgrid );   
         }
         
         if ( groups[ana] > 1 )        // 2. bis n. y-Achse
         {
            cx = xend ;                // y-Achse start rechts
            
            for ( n=1; n < groups[ana]; n++)
            {              
               wmass = minYValue[ana][n];
               intervall = ( maxYValue[ana][n] - minYValue[ana][n] ) / 10 ;
               if ( intervall == 0 )
                  intervall = 1;
               
               if ( n >= 2 )           // neue Senkrechte Linie malen
               {
                  g.drawLine( cx, y0 - ygrafSize, cx, y0 );
               }               
               
               do
               {
                  cy = y0 - (int)Math.round( ( wmass - minYValue[ana][n] ) * yscale[ana][n] );
                  g.drawLine( cx, cy, cx+3, cy );
                  rs = EditWert( (long)Math.round( wmass ), ykomma[ana][n] );                  
                  g.drawString( rs, cx+5, cy );
                  wmass += intervall ;               
               } while ( wmass <= maxYValue[ana][n] );
               
               if ( labelFontMetrics.stringWidth((String)ylabel[ana][n]) > 1 )               
               {
                  cy = labelFont.getSize();                  
                  g.drawString( (String)ylabel[ana][n], cx, cy );
               }
               rs = EditWert( (long)Math.round( maxYValue[ana][n] ), ykomma[ana][n] );
               rs2 = (String)ylabel[ana][n];            
               cx += (Math.max( labelFontMetrics.stringWidth( rs ), labelFontMetrics.stringWidth( rs2 )) + 10);                
            }             
         }     
      }
      
      g.setColor( labelColor );
      g.setFont ( labelFont );
      
      if ( bdimx[ana] )                     // -- x-Label ---
      {        
         cx = getSize().width ;
         cx -= labelFontMetrics.stringWidth( (String)dimx[ana] );
         cy = y0 + ( labelFont.getSize()*2) + 3;
         g.drawString( (String)dimx[ana], cx-5, cy );          
      }      
      
      cy = getSize().height - 2;     
      if ( bfoot[ana] )
      {                  
         cx = ( getSize().width - labelFontMetrics.stringWidth( (String)footnote[ana] )) / 2;
         if ( cx < 0 )
            cx = 0;
         else
         {            
            g.drawString( "Gmess V5", 2, cy );     // 17.2.12            
         }
         g.drawString( (String)footnote[ana], cx, cy );
         cy -= labelFontMetrics.getHeight() ;         
      }      

      if ( legend[ana] )                    //------- Legende zeichnen
      {
         int cxstart;
         plotLines = ywerte[ana];
         if ( plotLines > legendsPerLine )
            plotLines = legendsPerLine ;
         cx = ((labelFontSize + 8 + maxLegendWidth) * plotLines ) / 2;  // x platzbedarf / 2
         cx = ( getSize().width / 2 ) - cx ;                            // x Start
         if ( cx < 0 )
            cx = 0;
         cxstart = cx;
         cy -=  labelFontSize;
         
         for ( n=0; n < ywerte[ana]; n++ )
         {
            if ( n > 0 )
            {
               if ( (n % legendsPerLine) == 0 )               // neue Zeile
               {
                  cy -= labelFontMetrics.getHeight() ;
                  cx = cxstart;
               }   
            }
            g.setColor( (Color)plotColor[ana][ n ] );
            g.fillRect( cx, cy, labelFontSize, labelFontSize );
                                                              // merke fuer mouse abfrage
            legendeTerms[ n ] = new Rectangle( cx, cy, labelFontSize, labelFontSize ); 
            g.setColor( labelColor );
            g.drawString( (String)legends[ana][ n ], cx+2+labelFontSize, cy+labelFontSize-labelFontMetrics.getDescent() / 2);
            cx += labelFontSize + 8 + maxLegendWidth ;                                                            
         }
      }      
   }


   // -------------------------------- Kontrolle paint
   // in gb wird das Bild erstellet
   // in wird zum Bild die Linien dazu gemalt
   // -----------------------------------------
   public void paint(Graphics g)
   {
      int rc;
      if ( ValueAuswahl >= 0 )
	   {         
	      do_plot( gb , ValueAuswahl );
	      mdragged = 0;
	      g.drawImage( img, 0, 0, this );
	      if( drag )
         {
           rc = dispxy( g );
           if ( rc == 1 )
              g.drawImage( img, 0, 0, this );
         }  
	   }
	   else
	   {
         if ( mdragged == 0 || mdragged > 2 )
            do_plot( gb , -1 ); 
         g.drawImage( img, 0, 0, this );
         if( drag )
         {
            rc = dispxy( g );
            if ( rc == 1 )
               g.drawImage( img, 0, 0, this );
         }  
	   }	
   }
   
                              // x-y Werte anzeigen
   int dispxy(Graphics g)
   {
      long xmass = 0;
      long ymass = 0;
      int cx, cy, i, n, tx1, ty1, ty2, ty3;
      int ty = 0;
      int k = xkomma[ana];
      int breite, zeilen;
      double dt, dx;
      String rsx, rsy, rsw ;
      int xP[ ] = new int[ 7 ];
      int yP[ ] = new int[ 7 ];
      
      rsx = "";
      rsy = "";
      rsw = "";
      g.setFont(labelFont);
      
      dt =  y0 - y ;
      if ( dt >= 0 && x >= x0 && x <= xend )
      {
                                        // wertepaar ermitteln i = xWert
         for( i=0; i < graf_xwerte[ana]; i++ )
         {
            if ( xpixels[ i ] >= x )
            {
               x = xpixels[ i ];       // x auf den Messwert
               break;
            }    
         }
         dx = x - x0 ; 
         xmass = xvalues[ i ];
         
         if ( ana == 0 && xmass == xmass_old )
         {
            ana = 1;
            init_plot( xmass );     // g Werte Zeichnen      
            do_plot( gb, -1 );      // bild zeichnen mit allen Werten
            return(1);
         }
         
         xmass_old = xmass;
         
         if ( xkomma[ana] == 4 )
            k = 6;            // volle Zeit eintragen
         rsx = "x=" + EditWert( xmass, k ) + " " + (String)dimx[ana];
                                      // y Wert ermitteln
         if ( bplotAreas )
         {
            if ( oldValue == -1 )
            {
               ymass = yvalues[ i ] [ywerte[ana]-1] ;
            }
            else                  // mouse pressed
            {
               ymass = yvalues[ i ] [oldValue] ;
               if ( oldValue > 0 )
               {
                  ymass -= yvalues[ i ] [oldValue-1] ;
               }   
            }
            y = y0 - (int)Math.round( (ymass - minYValue[ana][0] ) * yscale[ana][0]);      
         }
         else
         {
            if ( oldValue == -1 )
            {
               for( n=0; n < ywerte[ana]; n++ )
               {              
                  gv = groupindex[ana][n];
                  ymass = yvalues[ i ] [ n ];
                  ty = y0 - (int)Math.round(( ymass - minYValue[ana][gv]) * yscale[ana][gv]);
                  if ( ty < y+5 && ty > y-5 )
                     break;
               }               
            }
            else
            {
               if ( oldValue < ywerte[ana] )           // Mouse Auswahl
               {
                  gv = groupindex[ana][oldValue];
                  ymass = yvalues[ i ] [ oldValue ];
                  ty = y0 - (int)Math.round(( ymass - minYValue[ana][gv]) * yscale[ana][gv]);
               }               
            }
            y = ty ;      
         }
         dt = y0 - y; 
         
         rsy = "y="+ EditWert( (long)Math.round( ymass ), ykomma[ana][gv] ) + " " + ylabel[ana][gv];
         breite = Math.max( labelFontMetrics.stringWidth( rsx ), labelFontMetrics.stringWidth( rsy ));
         zeilen = 2;
         
         xP[0]=x;       yP[0]=y;
         xP[6]=x;       yP[6]=y;
         xP[1]=x+4;     yP[1]=y-8;
         xP[2]=xP[1];   yP[2]=y-6-( labelFont.getSize()*zeilen);
         xP[3]= breite;
         xP[3]+= x+6;   yP[3]=yP[2];
         xP[4]=xP[3];   yP[4]=y-4;
         xP[5]=x+12;    yP[5]=yP[4];
         
         if ( xP[3] > xend )                  // spiegeln um vertikale achse
         {
            for( int ii = 1; ii < 6; ii++)
               xP[ii] = xP[0] - ( xP[ii] - xP[0]);
         }
         if ( yP[2] < ( y0 - ygrafSize ))     // spiegeln um die horizontale
         {
            for( int ii = 1; ii < 6; ii++)
              yP[ii] = yP[0] + ( yP[0] - yP[ii]);
         }       
         g.setColor( Color.yellow ) ;    
         g.fillPolygon( xP, yP, 7 );
         g.setColor( Color.black );
         g.drawPolygon( xP, yP, 7 );
         
         tx1 = Math.min( xP[1], xP[3] )+2;
         ty3 = Math.max( yP[4], yP[2] )-1;
         ty2 = ty3 - labelFont.getSize() - 1;
         ty1 = ty2 - labelFont.getSize();
         
         g.drawString( rsx, tx1, ty2);
         g.drawString( rsy, tx1, ty3);            
      }
      else
      {
         if ( ana == 1 )
         {
            ana = 0;
            init_plot( 0 );     // g Werte Zeichnen      
            do_plot( gb, -1 );      // bild zeichnen mit allen Werten
            return(1);
         }
      }
      return(0);      
   }
   
   // wenn browser fenster neu aufbaut
   public void update(Graphics g)
   {
      paint( g );
   }

   // wenn browser druckt 
   public void printAll(Graphics g)
   {
      do_plot( g , ValueAuswahl );
      if( drag )
         dispxy( g );
   }
   
   /**
   *   mouse events
   */
   public void mouseReleased( MouseEvent e ) {}
   public void mouseEntered ( MouseEvent e ) {}
   public void mouseExited  ( MouseEvent e ) {}
   public void mouseClicked ( MouseEvent e ) {}
   public void mouseDragged ( MouseEvent e ) {}
   
   public void mousePressed ( MouseEvent e )
   {
      e.consume();
      x = e.getX();
      y = e.getY();
      drag = true;
      ValueAuswahl = -1 ;
      mdragged++;
      if ( x < x0 || x > xend || y > y0 )  // y achsen
      {
         if ( x < x0 )
         {
            ygrid = true;
            ygrid2 = false;
            mdragged = 0;
         }
         if ( x > xend )
         {
            ygrid = false;
            ygrid2 = true;
            mdragged = 0;
         }      
      }
      else
      {
         if ( mdragged > 2 )
         {
            if ( ygrid )
               ygrid = false;
            else if ( ygrid2 )
               ygrid2 = false;
         }   
      }
                 // click in die Legende ??
      for ( n=0; n < ywerte[ana]; n++)
      {
         if ( legendeTerms[n].contains(x,y) )
         { 
            ValueAuswahl = n;
            break;
         }   
      }
      if ( ValueAuswahl != -1 )
      {
         if ( y > y0 || y <= (y0 - (ygrafSize+1)) )
            drag = false;
      }
      repaint();                       
   }
}
