/*32bit is integer ?!?!!. Messy code - BIG TIME!*/

SAVEDS ULONG mDraw(struct IClass *cl,Object *obj,struct MUIP_Draw *msg)
{
    struct WaveData *data = INST_DATA(cl,obj);

    /* First draw super class */
    DoSuperMethodA(cl,obj,(VOID *)msg);

    /*make sure range values are allowed*/
    if (data->start < 0) data->start = 0;
    if (data->start > data->length) data->start = data->length;
    if (data->end < 0) data->end = 0;
    if (data->end > data->length) data->end = data->length;
    data->x[0] = 0;
    ;data->x[data->used -1] = 65535;

    if ((msg->flags & MADF_DRAWOBJECT) || (msg->flags & MADF_DRAWUPDATE))
    {

        if ( (data->draw & WDM_RANGE) && (data->quickdraw != QDM_ENVPNT) && (msg->flags & MADF_DRAWUPDATE))
        {
            DrawOldRange(cl,obj);
        }

        if ( (data->draw & WDM_VFILL) && (data->quickdraw == QDM_WAVE))
        {
            DrawWave(cl,obj);
        }

        if ( (data->draw & WDM_ENVBLOCKS) || (data->draw & WDM_ENVLINES) && (data->quickdraw == QDM_ENVPNT))
        {
            DrawEnvPnt(cl,obj);
        }

        if(!data->quickdraw)
        {
            if (data->draw & WDM_HGRID)
            {
                ULONG height = _mheight(obj);
                SetAPen(_rp(obj),_dri(obj)->dri_Pens[SHINEPEN]);
                Move(_rp(obj), _mleft(obj), _mtop(obj) + height / 4);
                Draw(_rp(obj), _mright(obj), _mtop(obj) + height / 4);
                Move(_rp(obj), _mleft(obj), _mtop(obj) + height * 2 / 4);
                Draw(_rp(obj), _mright(obj), _mtop(obj) + height * 2 / 4);
                Move(_rp(obj), _mleft(obj), _mtop(obj) + height * 3 / 4);
                Draw(_rp(obj), _mright(obj), _mtop(obj) + height * 3 / 4);
            }

            if ((data->draw & WDM_VGRID) && data->vlinegap)
            {
                SetAPen(_rp(obj),_dri(obj)->dri_Pens[SHINEPEN]);

                if (data->length)
                {
                    ULONG first = data->vlinegap - data->shown % data->vlinegap;
                    for(ULONG n = first; n < data->visible; n += data->vlinegap)
                    {
                        Move(_rp(obj), n * _mwidth(obj) / data->visible + _mleft(obj), _mtop(obj));
                        Draw(_rp(obj), n * _mwidth(obj) / data->visible + _mleft(obj), _mbottom(obj));
                    }
                }

                if(data->editmode == EM_ENV)
                {
                    for(ULONG n = 0; n < data->vlinegap; n++)
                    {
                        Move(_rp(obj), n * _mwidth(obj) / data->vlinegap + _mleft(obj), _mtop(obj));
                        Draw(_rp(obj), n * _mwidth(obj) / data->vlinegap + _mleft(obj), _mbottom(obj));
                    }
                }

            }

            if (data->draw & WDM_VFILL)
            {
                DrawWave(cl,obj);
            }

            if ( (data->draw & WDM_ENVBLOCKS) || (data->draw & WDM_ENVLINES) && (data->quickdraw == QDM_ENVPNT))
            {
                DrawEnv(cl,obj);
            }
        }

        if ( (data->draw & WDM_RANGE) && (data->quickdraw != QDM_ENVPNT))
        {
            DrawNewRange(cl,obj);
        }
    }

    return(0);
}

