/*
 * dxlAPRS toolchain
 *
 * Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */


#define X2C_int32
#define X2C_index32
#ifndef aprstat_H_
#include "aprstat.h"
#endif
#define aprstat_C_
#ifndef maptool_H_
#include "maptool.h"
#endif
#ifndef aprsdecode_H_
#include "aprsdecode.h"
#endif
#ifndef aprspos_H_
#include "aprspos.h"
#endif
#ifndef osi_H_
#include "osi.h"
#endif
#include <osic.h>
#ifndef aprsstr_H_
#include "aprsstr.h"
#endif
#ifndef useri_H_
#include "useri.h"
#endif
#ifndef aprstext_H_
#include "aprstext.h"
#endif



/* aprs statistc graphs by oe5dxl */
#define aprstat_KMHTIME 600


static void setpix(maptool_pIMAGE img, int32_t x, int32_t y,
                int32_t rr, int32_t gg, int32_t bb)
{
   struct maptool_PIX * anonym;
   { /* with */
      struct maptool_PIX * anonym = &img->Adr[(x)*img->Len0+y];
      anonym->r = (uint16_t)rr;
      anonym->g = (uint16_t)gg;
      anonym->b = (uint16_t)bb;
   }
} /* end setpix() */


static void str(maptool_pIMAGE img, uint32_t x, uint32_t y, char s[],
                 uint32_t s_len)
{
   uint32_t i;
   uint32_t l;
   int32_t inc;
   struct aprsdecode_COLTYP col;
   X2C_PCOPY((void **)&s,s_len);
   l = aprsstr_Length(s, s_len);
   i = 0UL;
   maptool_Colset(&col, 'W');
   while (i<l) {
      maptool_drawchar(img, s[i], (float)x, (float)y, &inc, 700UL, 1UL,
                 col, 0);
      x += (uint32_t)inc;
      ++i;
   }
   X2C_PFREE(s);
} /* end str() */


static void num(maptool_pIMAGE img, int32_t x, int32_t y, int32_t n,
                char h[], uint32_t h_len)
{
   char s[51];
   X2C_PCOPY((void **)&h,h_len);
   aprsstr_IntToStr(n, 1UL, s, 51ul);
   aprsstr_Append(s, 51ul, h, h_len);
   str(img, (uint32_t)x, (uint32_t)y, s, 51ul);
   X2C_PFREE(h);
} /* end num() */


static float sq(float x)
{
   return x*x;
} /* end sq() */


static uint32_t pixl(float x, float y)
{
   x = x*x+y*y;
   if (x<=0.0f) return 0UL;
   return aprsdecode_trunc(256.0f*osic_sqrt(x));
} /* end pixl() */
/*
BEGIN RETURN TRUNC(256.0*(ABS(x) + ABS(y))) END pixl;
*/

#define aprstat_KL 512


static void addpix(maptool_pIMAGE img, float x, float y, uint32_t rr,
                 uint32_t gg, uint32_t bb)
{
   float fy;
   float fx;
   uint32_t l;
   uint32_t yy;
   uint32_t xx;
   struct maptool_PIX * anonym;
   struct maptool_PIX * anonym0;
   struct maptool_PIX * anonym1;
   struct maptool_PIX * anonym2;
   xx = aprsdecode_trunc(x);
   yy = aprsdecode_trunc(y);
   fx = x-(float)xx;
   fy = y-(float)yy;
   l = pixl(1.0f-fx, 1.0f-fy);
   { /* with */
      struct maptool_PIX * anonym = &img->Adr[(xx)*img->Len0+yy];
      anonym->r += (uint16_t)((rr*l)/512UL);
      anonym->g += (uint16_t)((gg*l)/512UL);
      anonym->b += (uint16_t)((bb*l)/512UL);
   }
   l = pixl(fx, 1.0f-fy);
   { /* with */
      struct maptool_PIX * anonym0 = &img->Adr[(xx+1UL)*img->Len0+yy];
      anonym0->r += (uint16_t)((rr*l)/512UL);
      anonym0->g += (uint16_t)((gg*l)/512UL);
      anonym0->b += (uint16_t)((bb*l)/512UL);
   }
   l = pixl(1.0f-fx, fy);
   { /* with */
      struct maptool_PIX * anonym1 = &img->Adr[(xx)*img->Len0+(yy+1UL)];
      anonym1->r += (uint16_t)((rr*l)/512UL);
      anonym1->g += (uint16_t)((gg*l)/512UL);
      anonym1->b += (uint16_t)((bb*l)/512UL);
   }
   l = pixl(fx, fy);
   { /* with */
      struct maptool_PIX * anonym2 = &img->Adr[(xx+1UL)*img->Len0+(yy+1UL)];
      anonym2->r += (uint16_t)((rr*l)/512UL);
      anonym2->g += (uint16_t)((gg*l)/512UL);
      anonym2->b += (uint16_t)((bb*l)/512UL);
   }
} /* end addpix() */

#define aprstat_KL0 512


static void fillpix(maptool_pIMAGE img, uint32_t x, uint32_t yfrom,
                float yto, uint32_t rr, uint32_t gg, uint32_t bb)
{
   float fy;
   uint32_t yy;
   struct maptool_PIX * anonym;
   yy = aprsdecode_trunc(yto);
   fy = yto-(float)yy;
   while (yfrom<=yy) {
      { /* with */
         struct maptool_PIX * anonym = &img->Adr[(x)*img->Len0+yfrom];
         anonym->r += (uint16_t)rr;
         anonym->g += (uint16_t)gg;
         anonym->b += (uint16_t)bb;
      }
      ++yfrom;
   }
} /* end fillpix() */


static uint32_t sfact(float y)
{
   uint32_t m;
   uint32_t s;
   s = 1UL;
   m = 2UL;
   while (X2C_DIVR(y,(float)s)>X2C_DIVR(200.0f,
                (float)(aprsdecode_lums.fontysize+2UL))) {
      s = s*m;
      if (m==2UL) m = 5UL;
      else m = 2UL;
   }
   return s;
} /* end sfact() */


static uint32_t dynmaxx(uint32_t margin, uint32_t min0,
                uint32_t max0)
{
   if (max0+margin*2UL>(uint32_t)maptool_xsize) {
      if ((uint32_t)maptool_xsize>min0) {
         max0 = (uint32_t)maptool_xsize-margin*2UL;
      }
      else max0 = min0-margin*2UL;
   }
   return max0;
} /* end dynmaxx() */

#define aprstat_MAXT 7200

#define aprstat_X 620

#define aprstat_Y 150

#define aprstat_MARGIN1 16

#define aprstat_XI 636

#define aprstat_YI 166


