/*
**  MemMinister is copyright by Marcus Ohlström 1994-1995. All rights reserved
*/

#include "memminister.h"

IMPORT UBYTE *ver ;

LONG __oslibversion = 36 ;

void __regargs __chkabort(void);
void __regargs __chkabort(void){}  /* Oskadliggör hanteringen av CTRL-C */

struct TextAttr textattr ;  /* initieras av layoutAll() */

UWORD snap_borData[2][6] ;  /*  kommer enligt ANSI-standard 0-initialiseras  */
UWORD flush_borData[2][6] ; /*  kommer enligt ANSI-standard 0-initialiseras  */

struct Border snap_bor[] = 
{
    { 0, 0, 2, 0, JAM1, 3, snap_borData[0], &snap_bor[1] },
    { 0, 0, 1, 0, JAM1, 3, snap_borData[1], NULL }
} ;

struct Border flush_bor[] = 
{
    { 0, 0, 2, 0, JAM1, 3, flush_borData[0], &flush_bor[1] },
    { 0, 0, 1, 0, JAM1, 3, flush_borData[1], NULL }
} ;

struct IntuiText snap_gadText[] = 
{
    { 1, 0, JAM2, 10, 2, &textattr, "Free",     &snap_gadText[1] },
    { 1, 0, JAM2, 45, 2, &textattr, "Snapped",  &snap_gadText[2] },
    { 1, 0, JAM2, 90, 2, &textattr, "Used",     NULL },
} ;

struct IntuiText flush_gadText =
    { 1, 0, JAM2, 4,  2, &textattr, "Flush",    NULL } ;

struct Gadget snap_gad =  { NULL,     54, 12, 100, 12, GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_BOOLGADGET,  &snap_bor, NULL,   snap_gadText, NULL, NULL,  SNAP_GAD, NULL } ;
struct Gadget flush_gad = { &snap_gad, 4, 12,  28, 12, GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_BOOLGADGET, &flush_bor, NULL, &flush_gadText, NULL, NULL, FLUSH_GAD, NULL } ;

struct Image image ; /*  kommer enligt ANSI-standard 0-initialiseras  */

ULONG chip_snapped, fast_snapped, old_chip_free, old_fast_free ;

/*  nedanstående initieras i layouotAll()  */
ULONG chip_XPos, fast_XPos, total_XPos ;
ULONG chip_YPos, fast_YPos, total_YPos ;
ULONG text_RightX, free_RightX, snapped_RightX, used_RightX ;
LONG number_length ;

UBYTE *chip_text = "Chip" , *fast_text = "Fast", *total_text = "Total" ;

UBYTE str[11] ; /* <-  11 istället för STRLEN gör att fönstret ser        */
                /* konstigt ut om STRLEN är för litet, men programmet     */
                /* krashar inte!! (Vilket det gör om det står STRLEN här) */

struct IntuiText iText = { 1, 0, JAM2, 0, 0, &textattr, str, NULL } ;

struct Window *win ;
struct Screen *scr ;

/*  värden som kan förändras mha tooltypes  */
WORD zoomsize[4] ; /*  kommer enligt ANSI-standard 0-initialiseras  */
LONG big_Left = 0, big_Top = 0, big_Width, big_Height ;
STRPTR winTitle = "MemMinister 1.2" ;
STRPTR fTitle   = "Total: %t" ;
UBYTE *dPoint = "." ;
LONG delaytime = DELAYTIME ;
BOOL started_zoomed = FALSE, windowToBack = FALSE, savePosition = FALSE ;

