/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
 * display.c -
 *    CD play display functions.   
\*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/

#include   <stdlib.h>
#include   <stdio.h>
#include   <ncurses.h>
#include   <string.h>

#include   "color.h"
#include   "struct.h"
#include   "misc.h"
#include   "cdp.h"
#include   "display.h"
#include   "database.h"
#include   "getline.h"


/*=========================================================================
 * Static Debug Variables
\*=========================================================================*/
/* SOURCE__FILE; */


/*======================================================================
 * Static prototypes
\*======================================================================*/
static  void     refreshMessage( displayInfoType        * pInfo );


/*======================================================================
 * Static constants 
\*======================================================================*/
#define  PANEL_YSIZE          6
#define  PANEL_XSIZE          28
#define  PAD_STARTX           (COLS - PANEL_XSIZE)
#define  TOC_XSIZE            COLS
#define  TOC_YSIZE            ( LINES - 1 )
#define  INFO_LINE            6
#define  TOC_TOP_LINE         7
#define  WIDTH_TRK_NUM        3
#define  WIDTH_TRK_START      9
#define  WIDTH_TRK_LENGTH     7
#define  WIDTH_TRK_NAME       ( TOC_XSIZE - ( WIDTH_TRK_NUM + WIDTH_TRK_START+\
                                WIDTH_TRK_LENGTH ) - 7 )
#define  STARTX_TRK_NUM       1
#define  STARTX_TRK_START     ( STARTX_TRK_NUM + WIDTH_TRK_NUM + 1 )
#define  STARTX_TRK_LENGTH    ( STARTX_TRK_START + WIDTH_TRK_START + 1 )
#define  STARTX_TRK_NAME      ( STARTX_TRK_LENGTH + WIDTH_TRK_LENGTH + 1 )
#define  STARTX_CDNAME        19
#define  WIDTH_CDNAME         ( PAD_STARTX - STARTX_CDNAME )
#define  STARTX_ARTIST        19
#define  WIDTH_ARTIST         ( PAD_STARTX - STARTX_ARTIST )


/*=========================================================================
 * Start of Code
\*=========================================================================*/


/*--------------------------------------------------------------------------
 * output a string that can be made of two colors. ch is used to flip
 * between the two colors.
\*--------------------------------------------------------------------------*/
int   cursesSmartPrint( WINDOW    * pw,
		        int         y,
		        int         x,
		        char      * str, 
		        char        ch, 
		        chtype      regColor,
		        chtype      hiColor )
{
    char            buffer[ 200 ];
    char          * pos;
    BOOL            fRegColor = TRUE;
    char            oldCh;

    strcpy( buffer, str );
    str = buffer;
 
    wmove( pw, y, x );
    wstandend( pw );
    do { 
	pos = strchr( str, ch );
	if  ( pos == NULL ) 
	    pos = str + strlen( str );
	
	oldCh = *pos;
	*pos = 0;
	
	if  ( fRegColor ) { 
	    wattrset( pw, regColor );
	} else {
	    wattrset( pw, hiColor );
	}

	wmove( pw, y, x );
	wprintw( pw, str );
	wstandend( pw );
	x += strlen( str );
	str = pos + 1;
	fRegColor = ! fRegColor;
    }  while  ( oldCh != 0 );

    return  0;
}



#define   BUFFER_SIZE 400

static  void          width_wprintw( WINDOW         * pw,
				     int              y,
				     int              x,
				     int              width,
				     char           * str )
{
    char                   * lpszBuf;
    int                      len;

    lpszBuf = malloc( BUFFER_SIZE );
    if  ( lpszBuf == NULL )
        return;
    len = strlen( str );

    memset( lpszBuf, ' ', BUFFER_SIZE );
    strcpy( lpszBuf + 1, str );
    lpszBuf[ strlen( lpszBuf ) ] = ' ';
    lpszBuf[ width - 1 ] = ' ';
    lpszBuf[ width ] = 0;

    if  ( len > ( width - 2 ) ) 
        lpszBuf[ width - 1 ] = '>';

    mvwprintw( pw, y, x, lpszBuf );
    free( lpszBuf );
}
				    