extern void aprstat_btimehist(maptool_pIMAGE * img, aprsdecode_pOPHIST op)
{
   uint32_t t[7200];
   aprsdecode_pFRAMEHIST pf;
   uint32_t textd;
   uint32_t textx;
   uint32_t max0;
   uint32_t expand;
   uint32_t scale0;
   uint32_t xm;
   uint32_t sum;
   uint32_t y;
   uint32_t i;
   uint32_t dt;
   char s[256];
   uint32_t tmp;
   size_t tmp0[2];
   if (op==0) return;
   for (i = 0UL; i<=7199UL; i++) {
      t[i] = 0UL;
   } /* end for */
   pf = op->frames;
   sum = 0UL;
   if (pf) {
      while (pf->next) {
         if (maptool_vistime(pf->time0) && pf->next->time0>=pf->time0) {
            dt = pf->next->time0-pf->time0;
            if (dt<=7199UL) {
               ++t[dt];
               ++sum;
            }
         }
         pf = pf->next;
      }
   }
   sum -= sum/20UL;
   xm = 0UL;
   y = 0UL;
   do {
      y += t[xm];
      ++xm;
   } while (!(xm>=7199UL || y>=sum));
   ++xm;
   if (xm<120UL) xm = 120UL;
   for (i = xm+1UL; i<=7199UL; i++) {
      t[xm] += t[i]; /* add not shown rest to last shown element */
   } /* end for */
   scale0 = ((xm+620UL)-1UL)/620UL;
   textd = 50UL;
   if (scale0>30UL) {
      scale0 = 60UL;
      textx = 50UL;
   }
   else if (scale0>12UL) {
      scale0 = 30UL;
      textx = 20UL;
   }
   else if (scale0>6UL) {
      scale0 = 12UL;
      textx = 10UL;
   }
   else if (scale0>3UL) {
      scale0 = 6UL;
      textx = 5UL;
   }
   else if (scale0>2UL) {
      scale0 = 3UL;
      textx = 3UL;
      textd = 60UL;
   }
   else if (scale0>1UL) {
      scale0 = 2UL;
      textx = 2UL;
      textd = 60UL;
   }
   else {
      scale0 = 1UL;
      textx = 1UL;
      textd = 60UL;
   }
   if (scale0>1UL) {
      for (i = 1UL; i<=7199UL; i++) {
         if (i%scale0==0UL) t[i/scale0] = 0UL;
         t[i/scale0] += t[i];
      } /* end for */
   }
   xm = ((xm+scale0)-1UL)/scale0;
   expand = 1UL;
   if (xm<310UL) expand = 2UL;
   else if (xm>620UL) xm = 620UL;
   else if (xm==0UL) return;
   xm = xm*expand;
   max0 = 0UL;
   tmp = xm-1UL;
   i = 0UL;
   if (i<=tmp) for (;; i++) {
      if (t[i]>max0) max0 = t[i];
      if (i==tmp) break;
   } /* end for */
   if (max0==0UL) return;
   tmp = xm-1UL;
   i = 0UL;
   if (i<=tmp) for (;; i++) {
      t[i] = (t[i]*150UL)/max0;
      if (i==tmp) break;
   } /* end for */
   X2C_DYNALLOCATE((char **)img,sizeof(struct maptool_PIX),
                (tmp0[0] = xm+16UL,tmp0[1] = 166U,tmp0),2u);
   useri_debugmem.screens += (*img)->Len1*(*img)->Size1;
   if (*img==0) {
      osi_WrStrLn("error image alloc", 18ul);
      return;
   }
   maptool_clr(*img);
   tmp = xm-1UL;
   i = 0UL;
   if (i<=tmp) for (;; i++) {
      setpix(*img, (int32_t)(i+8UL), 7L, 0L, 500L, 800L);
      if ((i/expand)%10UL==0UL) {
         setpix(*img, (int32_t)(i+8UL), 6L, 0L, 500L, 800L);
      }
      if ((i/expand)%textd==0UL) {
         setpix(*img, (int32_t)(i+8UL), 5L, 0L, 500L, 800L);
         setpix(*img, (int32_t)(i+8UL), 4L, 0L, 500L, 800L);
      }
      for (y = 0UL; y<=149UL; y++) {
         setpix(*img, (int32_t)(i+8UL), (int32_t)(y+8UL), 50L,
                (int32_t)(20UL*(uint32_t)(char)((i/expand)/10UL&1)
                +30UL), 30L);
      } /* end for */
      y = 0UL;
      while (y<t[i/expand]) {
         setpix(*img, (int32_t)(i+8UL), (int32_t)(y+8UL), 500L, 500L,
                0L);
         ++y;
      }
      if (i==tmp) break;
   } /* end for */
   for (i = 0UL; i<=149UL; i++) {
      setpix(*img, 7L, (int32_t)((i+8UL)-1UL), 0L, 500L, 800L);
      if (i%10UL==0UL) {
         setpix(*img, 6L, (int32_t)((i+8UL)-1UL), 0L, 500L, 800L);
      }
   } /* end for */
   strncpy(s," Beacons per Time ",256u);
   aprsstr_Append(s, 256ul, op->call, 9ul);
   num(*img, 10L, (int32_t)((166UL-aprsdecode_lums.fontysize)-1UL),
                (int32_t)max0, s, 256ul);
   num(*img, (int32_t)((expand*textd+8UL)-12UL), 8L, (int32_t)textx, "m",
                 2ul);
/*
  DISPOSE(img);
*/
} /* end btimehist() */

#define aprstat_MAXX 1584

#define aprstat_MINX 584

#define aprstat_MAXY 120

#define aprstat_MARGIN 8

#define aprstat_XSTEPS 8
/* in 1 pixel */

#define aprstat_FILTERLEN 6
/* median filter span in pixels */

#define aprstat_NOINFOTIME 300
/* seconds timeout to no info */

#define aprstat_MINSPAN 3600

#define aprstat_MAXSPAN 28800