void DrawWave(struct IClass *cl,Object *obj)
{
    struct WaveData *data = INST_DATA(cl,obj);
    ULONG height = _mheight(obj) / 2, x, y;
    UBYTE chan = 0;

    SetAPen(_rp(obj),_dri(obj)->dri_Pens[TEXTPEN]);

    if (data->length)
    {
        if (data->type & STYPE_S8) height /= 2;
        for (UBYTE n = 0; n <= chan; n++)
        {
        Move(_rp(obj), _mleft(obj), FindPnt(cl, obj, _mleft(obj)*8, chan));

        if((data->draw & 7) == WDM_PIXEL2)
        {
            for (x = 0; x < _mwidth(obj)*4; x++)
            {
                y = FindPnt(cl, obj, x*2, chan);
                WritePixel(_rp(obj), _mleft(obj) + x / 4, y);
            }
        }

        if((data->draw & 7) == WDM_PIXEL3)
        {
            for (x = 0; x < _mwidth(obj)*8; x++)
            {
                y = FindPnt(cl, obj, x, chan);
                WritePixel(_rp(obj), _mleft(obj) + x / 8, y);
            }
        }

        if((data->draw & 7) == WDM_PIXELALL)
        {
            for (x = 0; x < data->visible; x++)
            {
                y = FindSamp(cl, obj, x, chan);
                /*wave = (data->waveform + data->shown + x);
                y = *wave * height / 128 + height + _mtop(obj);*/
                WritePixel(_rp(obj), _mleft(obj) + x * _mwidth(obj) / data->visible, y);
            }
        }

        for (x = 0; x < _mwidth(obj); x++)
        {
            y = FindPnt(cl, obj, x*8, chan);
            if ((data->draw & 7) == WDM_LINE) Draw(_rp(obj), _mleft(obj) + x, y);
            if ((data->draw & 7) == WDM_PIXEL1) WritePixel(_rp(obj), _mleft(obj) + x, y);
            if ((data->draw & 7) == WDM_VFILLHALF) {Move(_rp(obj), _mleft(obj) + x, height + _mtop(obj));Draw(_rp(obj), _mleft(obj) + x, y);}
            if ((data->draw & 7) == WDM_VFILL) {Move(_rp(obj), _mleft(obj) + x, height*2 + _mtop(obj)*2 - y -1);Draw(_rp(obj), _mleft(obj) + x, y);}
        }
            if (data->type & 2)
            {
                chan = 1;
                height *= 3;
            }
        }
    }
}

void DrawEnv(struct IClass *cl,Object *obj)
{
    struct WaveData *data = INST_DATA(cl,obj);
    ULONG n;
    if (data->used < 2) return();

    SetAPen(_rp(obj),_dri(obj)->dri_Pens[TEXTPEN]);
    if(data->draw & WDM_ENVLINES)
    {
        Move(_rp(obj), _mleft(obj) +1, _mbottom(obj) -1 - data->lev[0] * (_mheight(obj) -3) / 65535);
        for (n = 0; n < data->used-1; n++)
        {
            Draw(_rp(obj), _mleft(obj) +1 + data->x[n] * (_mwidth(obj) -3) / 65535, _mbottom(obj) -1 - data->lev[n] * (_mheight(obj) -3) / 65535);
        }
        Draw(_rp(obj), _mright(obj) -1, _mbottom(obj) -1 - data->lev[n] * (_mheight(obj) -3) / 65535);
    }

    if(data->draw & WDM_ENVBLOCKS)
    {
        ULONG x, y;
        for (n = 0; n < data->used-1; n++)
        {
            x = _mleft(obj) + data->x[n] * (_mwidth(obj) -3) / 65535;
            y = _mbottom(obj) -2 - data->lev[n] * (_mheight(obj) -3) / 65535;
            RectFill(_rp(obj), x , y , x + 2, y + 2);
        }
        x = _mright(obj) -2;
        y = _mbottom(obj) -2 - data->lev[n] * (_mheight(obj) -3) / 65535;
        RectFill(_rp(obj), x , y , x + 2, y + 2);

        SetAPen(_rp(obj),_dri(obj)->dri_Pens[SHINEPEN]);
        x = _mleft(obj) + data->x[data->current] * (_mwidth(obj) -3) / 65535;
        y = _mbottom(obj) -2 - data->lev[data->current] * (_mheight(obj) -3) / 65535;
        RectFill(_rp(obj), x , y , x + 2, y + 2);
        SetAPen(_rp(obj),_dri(obj)->dri_Pens[TEXTPEN]);
    }

}