VOID main( int argc, char **argv )
{
    struct Gadget *gad ;
    struct DiskObject *dobj = NULL ;
    STRPTR progName = (FROMWB ? ((struct WBStartup *)argv)->sm_ArgList->wa_Name : argv[0]) ;
    struct TextFont *userfont = NULL ;
    struct IntuiMessage *iMsg ;
    ULONG chip_free, fast_free, class ;
    UBYTE buf[200] ;
    BOOL done = FALSE ;
    
    if( FROMWB || (argc > 1 && *argv[1] == '-') )
        if( dobj = GetDiskObject(progName) )
            userfont = setOptions( dobj ) ;
    
    if( scr = LockPubScreen( NULL ) )
    {
        /* layoutAll() initierar bla textattr => använd EJ textattr innan */
        userfont = layoutAll( userfont ) ;
        if( started_zoomed )
        {
            SWAP( big_Left,   zoomsize[0] ) ;
            SWAP( big_Top,    zoomsize[1] ) ;   /*  ingen snygg lösning,   */
            SWAP( big_Width,  zoomsize[2] ) ;   /*  men enkel...           */
            SWAP( big_Height, zoomsize[3] ) ;
        }
        if( win = OpenWindowTags( NULL,
            WA_Left,            big_Left,
            WA_Top,             big_Top,
            WA_Width,           big_Width,
            WA_Height,          big_Height,
            WA_Title,           winTitle,
            WA_ScreenTitle,     "MemMinister 1.2  ©1994-1995 Marcus Ohlström",
            WA_Gadgets,         &flush_gad,
            WA_Zoom,            zoomsize,
            WA_AutoAdjust,      TRUE,
            WA_Flags,           WFLG_CLOSEGADGET | WFLG_DEPTHGADGET | WFLG_DRAGBAR,
            WA_IDCMP,           IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_NEWSIZE,
            TAG_END ) )
        {
            if( windowToBack )
                WindowToBack( win ) ;
            SetFont( win->RPort, userfont ) ; /* krävs, annars -> BUGG! */
            writeInit() ; /* <= behövs egentligen inte om vi zip-startats */
            writeSnapped( AvailMem(MEMF_CHIP), AvailMem(MEMF_FAST) ) ;
            while( !done )
            {
                if( !(win->Flags & WFLG_ZOOMED) ^ started_zoomed )
                    writeFree( AvailMem(MEMF_CHIP), AvailMem(MEMF_FAST) ) ;
                else {
                    chip_free  = AvailMem(MEMF_CHIP) ;
                    fast_free  = AvailMem(MEMF_FAST) ;
                    if(old_chip_free!=chip_free || old_fast_free!=fast_free)
                    {
                        formatTitle( fTitle, buf, chip_free, fast_free ) ;
                        SetWindowTitles( win, buf, (UBYTE *)~0 ) ;
                        old_chip_free  = chip_free  ;
                        old_fast_free  = fast_free  ;
                    }
                }
                Delay( delaytime ) ;
                
                /*   denna sats bör ligga här nedan för att programmet  */
                /*   inte ska vänta ytterligare delaytime*1/50 sec      */
                /*   efter IDCMP-meddelanden                            */
                while( iMsg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
                {
                    class = iMsg->Class ;
                    gad   = (struct Gadget *)iMsg->IAddress ;
                    /*  använd INTE gad om class != IDCMP_GADGETUP  */
                    ReplyMsg( (struct Message *)iMsg ) ;

                    switch( class )
                    {
                        case IDCMP_GADGETUP:
                                switch( gad->GadgetID )
                                {
                                    case FLUSH_GAD:
                                        AllocMem( 0, 0 ) ;
                                        break;
                                    case SNAP_GAD:
                                        writeSnapped( AvailMem(MEMF_CHIP), AvailMem(MEMF_FAST) ) ;
                                        writeUsed( 0, 0 ) ;
                                }
                                break ;
                        case IDCMP_NEWSIZE:
                                if( !(win->Flags & WFLG_ZOOMED) ^ started_zoomed )
                                {
                                    SetWindowTitles( win, winTitle, (UBYTE *)~0 ) ;
                                    writeInit() ;
                                    writeSnapped( chip_snapped, fast_snapped ) ;
                                }
                                old_chip_free = old_fast_free = 0 ;
                                /* ^^ för att alla siffror ska uppdateras */
                                break;
                        case IDCMP_CLOSEWINDOW:
                                done = TRUE ;
                                if(dobj && savePosition)
                                    putToolTypes( dobj, progName, (!(win->Flags & WFLG_ZOOMED) ^ started_zoomed )) ;
                    }
                }
            }
            CloseWindow( win ) ;
        }
        UnlockPubScreen( NULL, scr ) ;
    }
    
    if( dobj )
        FreeDiskObject( dobj ) ;
    
    if( userfont )
        CloseFont( userfont ) ;
}

struct TextFont *setOptions( struct DiskObject *dobj )
{
    struct TextFont *userfont = NULL ;
    char **toolarray ;
    UBYTE *str ;
    LONG tmp ;
    
    toolarray = (char **)dobj->do_ToolTypes ;
    
    if( str = FindToolType(toolarray, "LEFT") )
        StrToLong( str, &big_Left ) ;
    
    if( str = FindToolType(toolarray, "TOP") )
        StrToLong( str, &big_Top ) ;
    
    if( str = FindToolType(toolarray, "ZIPLEFT") )
    {
        StrToLong( str, &tmp ) ;
        zoomsize[0] = (WORD)tmp ;
    }
    
    if( str = FindToolType(toolarray, "ZIPTOP") )
    {
        StrToLong( str, &tmp ) ;
        zoomsize[1] = (WORD)tmp ;
    }
    
    if( str = FindToolType(toolarray, "ZIPWIDTH") )
    {
        StrToLong( str, &tmp ) ;
        zoomsize[2] = (WORD)tmp ;
    }
    
    if( textattr.ta_Name = FindToolType(toolarray, "FONTNAME") )
    {
        if( str = FindToolType(toolarray, "FONTSIZE") )
        {
            StrToLong( str, &tmp ) ;
            if( (textattr.ta_YSize = (UWORD)tmp) > 0 )
                userfont = OpenDiskFont( &textattr ) ;
        }
    }
    
    if( str = FindToolType(toolarray, "TITLEFORMAT") )
        fTitle = str ;
    
    if( (str = FindToolType(toolarray, "DECIMALPOINT")) && *str != NULL )
        dPoint = str ;
    
    if( str = FindToolType(toolarray, "DELAYTIME") )
        StrToLong( str, &delaytime ) ;
    
    if( FindToolType(toolarray, "ZIPPED") )
        started_zoomed = TRUE ;
    
    if( FindToolType(toolarray, "WINDOWTOBACK") )
        windowToBack = TRUE ;
    
    if( FindToolType(toolarray, "SAVEPOSITION") )
        savePosition = TRUE ;
    
    return( userfont ) ;
}

struct TextFont *layoutAll( struct TextFont *userTFont )
{
    LONG chip_length, fast_length, total_length, max_length, flush_length ;
    struct TextFont *scrTFont = scr->RastPort.Font ;
    
    if( !userTFont )
    {
        userTFont = scrTFont ;
        
        /* om userTFont != NULL är dessa fält redan satta (i setOptions()) */
        textattr.ta_Name  = userTFont->tf_Message.mn_Node.ln_Name ;
        textattr.ta_YSize = userTFont->tf_YSize ;
    }
    
    number_length = digit_maxlength( userTFont ) ;
    
    if( zoomsize[2] < 65 )   /* giltigt värde i tooltypes? */
        zoomsize[2] = 200 ;  /* nej! (200 ser bäst ut på topaz8-skärm) */
        
    zoomsize[3] = 3 + scrTFont->tf_YSize ;
    
    iText.IText = chip_text ;   chip_length  = IntuiTextLength( &iText ) ;
    iText.IText = fast_text ;   fast_length  = IntuiTextLength( &iText ) ;
    iText.IText = total_text ;  total_length = IntuiTextLength( &iText ) ;
                                flush_length = IntuiTextLength( &flush_gadText ) ;
    
    max_length = MAX( MAX(chip_length, fast_length), MAX(total_length, flush_length) ) ;
    
    big_Height = scr->WBorBottom + userTFont->tf_YSize +
        (total_YPos = userTFont->tf_YSize +
        (fast_YPos = userTFont->tf_YSize +
        (chip_YPos = scr->WBorTop + 1 + userTFont->tf_YSize + scrTFont->tf_YSize + 3 + 1))) ;
    
    big_Width = scr->WBorRight + 4 +
        (used_RightX = number_length +
        (snapped_RightX = number_length +
        (free_RightX = number_length +
        (text_RightX = scr->WBorLeft + 2 + max_length)))) ;
    
    flush_gad.LeftEdge = scr->WBorLeft ;
    flush_gad.TopEdge  = scrTFont->tf_YSize + 3 ;
    flush_gad.Width    = 2 + max_length + 5 ;
    flush_gad.Height   = userTFont->tf_YSize + 3 ;
    
    snap_gad.LeftEdge = scr->WBorLeft + flush_gad.Width ;
    snap_gad.TopEdge  = flush_gad.TopEdge ;
    snap_gad.Width    = big_Width - flush_gad.Width - scr->WBorLeft - scr->WBorRight ;
    snap_gad.Height   = flush_gad.Height ;
    
    buildBoolBorder( &flush_gad ) ;
    buildBoolBorder(  &snap_gad ) ;
    
    snap_gadText[0].LeftEdge = text_RightX    - flush_gad.Width + (number_length - IntuiTextLength(&snap_gadText[0]))/2 ;
    snap_gadText[1].LeftEdge = free_RightX    - flush_gad.Width + (number_length - IntuiTextLength(&snap_gadText[1]))/2 ;
    snap_gadText[2].LeftEdge = snapped_RightX - flush_gad.Width + (number_length - IntuiTextLength(&snap_gadText[2]))/2 ;
    
    image.Height = userTFont->tf_YSize ;
    
    chip_XPos  = text_RightX - chip_length  ;
    fast_XPos  = text_RightX - fast_length  ;
    total_XPos = text_RightX - total_length ;
    
    return( userTFont ) ;
}

VOID writeInit( VOID )
{
    struct DrawInfo *di = GetScreenDrawInfo( win->WScreen ) ;
    
    iText.FrontPen = di ? di->dri_Pens[HIGHLIGHTTEXTPEN] : 2 ;
    
    iText.IText = chip_text ;
    PrintIText( win->RPort, &iText, chip_XPos, chip_YPos ) ;
    
    iText.IText = fast_text ;
    PrintIText( win->RPort, &iText, fast_XPos, fast_YPos ) ;
    
    iText.IText = total_text ;
    PrintIText( win->RPort, &iText, total_XPos, total_YPos ) ;
    
    iText.FrontPen = di ? di->dri_Pens[TEXTPEN] : 1 ;
    
    iText.IText = str ;
}

VOID writeFree( ULONG chip_free, ULONG fast_free )
{
    BOOL any_change = FALSE ;
    
    if( chip_free != old_chip_free )
    {
        myPrintINumber( chip_free, free_RightX, chip_YPos ) ;
        old_chip_free = chip_free ;
        any_change = TRUE ;
    }
    
    if( fast_free != old_fast_free )
    {
        myPrintINumber( fast_free, free_RightX, fast_YPos ) ;
        old_fast_free = fast_free ;
        any_change = TRUE ;
    }
    
    if( any_change )
    {
        myPrintINumber( chip_free + fast_free, free_RightX, total_YPos ) ;
        
        writeUsed( chip_snapped-chip_free, fast_snapped-fast_free ) ;
    }
}

VOID writeSnapped( ULONG chip_now, ULONG fast_now )
{
    myPrintINumber( chip_now, snapped_RightX, chip_YPos ) ;
    myPrintINumber( fast_now, snapped_RightX, fast_YPos ) ;
    myPrintINumber( chip_now + fast_now, snapped_RightX, total_YPos ) ;
    chip_snapped = chip_now ;
    fast_snapped = fast_now ;
}

VOID writeUsed( ULONG chip_used, ULONG fast_used )
{
    myPrintINumber( chip_used, used_RightX, chip_YPos ) ;
    myPrintINumber( fast_used, used_RightX, fast_YPos ) ;
    myPrintINumber( chip_used+fast_used, used_RightX, total_YPos ) ;
}

VOID myPrintINumber( ULONG number, ULONG XRight, ULONG Y )
{
    sprintf( iText.IText, "%ld", number ) ;
    PrintIText( win->RPort, &iText, XRight-IntuiTextLength(&iText), Y ) ;
    
    image.Width = number_length - IntuiTextLength(&iText) ;
    DrawImage( win->RPort, &image, XRight-number_length, Y ) ;
}

/*  gad->GadgetRender->XY MÅSTE vara MEMF_CLEARed WORD[12]  */
VOID buildBoolBorder( struct Gadget *gad )
{
    WORD *XY = ((struct Border *)gad->GadgetRender)->XY ;
    
    XY[1] = XY[9] = XY[11] = gad->Height - 1 ;
    XY[4] = XY[6] = XY[8] = gad->Width - 1 ;
    XY[10] = 1 ;
}

LONG digit_maxlength( struct TextFont *Font )
{
    ULONG LoChar ;
    LONG char_width = 0, tmp, count = 10 ;
    
    LoChar = Font->tf_LoChar ;
    
    if( FPF_PROPORTIONAL & Font->tf_Flags )
    {
        while( count-- )
        {
            tmp = ((WORD*)Font->tf_CharSpace)['0' - LoChar + count] + ((WORD*)Font->tf_CharKern )['0' - LoChar + count] ;
            char_width = MAX( char_width, tmp ) ;
        }
        tmp = ((WORD*)Font->tf_CharSpace)['-' - LoChar] + ((WORD*)Font->tf_CharKern )['-' - LoChar] ;
        tmp = MAX( char_width, tmp ) ;
    } else
        char_width = tmp = Font->tf_XSize ;
    
    return( char_width * (STRLEN-2) + tmp ) ; /* <- för att tänka på '-' */
}

VOID formatTitle( STRPTR str, STRPTR buf, ULONG chip_free, ULONG fast_free )
{
    ULONG tmp, mod ;
    BOOL doFormat = FALSE ;
    
    while( NULL != (*buf = *str) )
    {
        if( *str == '%' )
        {
            switch( *(++str) )
            {
                case 'c':
                case 'C':   tmp = chip_free ;
                            doFormat = TRUE ;
                            break ;
                case 'f':
                case 'F':   tmp = fast_free ;
                            doFormat = TRUE ;
                            break ;
                case 't':
                case 'T':   tmp = chip_free + fast_free ;
                            doFormat = TRUE ;
                            break ;
                default:    *buf = *str ;
            }
            if( doFormat )
            {
                switch( *(str+1) )
                {
                    case 'm':
                    case 'M':   tmp /= 1024 ;
                    case 'k':
                    case 'K':   mod = (((tmp % 1024) * 1000/1024) + 5) / 10 ;
                                          /* för att få avrundning ^^^ */
                                tmp /= 1024 ;
                                sprintf( buf, "%ld%s%02.ld", tmp, dPoint, mod ) ;
                                str++ ;
                                break ;
                    case 'b':
                    case 'B':   str++ ;
                    default:    sprintf( buf, "%ld", tmp ) ;
                }
                while( *(buf+1) != NULL ) buf++ ;
                doFormat = FALSE ;
            }
        }
        buf++ ;
        str++ ;
    }
}

VOID putToolTypes( struct DiskObject *dobj, STRPTR name, BOOL big_win )
{
    char **oldtt = dobj->do_ToolTypes ;
    char *newtt[32] ;
    UBYTE i ;
    UBYTE left_str[14], top_str[13] ;
    
    for( i = 0 ; oldtt[i] && i < 32 ; i++ )
        newtt[i] = oldtt[i] ;
    
    newtt[i] = NULL ;
    
    if( big_win )
    {
        sprintf( left_str, "LEFT=%ld", win->LeftEdge ) ;
        sprintf( top_str,  "TOP=%ld",  win->TopEdge  ) ;
        
        newtt[ findToolType(newtt,"(LEFT=" ,6) ] = left_str   ;
        newtt[ findToolType(newtt,"(TOP="  ,5) ] = top_str    ;
        newtt[ findToolType(newtt,"(ZIPPED",7) ] = "(ZIPPED)" ;
    } else {
        sprintf( left_str, "ZIPLEFT=%ld", win->LeftEdge ) ;
        sprintf( top_str,  "ZIPTOP=%ld",  win->TopEdge  ) ;
        
        newtt[ findToolType(newtt,"(ZIPLEFT=",9) ] = left_str ;
        newtt[ findToolType(newtt,"(ZIPTOP=" ,8) ] = top_str  ;
        newtt[ findToolType(newtt,"(ZIPPED"  ,7) ] = "ZIPPED" ;
    }
    
    dobj->do_ToolTypes = newtt ;
    PutDiskObject( name, dobj ) ;
    dobj->do_ToolTypes = oldtt ;
}

ULONG findToolType( char **tt, char *str, ULONG strlen )
{
    UBYTE i ;
    
    for( i = 0 ; tt[i] && i < 32 ; i++ )
    {
        if( !strnicmp( tt[i], str,   strlen   ) ) break ;
        if( !strnicmp( tt[i], str+1, strlen-1 ) ) break ;
    }
    
    if( i > 30 ) i = 30 ;
    if( tt[i] == NULL ) tt[i+1] = NULL ;
    
    return( i ) ;
}