extern void aprstat_kmhist(maptool_pIMAGE * img, aprsdecode_pOPHIST op,
                char * test)
{
   aprsdecode_pFRAMEHIST fold;
   aprsdecode_pFRAMEHIST fto;
   aprsdecode_pFRAMEHIST ffrom;
   aprsdecode_pFRAMEHIST fr;
   uint32_t ot;
   uint32_t t1;
   uint32_t t0;
   uint32_t markkm;
   uint32_t markx;
   uint32_t maxx;
   uint32_t maxkm10;
   uint32_t maxkm;
   uint32_t tf;
   uint32_t sp;
   uint32_t i;
   uint32_t xi;
   uint32_t xt;
   float ys;
   float dy;
   float maxy;
   char h[256];
   char s[256];
   struct aprspos_POSITION po;
   float vt[12720];
   char marks[1584];
   uint32_t tops[5];
   struct aprsdecode_DAT dat;
   uint32_t tmp;
   size_t tmp0[2];
   if (op==0 || op->frames==0) {
      *test = 0;
      return;
   }
   fto = 0;
   ffrom = 0;
   fr = op->frames;
   po = fr->vardat->pos;
   fold = 0;
   do {
      /* find first to last move */
      if (((maptool_vistime(fr->time0) && !(fr->nodraw&~0x1U))
                && aprspos_posvalid(fr->vardat->pos)) && aprspos_distance(po,
                 fr->vardat->pos)>0.05f) {
         /* find last move */
         fto = fr;
         po = fr->vardat->pos;
         if (ffrom==0) ffrom = fold;
         fold = fr;
      }
      fr = fr->next;
   } while (fr);
   if (fto==0 || ffrom==0) {
      *test = 0; /* no move */
      return;
   }
   if (*test) return;
   *img = 0;
   for (xi = 0UL; xi<=1583UL; xi++) {
      marks[xi] = 0;
   } /* end for */
   /*
     IF ffrom=NIL THEN ffrom:=op^.frames END;
   */
   t1 = fto->time0;
   while (ffrom->next && (!(~ffrom->nodraw&0x1U) || ffrom->time0+28800UL<t1))
                 ffrom = ffrom->next;
   t0 = ffrom->time0;
   if (t1<t0+3600UL) {
      t1 = t0+3600UL;
      fto = 0;
   }
   /* find peak speeds to filter extrem values */
   for (i = 0UL; i<=4UL; i++) {
      tops[i] = 0UL;
   } /* end for */
   fr = ffrom;
   for (;;) {
      if ((!(fr->nodraw&~0x1U) && aprsdecode_Decode(fr->vardat->raw, 500ul,
                &dat)>=0L) && dat.speed<X2C_max_longcard) {
         i = 0UL;
         for (;;) {
            if (dat.speed>=tops[i]) {
               tops[i] = dat.speed;
               break;
            }
            ++i;
            if (i>4UL) break;
         }
      }
      if (fr==fto) break;
      fr = fr->next;
      if (fr==0) break;
   }
   /*FOR i:=0 TO HIGH(tops) DO WrInt(tops[i], 10) END; */
   while ((float)tops[0U]>(float)tops[1U]*1.5f) {
      for (i = 0UL; i<=3UL; i++) {
         tops[i] = tops[i+1UL];
      } /* end for */
   }
   markx = 0UL;
   markkm = 0UL;
   maxx = (1584UL*((t1-t0)+3600UL))/28800UL; /* guess picture width */
   if (maxx<584UL) maxx = 584UL;
   else if (maxx>1584UL) maxx = 1584UL;
   ot = t0;
   fr = ffrom;
   xi = 0UL;
   maxy = 0.0f;
   dy = 0.0f;
   tf = 0UL;
   for (;;) {
      if ((!(fr->nodraw&~0x1U) && aprsdecode_Decode(fr->vardat->raw, 500ul,
                &dat)>=0L) && (!useri_configon(useri_fTRACKFILT)
                || dat.speed<tops[0U])) {
         dy = (float)aprsdecode_knottokmh((int32_t)dat.speed)+0.5f;
         if (dy>1000.0f) dy = 1000.0f;
         if (fr->time0>ot+300UL) tf = 48UL;
         xt = aprsdecode_trunc((X2C_DIVR((float)(fr->time0-t0),
                (float)(t1-t0)))*(float)(maxx*8UL-1UL));
                /* x position in picture */
         if (xt>=maxx*8UL-1UL) xt = maxx*8UL;
         if (xi/8UL>3UL) marks[xi/8UL-3UL] = 1;
         if (dy>maxy) maxy = dy;
         while (xi<xt) {
            /* constant speed till next waypoint */
            vt[xi] = dy;
            ++xi;
            if (tf>0UL) {
               --tf;
               if (tf==0UL) dy = 0.0f;
            }
         }
         ot = fr->time0;
         if ((dat.pos.lat==aprsdecode_click.markpos.lat && dat.pos.long0==aprsdecode_click.markpos.long0)
                 && aprsdecode_click.markpost==ot) {
            markx = xi/8UL;
            markkm = (uint32_t)aprsdecode_knottokmh((int32_t)dat.speed);
         }
      }
      if (fr==fto) break;
      fr = fr->next;
      if (fr==0) break;
   }
   tf = 48UL;
   while (xi<=12719UL) {
      vt[xi] = dy;
      ++xi;
      if (tf>0UL) --tf;
      else dy = 0.0f;
   }
   tmp = maxx*8UL-1UL;
   xi = 0UL;
   if (xi<=tmp) for (;; xi++) {
      dy = 0.0f;
      for (xt = 0UL; xt<=47UL; xt++) {
         dy = dy+vt[xi+xt]*(1.0f-sq((float)xt*4.1666666666667E-2f-1.0f));
                /* FIR lowpass */
      } /* end for */
      vt[xi] = dy;
      if (xi==tmp) break;
   } /* end for */
   maxkm = aprsdecode_trunc(maxy);
   maxkm10 = ((maxkm+9UL)/10UL)*10UL;
   if (maxy>=2.0f) {
      maxy = X2C_DIVR(3.75f,(float)maxkm10); /* FIR gain integral 1-x^2 */
      for (xi = 0UL; xi<=12719UL; xi++) {
         vt[xi] = vt[xi]*maxy; /* fit y in picture */
      } /* end for */
      X2C_DYNALLOCATE((char **)img,sizeof(struct maptool_PIX),
                (tmp0[0] = maxx+16UL,tmp0[1] = 136U,tmp0),2u);
      useri_debugmem.screens += (*img)->Len1*(*img)->Size1;
      if (*img==0) {
         osi_WrStrLn("error image alloc", 18ul);
         return;
      }
      maptool_clr(*img);
      /*
          FOR xt:=MARGIN TO MAXY+MARGIN-1 DO  
            FOR xi:=MARGIN TO MAXX+MARGIN-1 DO
              WITH img^[xi+xt*(MAXX+2*MARGIN)] DO 
                r:=30; g:=60+50*ORD(ODD(xt DIV 10));
                b:=80+200*ORD(marks[xi-MARGIN]);
              END;
            END;
          END;
      */
      dy = (X2C_DIVR(120.0f,(float)maxkm10))*10.0f;
      ys = 0.0f;
      xt = 0UL;
      sp = 0UL;
      do {
         /* draw y scale and paper and waypoints*/
         for (i = 6UL-2UL*(uint32_t)(sp%5UL==0UL); i<=8UL; i++) {
            setpix(*img, (int32_t)i,
                (int32_t)(aprsdecode_trunc(ys+0.5f)+8UL), 200L, 1000L,
                200L);
         } /* end for */
         ys = ys+dy;
         while (xt<aprsdecode_trunc(ys) && xt<120UL) {
            tmp = (maxx+8UL)-1UL;
            xi = 8UL;
            if (xi<=tmp) for (;; xi++) {
               setpix(*img, (int32_t)xi, (int32_t)(xt+8UL), 20L,
                (int32_t)(30UL+50UL*(uint32_t)(char)(sp&1)),
                (int32_t)(60UL+200UL*(uint32_t)marks[xi-8UL]));
               if (xi==tmp) break;
            } /* end for */
            ++xt;
         }
         ++sp;
      } while (ys<121.0f);
      tmp = maxx-1UL;
      xi = 0UL;
      if (xi<=tmp) for (;; xi++) {
         setpix(*img, (int32_t)(xi+8UL), 8L, 200L, 1000L, 200L);
         if (xi==tmp) break;
      } /* end for */
      for (xi = 0UL; xi<=120UL; xi++) {
         setpix(*img, 8L, (int32_t)(xi+8UL), 200L, 1000L, 200L);
      } /* end for */
      sp = t0/3600UL+1UL;
      ot = sp*3600UL;
      ys = X2C_DIVR((float)(maxx*(ot-t0)),(float)(t1-t0));
                /* x of first full hour */
      dy = X2C_DIVR((float)(maxx*3600UL),(float)(t1-t0));
                /* x size of 1h */
      if (dy>20.0f && ys<=(float)maxx) {
         if (ys-dy*0.5f>0.0f) {
            /* draw 1/2 h mark */
            for (i = 6UL; i<=7UL; i++) {
               setpix(*img, (int32_t)(aprsdecode_trunc(ys-dy*0.5f)+8UL),
                (int32_t)i, 200L, 1000L, 200L);
            } /* end for */
         }
         sp = sp+24UL+useri_localtime()/3600UL;
         do {
            /* draw h and rest of 1/2h marks */
            for (i = 4UL; i<=7UL; i++) {
               setpix(*img, (int32_t)(aprsdecode_trunc(ys)+8UL),
                (int32_t)i, 200L, 1000L, 200L);
            } /* end for */
            if (ys+dy*0.5f<=(float)maxx) {
               for (i = 6UL; i<=7UL; i++) {
                  setpix(*img, (int32_t)(aprsdecode_trunc(ys+dy*0.5f)+8UL),
                 (int32_t)i, 200L, 1000L, 200L);
               } /* end for */
            }
            num(*img, (int32_t)((aprsdecode_trunc(ys)+8UL)-6UL), 8L,
                (int32_t)(sp%24UL), "h", 2ul);
            ++sp;
            ys = ys+dy;
         } while (ys<=(float)maxx);
      }
      if (markx>3UL) {
         markx -= 3UL;
         for (xi = 8UL; xi<=128UL; xi++) {
            setpix(*img, (int32_t)(markx+8UL), (int32_t)xi, 500L, 200L,
                50L);
         } /* end for */
      }
      tmp = maxx*8UL-1UL;
      xi = 8UL;
      if (xi<=tmp) for (;; xi++) {
         /* draw graph */
         dy = vt[xi];
         if (dy>=0.1f) {
            if (dy>120.0f) dy = 120.0f;
            addpix(*img, (float)xi*0.125f+8.0f, dy+8.0f, 125UL, 125UL,
                12UL);
         }
         if (xi==tmp) break;
      } /* end for */
      strncpy(s,"  ",256u);
      aprsstr_Append(s, 256ul, op->call, 9ul);
      aprsstr_Append(s, 256ul, " max=", 6ul);
      aprsstr_IntToStr((int32_t)maxkm, 1UL, h, 256ul);
      aprsstr_Append(s, 256ul, h, 256ul);
      if (markx>0UL) {
         aprsstr_Append(s, 256ul, " cursor=", 9ul);
         aprsstr_IntToStr((int32_t)markkm, 1UL, h, 256ul);
         aprsstr_Append(s, 256ul, h, 256ul);
      }
      aprsstr_Append(s, 256ul, "km/h", 5ul);
      num(*img, 10L, (int32_t)((136UL-aprsdecode_lums.fontysize)-1UL),
                (int32_t)maxkm10, s, 256ul);
   }
/*
  IF img<>NIL THEN DISPOSE(img) END;
*/
} /* end kmhist() */


