/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
 * getline.c -
 *     
\*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/

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

#include   "getline.h"
#include   "misc.h"


/*=========================================================================
 * Alternative keys
\*=========================================================================*/
#define  KEY_ALT_BACKSPACE   127
#define  KEY_ALT_ENTER       0x0a


/*=========================================================================
 * Static Types
\*=========================================================================*/
typedef struct {
    int       x, y;
    int       strSize;
    int       width;
    WINDOW  * pw;
    char    * text;
    int       textLen, startPos, cursorPos;
    BOOL      fDefault;
    chtype    attrText;
    chtype    attrDefault;
    chtype    attrMarkers;
}  interInfoType;


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


static int        drawLine( interInfoType       * pInfo )
{
    BOOL             fRightSlideActive, fLeftSlideActive;
    char             ch;
    int              posEnd;
    WINDOW         * pw = pInfo->pw;

    fRightSlideActive = ( pInfo->startPos + pInfo->width - 2 < pInfo->textLen );
    fLeftSlideActive = ( pInfo->startPos > 0 );

    wattrset( pw, pInfo->attrText ); 
    werase( pw );

    wattrset( pw, pInfo->attrMarkers );
    if  ( fRightSlideActive ) 
        mvwaddch( pw, 0, pInfo->width - 1, '>' );
    if  ( fLeftSlideActive ) 
        mvwaddch( pw, 0, 0, '<' );
    
    posEnd = min( pInfo->startPos + pInfo->width - 2, pInfo->textLen );
    ch = pInfo->text[ posEnd ];
    pInfo->text[ posEnd ] = 0;

    if  ( pInfo->fDefault ) 
        wattrset( pw, pInfo->attrDefault ); 
    else
        wattrset( pw, pInfo->attrText ); 

    mvwprintw( pw, 0, 1, pInfo->text + pInfo->startPos );
    wmove( pw, 0, pInfo->cursorPos - pInfo->startPos + 1 );

    wrefresh( pw );

    pInfo->text[ posEnd ] = ch;

    return  0;
}


static  void       addKey( interInfoType       * pInfo, int       key )
{
    int                      ind;

    if   ( pInfo->fDefault ) {
        pInfo->text[ 0 ] = 0;
	pInfo->cursorPos = pInfo->startPos = 0;
	pInfo->fDefault = 0;
	pInfo->textLen = 0;
    }

    if  ( ( pInfo->textLen + 1 ) >= pInfo->strSize ) {
        return;
    }

    for  ( ind = pInfo->textLen; ind >= pInfo->cursorPos; ind-- ) 
        pInfo->text[ ind + 1 ] = pInfo->text[ ind ];
    pInfo->text[ pInfo->cursorPos ] = key;
    pInfo->textLen++;
    pInfo->text[ pInfo->textLen ] = 0;
    pInfo->cursorPos++;    
}


static  void       normalizePos( interInfoType       * pInfo )
{
    if  ( pInfo->cursorPos < 0 ) 
        pInfo->cursorPos = 0;
    if  ( pInfo->cursorPos > pInfo->textLen ) 
        pInfo->cursorPos = pInfo->textLen;
    
    if  ( pInfo->cursorPos < pInfo->startPos ) 
        pInfo->startPos = pInfo->cursorPos;
    if  ( ( pInfo->cursorPos - pInfo->startPos ) > ( pInfo->width - 2 ) )
        pInfo->startPos = pInfo->cursorPos - pInfo->width + 2;
}



static void       deleteKey( interInfoType       * pInfo,
			     BOOL                  fDelKey )
{
    int                      ind;

    if  ( pInfo->textLen == 0  || 
	  ( fDelKey  &&  pInfo->cursorPos == pInfo->textLen ) ||
	  ( ! fDelKey  &&  pInfo->cursorPos == 0 ) )
         return;

    if  ( fDelKey )
        pInfo->cursorPos++;

    for  ( ind = pInfo->cursorPos - 1; ind < pInfo->textLen; ind++ )
        pInfo->text[ ind ] = pInfo->text[ ind + 1 ];
    pInfo->textLen--;
    pInfo->cursorPos--; 
}
			     

int     getline( int      y,
		 int      x, 
		 int      width,
 		 chtype   attrText,
		 chtype   attrDefault,
		 chtype   attrMarkers,
		 char   * str,
		 int      strSize,
		 char   * lpszDef )
{
    interInfoType        info;
    int                  key;
#ifdef  DEBUG
    int                  count = 0;
#endif /* DEBUG */

    memset( &info, 0, sizeof( info ) );
    info.pw = newwin( 1, width, y, x );
    if   ( info.pw == NULL ) 
        return   GETLINE_ERR;

    info.text = malloc( strSize + strlen( lpszDef ) + 256 );
    if  ( info.text == NULL )
        return   GETLINE_ERR;
    strcpy( info.text, lpszDef );
    info.textLen = strlen( info.text );
    info.fDefault = TRUE;
    info.strSize = strSize;

    info.width = width;
    info.attrText = attrText;
    info.attrDefault = attrDefault;
    info.attrMarkers = attrMarkers;

    drawLine( &info );
    
    cbreak();
    raw();
    noecho();

    keypad( info.pw, TRUE );
    do { 
#ifdef  DEBUG
        count++;
        standend(); 
	mvprintw( 2,1, "count: %d ----------[%s] ", count, info.text );
	refresh();
#endif /* DEBUG */
	
	wmove( info.pw, 0, info.cursorPos - info.startPos + 1 );
        key = wgetch( info.pw );

#ifdef  DEBUG 
	standend();
	mvprintw( 1,1, "key = [%d]\n%c [%d]", key, key );
	refresh();
#endif  /* DEBUG */

	switch  ( key ) {
	    case  KEY_ALT_ENTER :
	        strcpy( str, info.text );
	        return   GETLINE_OK;
                	      
	    case  KEY_LEFT :
	        info.cursorPos--;
		info.fDefault = FALSE;
	        break;
	     
	    case  KEY_RIGHT :
	        info.cursorPos++;
		info.fDefault = FALSE;
		break;
  
            case   KEY_ALT_BACKSPACE :
	    case   KEY_BACKSPACE :
	    case   KEY_DC :
	        deleteKey( &info, key == KEY_DC );
	        break;

            case   KEY_HOME :
	        info.cursorPos = 0;
		info.fDefault = FALSE;
	        break;

            case   KEY_END :
	        info.cursorPos = info.textLen;
		info.fDefault = FALSE;
	        break;
		
	    default :
	        if  ( key > 27  &&  key < 255 ) 
		    addKey( &info, key );	       
	        break;
	}; /* switch */

	normalizePos( &info );
	drawLine( &info );
    }  while   ( key != 27 );

    return   GETLINE_CANCEL;
}



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