static  void          displayTrack( displayInfoType * pInfo, 
                                    int               ind )
{
    struct trackinfo   * trk;
    WINDOW             * pwTOC; 
    struct cdinfo      * pCD;
    int                  line, scrLine, startHour;
    char               * lpszSong;

    if  ( ind < pInfo->scrStartTrack  || 
	  pInfo->scrStartTrack + pInfo->cdLines <= ind )
        return;
    line = ind - pInfo->scrStartTrack;

    pwTOC = pInfo->pwTOC;
    pCD = pInfo->pCD;

    if  ( ( ind + 1 ) == pInfo->cur_track ) 
        wattrset( pwTOC, REVERSE_COLOR );
    else
        wattrset( pwTOC, NORMAL_COLOR );

    trk = &pCD->trk[ ind ];
    
    scrLine = TOC_TOP_LINE + 1 + line;

    /* track number */
    mvwprintw( pwTOC, scrLine, STARTX_TRK_NUM, " %2d", ind + 1 );
    
    /* start time */
    startHour = trk->start / (60 * 75 * 60);
    if  ( startHour > 0 ) 
        mvwprintw( pwTOC, scrLine, STARTX_TRK_START,  
                   "%2d:%02d:%02d ", trk->start / (60 * 75 * 60), 
                   trk->start / (60 *75) % 60,
                   ( trk->start / 75 ) % 60 );
    else
        mvwprintw( pwTOC, scrLine, STARTX_TRK_START,  
                   "   %2d:%02d ",  trk->start / (60 *75) % 60,
                   ( trk->start / 75 ) % 60 );
    
    /* length */
    mvwprintw( pwTOC, scrLine, STARTX_TRK_LENGTH, 
               " %2d:%02d ", trk->length / 60, trk->length % 60 ); 
    
    /* name */
    if  ( trk->songname == NULL )
        lpszSong = "";
    else
        lpszSong = trk->songname;
    width_wprintw( pwTOC, scrLine, STARTX_TRK_NAME, WIDTH_TRK_NAME + 2, 
 		   lpszSong );		  

    wattrset( pwTOC, NORMAL_COLOR );
}


static  void     whsplitline( WINDOW     * pw, 
                              int          line,
                              int          xSize )
{
    mvwaddch( pw, line, 0, ACS_LTEE );
    mvwaddch( pw, line, xSize - 1, ACS_RTEE );
    wmove( pw, line, 0 ); 
    whline( pw, NORMAL_COLOR | ACS_HLINE, xSize - 3 );
}


static void            displayTOC( displayInfoType       * pInfo )
{
    static int           cols_start[] = { STARTX_TRK_START - 1,
                                          STARTX_TRK_LENGTH - 1, 
                                          STARTX_TRK_NAME - 1, 0 };
    int                  ind, currCol, hour;
    WINDOW             * pwTOC; 
    struct cdinfo      * pCD;
    char                 buffer[ 100 ];

    pwTOC = pInfo->pwTOC;
    pCD = pInfo->pCD;

    wstandend( pwTOC );
    wattrset( pwTOC, NORMAL_COLOR );
    werase( pwTOC );

    box( pwTOC, ACS_VLINE, ACS_HLINE );
   
    cursesSmartPrint( pwTOC, 1, 2, "~A~rtist          : ", '~', NORMAL_COLOR,
		      MARKED_COLOR | A_BOLD );
    cursesSmartPrint( pwTOC, 2, 2, "~C~D Name         : ", '~', NORMAL_COLOR,
		      MARKED_COLOR | A_BOLD );
    wattrset( pwTOC, NORMAL_COLOR );
    mvwprintw( pwTOC, 3,  2, "Tracks Number   : " );
    mvwprintw( pwTOC, 4,  2, "Total Play Time : " );

    wstandend( pwTOC );
    wattron( pwTOC, MARKED_COLOR | A_BOLD );
    
    width_wprintw( pwTOC, 1, 19, WIDTH_ARTIST, pCD->artist );
    width_wprintw( pwTOC, 2, 19, WIDTH_CDNAME, pCD->cdname );

    mvwprintw( pwTOC, 3, 20, "%d ", pCD->ntracks );

    hour =  pCD->length / 3600;
    if  ( hour > 0 )
        sprintf( buffer, "%d:%02d:%02d ",
               hour, (pCD->length / 60) % 60, pCD->length % 60 );
    else
        sprintf( buffer, "%2d:%02d ",
		 (pCD->length / 60) % 60, pCD->length % 60 );
    mvwprintw( pwTOC, 4, 20, buffer );
        
    wattrset( pwTOC, NORMAL_COLOR );

    whsplitline( pwTOC, TOC_TOP_LINE, TOC_XSIZE );
    whsplitline( pwTOC, INFO_LINE - 1, TOC_XSIZE );
    wattrset( pwTOC, NORMAL_COLOR );
    currCol = 1;
    
    for  ( ind = 0; cols_start[ ind  ] != 0; ind++ ) {
        currCol = cols_start[ ind ];
        mvwaddch( pwTOC, TOC_TOP_LINE, currCol, ACS_TTEE );
        mvwaddch( pwTOC, TOC_YSIZE - 1, currCol, ACS_BTEE );
        wmove( pwTOC, TOC_TOP_LINE, currCol );
        wvline( pwTOC, NORMAL_COLOR | ACS_VLINE, TOC_YSIZE - 3 - TOC_TOP_LINE );  
    }
    
    /*----------------------------------------------------------------------
     * We must normalize scrStartTrack
    \*----------------------------------------------------------------------*/
    if  ( pInfo->fFollowMode  &&  pInfo->cur_track > 0 ) {
        if  ( pInfo->scrStartTrack >= pInfo->cur_track ) 
            pInfo->scrStartTrack = max( pInfo->cur_track - 1 - pInfo->cdLines / 2,
				        0 );

        if  ( pInfo->scrStartTrack + pInfo->cdLines < pInfo->cur_track ) 
            pInfo->scrStartTrack = max( pInfo->cur_track - 1 - pInfo->cdLines / 2,
				        0 );
    }

    for  ( ind = 0; ind < pCD->ntracks; ind++ ) 
        displayTrack( pInfo, ind );

    wnoutrefresh( pwTOC );
}