static void paper(maptool_pIMAGE * img, float yax0, float yax1,
                uint32_t step, uint32_t margin, uint32_t maxx,
                uint32_t maxy, char name[], uint32_t name_len)
{
   uint32_t y;
   uint32_t x;
   int32_t so;
   int32_t s;
   float v;
   struct maptool_PIX * anonym;
   uint32_t tmp;
   uint32_t tmp0;
   X2C_PCOPY((void **)&name,name_len);
   so = osi_realint(aprsdecode_floor(X2C_DIVR(yax0,(float)step)));
   tmp = maxy-1UL;
   y = 0UL;
   if (y<=tmp) for (;; y++) {
      setpix(*img, (int32_t)margin, (int32_t)(y+margin), 200L, 1000L,
                200L);
      v = yax0+(yax1-yax0)*(float)y*(X2C_DIVR(1.0f,(float)maxy));
      s = osi_realint(aprsdecode_floor(X2C_DIVR(v,(float)step)));
      tmp0 = (maxx-1UL)+margin;
      x = margin+1UL;
      if (x<=tmp0) for (;; x++) {
         { /* with */
            struct maptool_PIX * anonym = &(*img)->Adr[(x)*(*img)
                ->Len0+(y+margin)];
            anonym->r += 60U;
            anonym->g += (uint16_t)(50UL+40UL*(uint32_t)(char)
                (s&1));
            anonym->b += 60U;
         }
         if (x==tmp0) break;
      } /* end for */
      if (s!=so) {
         tmp0 = margin-1UL;
         x = margin-3UL;
         if (x<=tmp0) for (;; x++) {
            setpix(*img, (int32_t)x, (int32_t)(y+margin), 200L, 1000L,
                200L);
            if (x==tmp0) break;
         } /* end for */
         num(*img, (int32_t)(margin+1UL), (int32_t)((y+margin)-6UL),
                s*(int32_t)step, "", 1ul);
         so = s;
      }
      if (y==tmp) break;
   } /* end for */
   str(*img, margin+50UL, ((maxy+margin*2UL)-aprsdecode_lums.fontysize)-1UL,
                name, name_len);
   X2C_PFREE(name);
} /* end paper() */

#define aprstat_MAXXX 720

#define aprstat_MAXY0 120

#define aprstat_MARGIN0 8

#define aprstat_XSTEPS0 8
/* in 1 pixel */

#define aprstat_EMPTY (-10000)

#define aprstat_MAXALT 50000

static float aprstat_E = (-1.E+4f);