void DrawEnvPnt(struct IClass *cl,Object *obj)
{
    struct WaveData *data = INST_DATA(cl,obj);
    SetAPen(_rp(obj),_dri(obj)->dri_Pens[TEXTPEN]);
    SetDrMd(_rp(obj),COMPLEMENT);
    ULONG x, y;

    x = _mleft(obj) + data->oldx * (_mwidth(obj) -3) / 65535;
    y = _mbottom(obj) -2 - data->oldlev * (_mheight(obj) -3) / 65535;

    if (data->current > 0) Move(_rp(obj), _mleft(obj) +1 + data->x[data->current -1] * (_mwidth(obj) -3) / 65535, _mbottom(obj) -1 - data->lev[data->current -1] * (_mheight(obj) -3) / 65535);
    else Move(_rp(obj), x +1, y +1);

    if (data->current > 0) Draw(_rp(obj), x +1, y +1);
    if (data->current < data->used -1) Draw(_rp(obj), _mleft(obj) +1 + data->x[data->current +1] * (_mwidth(obj) -3) / 65535, _mbottom(obj) -1 - data->lev[data->current +1] * (_mheight(obj) -3) / 65535);

    RectFill(_rp(obj), x , y , x + 2, y + 2);


    x = _mleft(obj) + data->x[data->current] * (_mwidth(obj) -3) / 65535;
    y = _mbottom(obj) -2 - data->lev[data->current] * (_mheight(obj) -3) / 65535;

    if (data->current > 0) Move(_rp(obj), _mleft(obj) +1 + data->x[data->current -1] * (_mwidth(obj) -3) / 65535, _mbottom(obj) -1 - data->lev[data->current -1] * (_mheight(obj) -3) / 65535);
    else Move(_rp(obj), x +1, y +1);

    if (data->current > 0) Draw(_rp(obj), x +1, y +1);
    if (data->current < data->used -1) Draw(_rp(obj), _mleft(obj) +1 + data->x[data->current +1] * (_mwidth(obj) -3) / 65535, _mbottom(obj) -1 - data->lev[data->current +1] * (_mheight(obj) -3) / 65535);

    RectFill(_rp(obj), x , y , x + 2, y + 2);

    SetDrMd(_rp(obj),JAM1);
    data->oldx = data->x[data->current];
    data->oldlev = data->lev[data->current];
}