/* display the complete screen */
void      displayControlPanel( displayInfoType       * pInfo )
{
    WINDOW             * pwTOC; 
    struct cdinfo      * pCD;
			      
    pwTOC = pInfo->pwTOC;
    pCD = pInfo->pCD;
    
    displayTOC( pInfo );
  
    mvwprintw( pwTOC, 1, PAD_STARTX + 1, "  STOP     ||       PLAY" ); 
    mvwprintw( pwTOC, 2, PAD_STARTX + 1, "   <-    RESTART     -> " ); 
    mvwprintw( pwTOC, 3, PAD_STARTX + 1, "   <<     EJECT      >> " ); 
    mvwprintw( pwTOC, 4, PAD_STARTX + 1, "  QUIT              HELP" );
    touchwin( pwTOC ); 
 
    mvwaddch( pwTOC, 0, PAD_STARTX, ACS_TTEE );
    mvwaddch( pwTOC, INFO_LINE - 1, PAD_STARTX, ACS_BTEE );
    wmove( pwTOC, 0, PAD_STARTX );
    wvline( pwTOC, NORMAL_COLOR | ACS_VLINE, INFO_LINE - 3 );  
   
    mvwaddch( pwTOC, 0, 2, ACS_RTEE );
    wattrset( pwTOC, NORMAL_COLOR );
    mvwprintw( pwTOC, 0, 3, " CDPlay  0.31" ); 
    wstandend( pwTOC );
    wattrset( pwTOC, MARKED_COLOR );
    mvwprintw( pwTOC, 0, 16, " " );
    wattrset( pwTOC, NORMAL_COLOR );
    mvwaddch( pwTOC, 0, 17, ACS_LTEE );

    wmove( pwTOC, LINES - 2, 0 );
    wnoutrefresh( pwTOC );
    doupdate();

    refreshMessage( pInfo );
}


void      displayInitInfo( displayInfoType       * pInfo,
  			   struct cdinfo         * pCD )
{
    pInfo->pCD = pCD;
    pInfo->scrStartTrack = 0;
    pInfo->cur_track = 0;

    pInfo->pwMessage = newwin( 1, TOC_XSIZE - 2, INFO_LINE, 1 );
    pInfo->pwTOC = newwin( TOC_YSIZE, TOC_XSIZE, 0, 0 );
    if  ( pInfo->pwMessage == NULL  ||  pInfo->pwTOC == NULL  )
        myExit( -1 );

    leaveok( pInfo->pwMessage, TRUE );

    pInfo->fFollowMode = TRUE;
    pInfo->cdLines = TOC_YSIZE - TOC_TOP_LINE - 2;
}


static  void     refreshMessage( displayInfoType        * pInfo )
{
    wstandend( pInfo->pwMessage );
    wattron( pInfo->pwMessage, NORMAL_COLOR );
    werase( pInfo->pwMessage );

    wattron( pInfo->pwMessage, MARKED_COLOR );
    cursesSmartPrint( pInfo->pwMessage, 0, 1, pInfo->szMessage, '~', NORMAL_COLOR,
	              MARKED_COLOR | A_BOLD );
    wrefresh( pInfo->pwMessage );
}