static void decodealt(uint32_t * beacons, float * resol, float wdiv,
                uint32_t * rejs, uint32_t * acks, uint32_t * msgs,
                struct aprsdecode_DAT * dat, float ground[5760],
                float alt[5760], char * end, float * waysum,
                aprsdecode_pOPHIST op, int32_t * markalt,
                uint32_t * markx1, uint32_t * markx, char do0)
{
   aprsdecode_pFRAMEHIST fr;
   struct aprspos_POSITION opos;
   float ognd;
   float a3;
   float a2;
   float a1;
   float a;
   uint32_t xc;
   uint32_t x;
   *markx = 0UL;
   *markx1 = 0UL;
   *markalt = X2C_min_longint;
   fr = op->frames;
   aprsdecode_posinval(&opos);
   *waysum = 0.0f;
   xc = 1UL;
   a = (-1.E+4f);
   a2 = (-1.E+4f);
   a3 = (-1.E+4f);
   ognd = (-1.E+4f);
   *end = 0;
   for (x = 0UL; x<=5759UL; x++) {
      alt[x] = (-1.E+4f);
   } /* end for */
   for (x = 0UL; x<=5759UL; x++) {
      ground[x] = (-1.E+4f);
   } /* end for */
   for (;;) {
      /* sum up km driven */
      if (maptool_vistime(fr->time0) && aprsdecode_Decode(fr->vardat->raw,
                500ul, dat)>=0L) {
         if (dat->type==aprsdecode_MSG) {
            /* count msg stuff */
            if (dat->ackrej==aprsdecode_MSGMSG) ++*msgs;
            else if (dat->ackrej==aprsdecode_MSGACK) ++*acks;
            else ++*rejs;
         }
         if (!useri_configon(useri_fTRACKFILT) || !(fr->nodraw&~0x1U)) {
            if (!aprspos_posvalid(dat->pos)) dat->pos = fr->vardat->pos;
            if (aprspos_posvalid(dat->pos)) {
               x = aprsdecode_trunc( *waysum*wdiv);
               if (aprspos_posvalid(opos)) {
                  *waysum = *waysum+aprspos_distance(opos, dat->pos);
               }
               if (dat->altitude>-10000L && dat->altitude<=50000L) {
                  a1 = (float)dat->altitude;
                  if (do0) {
                     if (x>5759UL) x = 5759UL;
                     if (a2>(-1.E+4f)) {
                        if (!useri_configon(useri_fTRACKFILT) || (float)
                fabs(((a-a1)+a)-a2)*0.25f<(float)fabs(a2-a1)) {
                           /* median error filter */
                           if (alt[x]<=(-1.E+4f)) {
                              alt[x] = a;
                              xc = 1UL;
                           }
                           else {
                              ++xc;
                              alt[x] = alt[x]*(1.0f-X2C_DIVR(1.0f,
                (float)xc))+X2C_DIVR(a,(float)xc);
                           }
                        }
                     }
                     if (*markalt>X2C_min_longint && *markx==0UL) {
                        *markx = x/8UL;
                     }
                     if ((dat->pos.lat==aprsdecode_click.markpos.lat && dat->pos.long0==aprsdecode_click.markpos.long0)
                 && aprsdecode_click.markpost==fr->time0) {
                        *markalt = dat->altitude;
                     }
                     ground[x] = ognd; /* delay same as gps filter */
                     ognd = maptool_getsrtm(dat->pos, 0UL, resol);
                     if (ognd>=20000.0f) ognd = (-1.E+4f);
                  }
                  if (!*end) a3 = a2;
                  a2 = a;
                  a = a1;
               }
               opos = dat->pos;
            }
            if (!*end) ++*beacons;
         }
      }
      if (*end) break;
      if (fr->next) fr = fr->next;
      else *end = 1;
   }
   if (a3<=(-1.E+4f)) *waysum = 0.0f;
} /* end decodealt() */

static float aprstat_E0 = (-1.E+4f);


static void interpol(float a[], uint32_t a_len)
{
   uint32_t j;
   uint32_t i;
   float k;
   float y;
   i = 0UL;
   j = 0UL;
   y = (-1.E+4f);
   while (i<=a_len-1) {
      if (a[i]>(-1.E+4f)) {
         if (y<=(-1.E+4f)) y = a[i];
         if (i>j) {
            k = X2C_DIVR(1.0f,(float)(i-j));
            while (j<i) {
               a[j] = y+(a[i]-y)*(1.0f-(float)(i-j)*k);
               ++j;
            }
         }
         else ++j;
         y = a[i];
      }
      ++i;
   }
   while (j<=a_len-1) {
      a[j] = y;
      ++j;
   }
} /* end interpol() */

static float aprstat_E1 = (-1.E+4f);


static void norm(float * hdiv, char * gndok, float ground[5760],
                 float alt[5760], float * maxaltd, float * minaltd,
                float * maxalt, float * minalt)
{
   uint32_t i;
   *minalt = 2.147483647E+9f;
   *maxalt = (-2.147483648E+9f);
   *minaltd = 2.147483647E+9f;
   *maxaltd = (-2.147483648E+9f);
   for (i = 0UL; i<=5759UL; i++) {
      /*IF alt[i]>E THEN WrFixed(alt[i], 10, 20); WrStrLn("=alt") END; */
      if (alt[i]>(-1.E+4f) && alt[i]<*minaltd) *minaltd = alt[i];
      if (alt[i]>*maxaltd) *maxaltd = alt[i];
      if (ground[i]>(-1.E+4f) && ground[i]<*minalt) *minalt = ground[i];
      if (ground[i]>*maxalt) *maxalt = ground[i];
   } /* end for */
   if (*minaltd-((*maxaltd-*minaltd)+100.0f)>*minalt || (*maxaltd-*minaltd)
                *0.05f>*maxalt-*minalt) {
      /* ground graph is too far below */
      /* ground graph is a flat line */
      *minalt = *minaltd; /* make no ground graph */
      *maxalt = *maxaltd;
   }
   else {
      if (*minaltd<*minalt) *minalt = *minaltd;
      if (*maxaltd>*maxalt) *maxalt = *maxaltd;
      *gndok = 1;
   }
   if (*maxalt-*minalt>8.3333333333333E-3f) {
      *hdiv = X2C_DIVR(120.0f,*maxalt-*minalt); /* normalize */
   }
   else *hdiv = 1.0f;
   for (i = 0UL; i<=5759UL; i++) {
      alt[i] = (alt[i]-*minalt)* *hdiv;
      ground[i] = (ground[i]-*minalt)* *hdiv;
   } /* end for */
} /* end norm() */