VOID DrawOldRange(struct IClass *cl,Object *obj)
{
    struct WaveData *data = INST_DATA(cl,obj);

    SetAPen(_rp(obj),_dri(obj)->dri_Pens[TEXTPEN]);
    SetDrMd(_rp(obj),COMPLEMENT);
    LONG x1, x2;
    if (data->oldstart < data->oldend)
    {
        x1 = (data->oldstart - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
        x2 = (data->oldend - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
    }
    else
    {
        x2 = (data->oldstart - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
        x1 = (data->oldend - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
    }

    if(x1 < _mleft(obj)) x1 = _mleft(obj);
    if(x1 > _mright(obj)) x1 = _mright(obj);
    if(x2 < _mleft(obj)) x2 = _mleft(obj);
    if(x2 > _mright(obj)) x2 = _mright(obj);
    RectFill(_rp(obj), x1, _mtop(obj), x2, _mbottom(obj));

    /*data->oldstart = data->start;
    data->oldend = data->end;*/
    SetDrMd(_rp(obj),JAM1);
}

VOID DrawNewRange(struct IClass *cl,Object *obj)
{
    struct WaveData *data = INST_DATA(cl,obj);

    SetAPen(_rp(obj),_dri(obj)->dri_Pens[TEXTPEN]);
    SetDrMd(_rp(obj),COMPLEMENT);
    LONG x1, x2;
    if (data->start < data->end)
    {
        x1 = (data->start - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
        x2 = (data->end - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
    }
    else
    {
        x2 = (data->start - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
        x1 = (data->end - data->shown) * _mwidth(obj) / data->visible + _mleft(obj);
    }

    if(x1 < _mleft(obj)) x1 = _mleft(obj);
    if(x1 > _mright(obj)) x1 = _mright(obj);
    if(x2 < _mleft(obj)) x2 = _mleft(obj);
    if(x2 > _mright(obj)) x2 = _mright(obj);
    RectFill(_rp(obj), x1, _mtop(obj), x2, _mbottom(obj));

    data->oldstart = data->start;
    data->oldend = data->end;
    SetDrMd(_rp(obj),JAM1);
}


LONG FindPnt(struct IClass *cl, Object *obj, ULONG x, UBYTE chan)
{
    struct WaveData *data = INST_DATA(cl,obj);
    ULONG height = _mheight(obj)/2;
    LONG y;

    if (data->type == STYPE_M8)
    {
        BYTE *wave = (data->waveform + data->shown) + ((data->visible) * x /8 / _mwidth(obj));
        y = *wave * height / 128 + height + _mtop(obj);
    }
    if (data->type == STYPE_M16)
    {
        WORD *wave = (WORD *)(data->waveform + (data->shown *2)) + ((data->visible) * x /8 / _mwidth(obj));
        y = *wave * height / 32768 + height + _mtop(obj);
    }
    if (data->type == STYPE_M32)
    {
        WORD *wave = (WORD *)(data->waveform + (data->shown *4)) + ((data->visible) * x /4 / _mwidth(obj));
        wave /= (WORD *)4; wave *= (WORD *)4;
        y = *wave * height / 32768 + height + _mtop(obj);  /*2147483648*/
    }

    height /=2;

    if (data->type == STYPE_S8)
    {
        BYTE *wave = (data->waveform + (data->shown *2)) + ((data->visible) * x /4 /_mwidth(obj));
        wave /= (BYTE *)2; wave *= (BYTE *)2; wave += (BYTE *)chan;
        y = *wave * height / 128 + height + _mtop(obj) + height*chan*2;
    }
    if (data->type == STYPE_S16)
    {
        WORD *wave = (WORD *)(data->waveform + (data->shown *4)) + ((data->visible) * x /4 / _mwidth(obj));
        wave /= (WORD *)4; wave *= (WORD *)4; wave += (WORD *)(chan*2);
        y = *wave * height / 32768 + height + _mtop(obj)+ height*chan*2;
    }
    if (data->type == STYPE_S32)
    {
        WORD *wave = (WORD *)(data->waveform + (data->shown *8)) + ((data->visible) * x /2 / _mwidth(obj));
        wave /= (WORD *)8; wave *= (WORD *)8; wave += (WORD *)(chan*4);
        y = *wave * height / 32768 + height + _mtop(obj)+ height*chan*2;
    }
    return(y);
}


ULONG FindSamp(struct IClass *cl, Object *obj, ULONG sam, UBYTE chan)
{
    struct WaveData *data = INST_DATA(cl,obj);
    ULONG height = _mheight(obj)/2, y;

    if (data->type == STYPE_M8)
    {
        BYTE *wave = data->waveform + data->shown + sam;
        y = *wave * height / 128 + height + _mtop(obj);
    }
    if (data->type == STYPE_M16)
    {
        WORD *wave = (WORD *)data->waveform + data->shown + sam;
        y = *wave * height / 32768 + height + _mtop(obj);
    }
    if (data->type == STYPE_M32)
    {
        WORD *wave = (WORD *)data->waveform + data->shown *2 + sam *2;
        wave /= (WORD *)2; wave *= (WORD *)2;
        y = *wave * height / 32768 + height + _mtop(obj);
    }

    height /=2;

    if (data->type == STYPE_S8)
    {
        BYTE *wave = data->waveform + data->shown *2+ sam *2;
        wave /= (BYTE *)2; wave *= (BYTE *)2; wave += (BYTE *)chan;
        y = *wave * height / 128 + height + _mtop(obj) + height*chan*2;
    }
    if (data->type == STYPE_S16)
    {
        WORD *wave = (WORD *)data->waveform + data->shown *2 + sam *2;
        wave /= (WORD *)4; wave *= (WORD *)4; wave += (WORD *)(chan*2);
        y = *wave * height / 32768 + height + _mtop(obj)+ height*chan*2;
    }
    if (data->type == STYPE_S32)
    {
        WORD *wave = (WORD *)data->waveform + data->shown *4 + sam *4;
        wave /= (WORD *)8; wave *= (WORD *)8; wave += (WORD *)(chan*4);
        y = *wave * height / 32768 + height + _mtop(obj)+ height*chan*2;
    }
    return(y);
}