int            displayStatusPrintf( displayInfoType       * pInfo, 
		 		    char                  * fmt, ...)
{
   va_list   argptr;
   int       cnt, ind;
   char      buffer[ TOC_XSIZE + 50 ];

   va_start( argptr, fmt );
   cnt = vsprintf( buffer, fmt, argptr );
   
   for  ( ind = cnt; ind < TOC_XSIZE; ind++ )
       buffer[ ind ] = ' ';
   buffer[ TOC_XSIZE - 4 ] = 0;
   va_end(argptr);

   strcpy( pInfo->szMessage, buffer );
   refreshMessage( pInfo );

   return( cnt );
}


void      displayClearScreen( displayInfoType       * pInfo )
{
    /*-----------------------------------------------------------
     * The following is a rather dirty bypass to a bug of ncurses
     * : Ncurses when cleaning screen, uses terminal special code
     * . Thus the screen is automaticly cleaned to current term
     * color. If we want to clear to a specific color. We must 
     * force the terminal into changing it color into the
     * required color 
    \*----------------------------------------------------------*/ 
    wstandend( pInfo->pwTOC );
    mvwaddch( pInfo->pwTOC, 0, 0, '.' );
    wrefresh( pInfo->pwTOC );
		    
    standend();
    clear();
    refresh();
}


static void     resetCurrTrackMark( displayInfoType     * pInfo )
{
    int                      track;

    track = pInfo->cur_track;
    pInfo->cur_track = 0;
    displayTrack( pInfo, track - 1 );
    wrefresh( pInfo->pwTOC );
    pInfo->cur_track = track;
}


#define  SONG_SIZE               502

void      displayEditCurrSongName( displayInfoType      * pInfo )
{
    char                   * lpszNewName;
    int                      track;
    int                      line, code;
    struct cdinfo          * pCD;

    if   ( pInfo->cur_track <= 0 ) 
        return;
    lpszNewName = malloc( SONG_SIZE );
    if  ( lpszNewName == NULL )
        return;

    pCD = pInfo->pCD;
    track = pInfo->cur_track;
    resetCurrTrackMark( pInfo );

    line = TOC_TOP_LINE + 1 + track - 1 - pInfo->scrStartTrack;
    code = getline( line, STARTX_TRK_NAME, WIDTH_TRK_NAME + 2,REVERSE_COLOR,
		    NORMAL_COLOR, MARKED_COLOR | A_BOLD, 
 		    lpszNewName, SONG_SIZE, 
		    pCD->trk[ track - 1 ].songname );

    if   ( code == GETLINE_OK ) {
        free( pCD->trk[ track - 1 ].songname );
        pCD->trk[ track - 1 ].songname = lpszNewName;
	save();
    } else { 
        free( lpszNewName );
    }

    displayControlPanel( pInfo );    
}


void      displayEditCDName( displayInfoType      * pInfo )
{
    char                   * lpszNewName;
    int                      code;
    struct cdinfo          * pCD;

    if   ( pInfo->cur_track <= 0 ) 
        return;
    lpszNewName = malloc( SONG_SIZE + sizeof( pCD->cdname ) );
    if  ( lpszNewName == NULL )
        return;

    resetCurrTrackMark( pInfo );
    pCD = pInfo->pCD;

    code = getline( 2, 19, WIDTH_CDNAME, REVERSE_COLOR,
		    NORMAL_COLOR, MARKED_COLOR | A_BOLD, 
		    lpszNewName, sizeof( pCD->cdname ), 
		    pCD->cdname );

    if   ( code == GETLINE_OK ) {
        strcpy( pCD->cdname, lpszNewName ); 
	save();
    } 
    
    free( lpszNewName );
    displayControlPanel( pInfo );    
}


void      displayEditArtistName( displayInfoType      * pInfo )
{
    char                   * lpszNewName;
    int                      code;
    struct cdinfo          * pCD;

    if   ( pInfo->cur_track <= 0 ) 
        return;
    lpszNewName = malloc( SONG_SIZE + sizeof( pCD->artist ) );
    if  ( lpszNewName == NULL )
        return;

    resetCurrTrackMark( pInfo );
    pCD = pInfo->pCD;

    code = getline( 1, 19, WIDTH_ARTIST,REVERSE_COLOR,
		    NORMAL_COLOR, MARKED_COLOR | A_BOLD, 
		    lpszNewName, sizeof( pCD->artist ), 
		    pCD->artist );

    if   ( code == GETLINE_OK ) {
        strcpy( pCD->artist, lpszNewName ); 
	save();
    } 
    
    free( lpszNewName );
    displayControlPanel( pInfo );    
}


/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
 *     
 * display.c - End of File
\*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