extern void aprstat_althist(maptool_pIMAGE * img, aprsdecode_pOPHIST op,
                char * test, float * way, uint32_t * beacons,
                uint32_t * msgs, uint32_t * acks, uint32_t * rejs)
{
   char h[256];
   char s[256];
   float maxaltd;
   float minaltd;
   float maxalt;
   float minalt;
   float ground[5760];
   float alt[5760];
   float hdiv;
   float wdiv;
   uint32_t markx1;
   uint32_t markx;
   uint32_t xc;
   uint32_t sc;
   uint32_t x;
   uint32_t Maxx;
   struct aprsdecode_DAT dat;
   float resol;
   float waysum;
   int32_t markalt;
   char end;
   char gndok;
   size_t tmp[2];
   uint32_t tmp0;
   *way = 0.0f;
   *beacons = 0UL;
   *msgs = 0UL;
   *acks = 0UL;
   *rejs = 0UL;
   gndok = 0;
   minaltd = 0.0f;
   maxaltd = 0.0f;
   if (op==0 || op->frames==0) {
      *test = 0;
      return;
   }
   Maxx = dynmaxx(8UL, 400UL, 720UL);
   decodealt(beacons, &resol, wdiv, rejs, acks, msgs, &dat, ground, alt,
                &end, &waysum, op, &markalt, &markx1, &markx, 0);
   *way = waysum;
   if (waysum<0.05f) {
      *test = 0; /* no altitudes or km */
      return;
   }
   if (*test) return;
   X2C_DYNALLOCATE((char **)img,sizeof(struct maptool_PIX),
                (tmp[0] = Maxx+16UL,tmp[1] = 136U,tmp),2u);
   useri_debugmem.screens += (*img)->Len1*(*img)->Size1;
   if (*img==0) {
      osi_WrStrLn("error image alloc", 18ul);
      return;
   }
   maptool_clr(*img);
   wdiv = X2C_DIVR((float)(Maxx*8UL-1UL),waysum);
   decodealt(beacons, &resol, wdiv, rejs, acks, msgs, &dat, ground, alt,
                &end, &waysum, op, &markalt, &markx1, &markx, 1);
   interpol(alt, 5760ul);
   interpol(ground, 5760ul);
   norm(&hdiv, &gndok, ground, alt, &maxaltd, &minaltd, &maxalt, &minalt);
   /*
   FOR x:=0 TO HIGH(alt) DO
    IF alt[x]>=0.0 THEN WrFixed(alt[x], 3,11) ELSE WrStr(".") END;
   END;
    WrStrLn("");
   */
   /*sc:=VAL(CARDINAL, maxalt-minalt) DIV sfact(FLOAT(maxalt-minalt)); */
   sc = sfact(maxalt-minalt);
   strncpy(s,"  ",256u);
   aprsstr_Append(s, 256ul, op->call, 9ul);
   aprsstr_Append(s, 256ul, " dist=", 7ul);
   aprsstr_FixToStr(waysum, 2UL, h, 256ul);
   aprsstr_Append(s, 256ul, h, 256ul);
   aprsstr_Append(s, 256ul, "km min=", 8ul);
   aprsstr_IntToStr(osi_realint(minaltd), 1UL, h, 256ul);
   aprsstr_Append(s, 256ul, h, 256ul);
   aprsstr_Append(s, 256ul, "m max=", 7ul);
   aprsstr_IntToStr(osi_realint(maxaltd), 1UL, h, 256ul);
   aprsstr_Append(s, 256ul, h, 256ul);
   if (markalt>X2C_min_longint) {
      aprsstr_Append(s, 256ul, "m curs=", 8ul);
      aprsstr_IntToStr(markalt, 1UL, h, 256ul);
      aprsstr_Append(s, 256ul, h, 256ul);
   }
   aprsstr_Append(s, 256ul, "m (NN)", 7ul);
   paper(img, minalt, maxalt, sc, 8UL, Maxx, 120UL, s, 256ul);
   tmp0 = Maxx+8UL;
   x = 5UL;
   if (x<=tmp0) for (;; x++) {
      setpix(*img, (int32_t)x, 8L, 200L, 1000L, 200L);
      if (x==tmp0) break;
   } /* end for */
   strncpy(h,"km",256u);
   if (waysum<5.0f) {
      waysum = waysum*1000.0f;
      strncpy(h,"m",256u);
   }
   sc = sfact(waysum);
   hdiv = X2C_DIVR((float)sc*(float)Maxx,waysum);
   wdiv = 0.0f;
   xc = 0UL;
   do {
      for (x = 5UL; x<=7UL; x++) {
         setpix(*img, (int32_t)(aprsdecode_trunc(wdiv)+8UL), (int32_t)x,
                200L, 1000L, 200L);
      } /* end for */
      if (xc>0UL && aprsdecode_trunc(wdiv)<Maxx-10UL) {
         num(*img, (int32_t)((aprsdecode_trunc(wdiv)+8UL)-6UL), 8L,
                (int32_t)xc, h, 256ul);
         h[0U] = 0;
      }
      xc += sc;
      wdiv = wdiv+hdiv;
   } while (aprsdecode_trunc(wdiv)<=Maxx);
   if (markx>0UL) {
      for (x = 8UL; x<=128UL; x++) {
         setpix(*img, (int32_t)(markx+8UL), (int32_t)x, 50L, 400L, 500L);
      } /* end for */
   }
   tmp0 = Maxx*8UL-1UL;
   x = 0UL;
   if (x<=tmp0) for (;; x++) {
      /* draw graph */
      addpix(*img, (float)x*0.125f+8.0f, alt[x]+8.0f, 62UL, 75UL, 87UL);
      if (gndok) {
         addpix(*img, (float)x*0.125f+8.0f, ground[x]+8.0f, 31UL, 18UL,
                0UL);
      }
      if (x==tmp0) break;
   } /* end for */
   if (gndok) {
      tmp0 = Maxx-1UL;
      x = 0UL;
      if (x<=tmp0) for (;; x++) {
         fillpix(*img, x+8UL, 8UL, ground[x*8UL]+7.0f, 63UL, 38UL, 0UL);
         if (x==tmp0) break;
      } /* end for */
   }
} /* end althist() */

#define aprstat_TIMESPAN 86400

#define aprstat_MAXXX0 720

#define aprstat_MINXSIZE 320

#define aprstat_MAXY1 120

#define aprstat_MARGIN2 8

#define aprstat_ARRSIZE 1440
/*    XSTEP=FLOAT(MAXXX)/FLOAT(ARRSIZE); */

#define aprstat_INCHMM 0.254
/* inch/100 to mm */

#define aprstat_INVAL (-1.E+4)

#define aprstat_MAXJOIN 65
/* maximum interpolated span min */

struct WX;


struct WX {
   float temp;
   float hyg;
   float baro;
   float wind;
   float rain;
   float lumi;
   float siev;
};

#define aprstat_F 0.9


static void scale(float v[], uint32_t v_len, float min0,
                float max0, float ysize, float maxamp,
                float * smin, float * smax, uint32_t * step)
{
   uint32_t i;
   float d;
   float a;
   float k;
   uint32_t tmp;
   if (min0==(-1.E+4f)) {
      min0 = 0.0f;
      d = max0;
      if (d<=maxamp) d = maxamp;
      a = X2C_DIVR(ysize,d);
      k = 0.0f;
   }
   else {
      d = max0-min0;
      if (d<=maxamp) d = maxamp;
      a = X2C_DIVR(ysize*0.9f,d);
      k = ysize*0.05f;
   }
   *step = sfact(d);
   *smin = min0-X2C_DIVR(k,a);
   *smax = min0+X2C_DIVR(k,a)+d;
   tmp = v_len-1;
   i = 0UL;
   if (i<=tmp) for (;; i++) {
      if (v[i]!=(-1.E+4f)) v[i] = (v[i]-min0)*a+k;
      if (i==tmp) break;
   } /* end for */
} /* end scale() */


static char newimg(uint32_t Maxx, maptool_pIMAGE * img)
{
   size_t tmp[2];
   if (*img==0) {
      X2C_DYNALLOCATE((char **)img,sizeof(struct maptool_PIX),
                (tmp[0] = Maxx+16UL,tmp[1] = 136U,tmp),2u);
      useri_debugmem.screens += (*img)->Len1*(*img)->Size1;
   }
   if (*img==0) return 0;
   maptool_clr(*img);
   return 1;
} /* end newimg() */


static void timeline(uint32_t stime, maptool_pIMAGE * img,
                uint32_t Maxx)
{
   uint32_t y;
   uint32_t x;
   uint32_t to;
   uint32_t t;
   uint32_t tmp;
   to = 0UL;
   tmp = Maxx-1UL;
   x = 0UL;
   if (x<=tmp) for (;; x++) {
      setpix(*img, (int32_t)(x+8UL), 8L, 200L, 1000L, 200L);
      t = ((stime+useri_localtime())-(((Maxx-1UL)-x)*86400UL)/Maxx)/3600UL;
      if (to==0UL) to = t;
      if (to!=t) {
         to = t;
         for (y = 5UL; y<=7UL; y++) {
            setpix(*img, (int32_t)(x+8UL), (int32_t)y, 200L, 1000L,
                200L);
         } /* end for */
         if (x>28UL && t%3UL==0UL) {
            num(*img, (int32_t)((x+8UL)-6UL), 8L, (int32_t)(t%24UL), "h",
                 2ul);
         }
      }
      if (x==tmp) break;
   } /* end for */
} /* end timeline() */


static void dots(float XStep, maptool_pIMAGE * img, float v[],
                uint32_t v_len, char join, uint32_t r,
                uint32_t g, uint32_t b)
{
   uint32_t i;
   float dx;
   float io;
   float k;
   float yo;
   X2C_PCOPY((void **)&v,v_len*sizeof(float));
   yo = (-1.E+4f);
   io = 0.0f;
   i = 0UL;
   do {
      if (v[i]!=(-1.E+4f)) {
         maptool_waypoint(*img, (float)i*XStep+8.0f+0.5f, v[i]+8.0f, 2.0f,
                 (int32_t)r, (int32_t)g, (int32_t)b);
         if (((join && yo!=(-1.E+4f)) && i>aprsdecode_trunc(io))
                && aprsdecode_trunc(io)+65UL>=i) {
            k = X2C_DIVR(v[i]-yo,((float)i-io)+1.0f);
            if ((float)fabs(k)>2.0f) {
               dx = X2C_DIVR(2.0f,(float)fabs(k));
               k = k*dx;
            }
            else dx = 1.0f;
            while (aprsdecode_trunc(io)<=i) {
               yo = yo+k;
               maptool_waypoint(*img, io*XStep+8.0f, yo+8.0f, 1.2f,
                (int32_t)(r/2UL), (int32_t)(g/2UL), (int32_t)(b/2UL));
               io = io+dx;
            }
         }
         yo = v[i];
         io = (float)(i+1UL);
      }
      ++i;
   } while (i<=v_len-1);
   X2C_PFREE(v);
} /* end dots() */


extern void aprstat_wxgraph(maptool_pIMAGE * img, aprsdecode_pOPHIST op,
                uint32_t stime, uint16_t * what,
                struct aprstat_LASTVAL * lastval)
{
   aprsdecode_pFRAMEHIST fr;
   uint32_t Maxx;
   uint32_t step;
   uint32_t xt;
   uint32_t xi;
   float XStep;
   float yax1;
   float yax0;
   float vh;
   struct WX min0;
   struct WX max0;
   char hh[256];
   char h[256];
   char s[256];
   struct aprsdecode_DAT dat;
   float temp[1440];
   float hyg[1440];
   float baro[1440];
   float winds[1440];
   float windd[1440];
   float gust[1440];
   float rain1[1440];
   float rain24[1440];
   float rain0[1440];
   float lumi[1440];
   uint16_t have;
   char dirvalid;
   struct WX * anonym;
   if (op==0 || op->frames==0) {
      /*OR (op^.lastinftyp<100)*/
      return;
   }
   Maxx = dynmaxx(8UL, 320UL, 720UL);
   XStep = X2C_DIVR((float)Maxx,1440.0f);
   *img = 0;
   for (xi = 0UL; xi<=1439UL; xi++) {
      temp[xi] = (-1.E+4f);
      hyg[xi] = (-1.E+4f);
      baro[xi] = (-1.E+4f);
      winds[xi] = (-1.E+4f);
      windd[xi] = (-1.E+4f);
      gust[xi] = (-1.E+4f);
      rain1[xi] = (-1.E+4f);
      rain24[xi] = (-1.E+4f);
      rain0[xi] = (-1.E+4f);
      lumi[xi] = (-1.E+4f);
   } /* end for */
   { /* with */
      struct WX * anonym = &max0;
      anonym->temp = (-1.E+4f);
      anonym->hyg = (-1.E+4f);
      anonym->baro = (-1.E+4f);
      anonym->wind = (-1.E+4f);
      anonym->rain = (-1.E+4f);
      anonym->lumi = (-1.E+4f);
      anonym->siev = (-1.E+4f);
   }
   dirvalid = 0;
   min0.temp = X2C_max_real;
   min0.baro = X2C_max_real;
   memset((char *)lastval,(char)0,sizeof(struct aprstat_LASTVAL));
   fr = op->frames;
   do {
      if (((fr->time0>stime-86400UL && fr->time0<=stime)
                && aprsdecode_Decode(fr->vardat->raw, 500ul,
                &dat)>=0L) && dat.sym=='_') {
         xt = aprsdecode_trunc((float)(fr->time0-(stime-86400UL))
                *1.6666666666667E-2f);
         if (xt>=1440UL) xt = 1439UL;
         vh = X2C_DIVR(dat.wx.temp-32.0f,1.8f);
         if (vh>=(-99.0f) && vh<=99.0f) {
            temp[xt] = vh;
            if (vh>max0.temp) max0.temp = vh;
            if (vh<min0.temp) min0.temp = vh;
            lastval->temp = vh;
         }
         if (dat.wx.hygro>=0.0f && dat.wx.hygro<=100.0f) {
            hyg[xt] = dat.wx.hygro;
            if (dat.wx.hygro>max0.hyg) max0.hyg = dat.wx.hygro;
            lastval->hyg = dat.wx.hygro;
         }
         vh = dat.wx.baro*0.1f;
         if (vh>=900.0f && vh<=1100.0f) {
            baro[xt] = vh;
            if (vh>max0.baro) max0.baro = vh;
            if (vh<min0.baro) min0.baro = vh;
            lastval->baro = vh;
         }
         vh = dat.wx.rain24*0.254f;
         if (vh>=0.0f && vh<300.0f) {
            rain24[xt] = vh;
            if (vh>max0.rain) max0.rain = vh;
            lastval->rain24 = vh;
         }
         vh = dat.wx.raintoday*0.254f;
         if (vh>=0.0f && vh<300.0f) {
            rain0[xt] = vh;
            if (vh>max0.rain) max0.rain = vh;
         }
         vh = dat.wx.rain1*0.254f;
         if (vh>=0.0f && vh<300.0f) {
            rain1[xt] = vh;
            if (vh>max0.rain) max0.rain = vh;
            lastval->rain = vh;
         }
         if (dat.wx.lum>=0.0f && dat.wx.lum<=2000.0f) {
            lumi[xt] = dat.wx.lum;
            if (dat.wx.lum>max0.lumi) max0.lumi = dat.wx.lum;
            lastval->lumi = dat.wx.lum;
         }
         if (dat.wx.sievert>=0.0f && dat.wx.sievert<1000.0f) {
            /*        siev[xt]:=dat.wx.sievert; */
            if (dat.wx.sievert>max0.siev) max0.siev = dat.wx.sievert;
            lastval->siev = dat.wx.sievert;
         }
         if (dat.course>0UL && dat.course<=360UL) {
            lastval->winddir = (float)(dat.course%360UL);
            windd[xt] = lastval->winddir;
            dirvalid = 1;
         }
         vh = (float)dat.speed*1.609f;
         if (vh>=0.0f && vh<=1000.0f) {
            winds[xt] = vh;
            lastval->winds = vh;
            if (vh>max0.wind) max0.wind = vh;
         }
         vh = dat.wx.gust*1.609f;
         if (vh>=0.0f && vh<=1000.0f) {
            gust[xt] = vh;
            lastval->gust = vh;
            if (vh>max0.wind) max0.wind = vh;
         }
      }
      fr = fr->next;
   } while (fr);
   aprstext_DateLocToStr(stime, h, 256ul);
   aprsstr_Append(h, 256ul, " ", 2ul);
   aprsstr_Append(h, 256ul, op->call, 9ul);
   have = 0U;
   if (max0.temp!=(-1.E+4f)) {
      have |= 0x1U;
      if ((0x1U & *what)) {
         if (!newimg(Maxx, img)) return;
         scale(temp, 1440ul, min0.temp, max0.temp, 120.0f, 10.0f, &yax0,
                &yax1, &step);
         aprsstr_FixToStr(lastval->temp, 2UL, s, 256ul);
         aprsstr_Append(s, 256ul, "\177C ", 4ul);
         aprsstr_Append(s, 256ul, h, 256ul);
         paper(img, yax0, yax1, step, 8UL, Maxx, 120UL, s, 256ul);
         timeline(stime, img, Maxx);
         dots(XStep, img, temp, 1440ul, 1, 200UL, 700UL, 40UL);
      }
   }
   if (max0.baro!=(-1.E+4f)) {
      have |= 0x2U;
      if ((0x2U & *what)) {
         if (!newimg(Maxx, img)) return;
         scale(baro, 1440ul, min0.baro, max0.baro, 120.0f, 2.0f, &yax0,
                &yax1, &step);
         aprsstr_FixToStr(lastval->baro, 2UL, s, 256ul);
         aprsstr_Append(s, 256ul, "hPa ", 5ul);
         aprsstr_Append(s, 256ul, h, 256ul);
         paper(img, yax0, yax1, step, 8UL, Maxx, 120UL, s, 256ul);
         timeline(stime, img, Maxx);
         dots(XStep, img, baro, 1440ul, 1, 500UL, 400UL, 500UL);
      }
   }
   if (max0.wind!=(-1.E+4f) && max0.wind>0.0f) {
      have |= 0x8U;
      if ((0x8U & *what)) {
         if (!newimg(Maxx, img)) return;
         scale(winds, 1440ul, (-1.E+4f), max0.wind, 120.0f, 20.0f, &yax0,
                &yax1, &step);
         scale(gust, 1440ul, (-1.E+4f), max0.wind, 120.0f, 20.0f, &yax0,
                &yax1, &step);
         s[0U] = 0;
         if (lastval->winds!=0.0f || lastval->gust==0.0f) {
            aprsstr_FixToStr(lastval->winds, 2UL, hh, 256ul);
            aprsstr_Append(hh, 256ul, "km/h Wind  ", 12ul);
            aprsstr_Append(s, 256ul, hh, 256ul);
         }
         if (lastval->gust!=0.0f) {
            aprsstr_FixToStr(lastval->gust, 2UL, hh, 256ul);
            aprsstr_Append(hh, 256ul, "km/h Gust  ", 12ul);
            aprsstr_Append(s, 256ul, hh, 256ul);
         }
         aprsstr_Append(s, 256ul, h, 256ul);
         paper(img, yax0, yax1, step, 8UL, Maxx, 120UL, s, 256ul);
         timeline(stime, img, Maxx);
         dots(XStep, img, winds, 1440ul, 1, 100UL, 500UL, 700UL);
         dots(XStep, img, gust, 1440ul, 1, 600UL, 100UL, 0UL);
      }
      if (dirvalid) {
         have |= 0x10U;
         if ((0x10U & *what)) {
            if (!newimg(Maxx, img)) return;
            scale(windd, 1440ul, (-1.E+4f), 360.0f, 120.0f, 365.0f, &yax0,
                &yax1, &step);
            aprsstr_FixToStr(lastval->winddir, 0UL, s, 256ul);
            aprsstr_Append(s, 256ul, "deg Wind Direction ", 20ul);
            aprsstr_Append(s, 256ul, h, 256ul);
            paper(img, yax0, yax1, 90UL, 8UL, Maxx, 120UL, s, 256ul);
            timeline(stime, img, Maxx);
            dots(XStep, img, windd, 1440ul, 0, 200UL, 700UL, 700UL);
         }
      }
   }
   if (max0.hyg!=(-1.E+4f)) {
      have |= 0x4U;
      if ((0x4U & *what)) {
         if (!newimg(Maxx, img)) return;
         scale(hyg, 1440ul, (-1.E+4f), 100.0f, 120.0f, 101.0f, &yax0, &yax1,
                &step);
         aprsstr_FixToStr(lastval->hyg, 0UL, s, 256ul);
         aprsstr_Append(s, 256ul, "% Humidty ", 11ul);
         aprsstr_Append(s, 256ul, h, 256ul);
         paper(img, yax0, yax1, step, 8UL, Maxx, 120UL, s, 256ul);
         timeline(stime, img, Maxx);
         dots(XStep, img, hyg, 1440ul, 1, 0UL, 500UL, 700UL);
      }
   }
   if (max0.lumi!=(-1.E+4f)) {
      have |= 0x40U;
      if ((0x40U & *what)) {
         if (!newimg(Maxx, img)) return;
         scale(lumi, 1440ul, (-1.E+4f), max0.lumi, 120.0f, 50.0f, &yax0,
                &yax1, &step);
         aprsstr_FixToStr(lastval->lumi, 0UL, s, 256ul);
         aprsstr_Append(s, 256ul, "W/m^2 Luminosity ", 18ul);
         aprsstr_Append(s, 256ul, h, 256ul);
         paper(img, yax0, yax1, step, 8UL, Maxx, 120UL, s, 256ul);
         timeline(stime, img, Maxx);
         dots(XStep, img, lumi, 1440ul, 1, 600UL, 600UL, 0UL);
      }
   }
   if (max0.rain!=(-1.E+4f)) {
      have |= 0x20U;
      if ((0x20U & *what)) {
         if (!newimg(Maxx, img)) return;
         scale(rain1, 1440ul, (-1.E+4f), max0.rain, 120.0f, 5.0f, &yax0,
                &yax1, &step);
         scale(rain24, 1440ul, (-1.E+4f), max0.rain, 120.0f, 5.0f, &yax0,
                &yax1, &step);
         scale(rain0, 1440ul, (-1.E+4f), max0.rain, 120.0f, 5.0f, &yax0,
                &yax1, &step);
         aprsstr_FixToStr(lastval->rain, 2UL, s, 256ul);
         aprsstr_Append(s, 256ul, "mm Rain ", 9ul);
         aprsstr_Append(s, 256ul, h, 256ul);
         paper(img, yax0, yax1, step, 8UL, Maxx, 120UL, s, 256ul);
         timeline(stime, img, Maxx);
         dots(XStep, img, rain1, 1440ul, 1, 500UL, 100UL, 0UL);
         dots(XStep, img, rain24, 1440ul, 1, 50UL, 600UL, 50UL);
         dots(XStep, img, rain0, 1440ul, 1, 100UL, 100UL, 700UL);
      }
   }
   if (max0.siev>0.0f) have |= 0x400U;
   *what = have;
/*
  IF img<>NIL THEN DISPOSE(img) END;
*/
} /* end wxgraph() */


extern void aprstat_BEGIN(void)
{
   static int aprstat_init = 0;
   if (aprstat_init) return;
   aprstat_init = 1;
   aprstext_BEGIN();
   useri_BEGIN();
   aprspos_BEGIN();
   osi_BEGIN();
   aprsdecode_BEGIN();
   aprsstr_BEGIN();
   maptool_BEGIN();
}

