/* TextORama.m
 *
 *   TextORama is a subclass of Object which acts as the
 * application delegate.
 * 
 *
 * You may freely copy, distribute, and reuse the code in this example.
 * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
 * fitness for any particular use.
 *
 * Written by:  Sharon Zakhour 
 * Created:  Oct/91
 */

#import "TextORama.h"
#import "TurboTextField.h"
#import "TurboTFCell.h"

@implementation TextORama

- appDidInit:sender
{
    id font;
    
    font = [Font newFont: "Helvetica" size: 16.0];
    
    [dateField setAutoJump:YES forLength:8];
    [dateField setCustomFilter: (NXTextFilterFunc)dateFilter];
    [[dateField cell] setFont: font];

    [socSecField setAutoJump:YES forLength:11];
    [socSecField setCustomFilter: (NXTextFilterFunc)socSecFilter];
    [[socSecField cell] setFont: font];

    [phoneField setMaxLength:8];
    [phoneField setCustomFilter: (NXTextFilterFunc)phoneFilter];
    [[phoneField cell] setFont: font];
    
    [self loadEmacsScrollView];
    
    return self;
}


#define IS_DATE_DELIMITER(ch) ((ch) == '/')
#define IS_PHONE_DELIMITER(ch) ((ch) == '-')
#define IS_NUMBER(ch) ((ch) >= '0' && (ch) <= '9')
#define IS_LETTER(ch) ((ch) >= 'a' && (ch) <= 'z' || (ch) >= 'A' && (ch) <= 'Z')

// This could easily be extended to include letters with diacritics.
// See Chapter 6 Summary for KeyInfo for a full listing of keyboard
// event information.
#define IS_VALID_ASCII(ch)	((ch) >= ' ' && (ch) <= '~')

char *dateFilter(id textObj, char *inputText, int *inputLength, int position)
{
    BOOL ok = NO;
    char	*dateString;
    int		dateLength, tmp;
    
    switch(position) 
    {

	case 2: case 5:
	    ok = IS_DATE_DELIMITER(*inputText);
	    if (!ok && IS_VALID_ASCII(*inputText))  NXBeep();
	    break;

	default:
	    ok = IS_NUMBER(*inputText);
	    if (!ok && IS_VALID_ASCII(*inputText))  NXBeep();
	    break;
    }
    
    // Let's do some actual date validation...
    dateLength = [textObj textLength];
    dateString = malloc(dateLength + 1);
    [textObj getSubstring:dateString start:0 length:dateLength];
    
    if (!ok)
    {
	*inputLength = 0;
	free(dateString);
	return "";
    }
    
    switch (dateLength)
    {
    case 1:
	dateString[1] = '\0';
	tmp = atoi(&dateString[0]);
	ok = (tmp == 0 || tmp == 1);
	break;
    case 2:
	dateString[2] = '\0';
	tmp = atoi(&dateString[0]);
	ok = (tmp >= 1 && tmp <= 12);
	break;
    case 4:
	dateString[4] = '\0';
	tmp = atoi(&dateString[3]);
	ok = (tmp >= 0 && tmp <= 3);
	break;
    case 5:
	dateString[5] = '\0';
	tmp = atoi(&dateString[3]);
	ok = (tmp >= 1 && tmp <= 31);
	break;
    case 7:
	dateString[7] = '\0';
	tmp = atoi(&dateString[6]);
	ok = (tmp == 8 || tmp == 9);
	break;
    case 8:
	dateString[8] = '\0';
	tmp = atoi(&dateString[6]);
	ok = (tmp >= 80 && tmp <= 99);
	break;
    }
    
    free(dateString);    
    if (ok) return inputText;
    *inputLength = 0;
    return "";
}

char *socSecFilter(id textObj, char *inputText, int *inputLength, int position)
{
    BOOL ok = NO;
    
    switch(position) 
    {
	case 3: case 6:
	    ok = IS_PHONE_DELIMITER(*inputText);
	    if (!ok && IS_VALID_ASCII(*inputText))  NXBeep();
	    break;

	default:
	    ok = IS_NUMBER(*inputText);
	    if (!ok && IS_VALID_ASCII(*inputText))  NXBeep();
	    break;
    }
    if (ok) return inputText;
    *inputLength = 0;
    return "";
}

char *phoneFilter(id textObj, char *inputText, int *inputLength, int position)
{
    BOOL ok = NO;
    
    switch(position) 
    {
	case 3:
	    ok = IS_PHONE_DELIMITER(*inputText);
	    if (!ok && IS_VALID_ASCII(*inputText))  NXBeep();
	    break;

	default:
	    ok = IS_NUMBER(*inputText);
	    if (!ok && IS_VALID_ASCII(*inputText))  NXBeep();
	    break;
    }
    if (ok) return inputText;
    *inputLength = 0;
    return "";
}

// Load the EMACS window with some text so that we can play with the emacs
// bindings!!
- loadEmacsScrollView
{
    id  theTO;
    NXStream *s = (NXStream *)nil;
    char buf[256];
    const char *bp;
    
    theTO = [emacsScrollView docView];
    
    // Open a memory stream on the data file and read it into the text object.
    bp = [[NXBundle mainBundle] directory];
    sprintf(buf, "%s/SoapStory.rtf", bp);
    s = NXMapFile(buf, NX_READONLY);
    if (s)
    {
	[theTO readRichText:s];
	NXCloseMemory(s, NX_FREEBUFFER);
    }
    
    [[emacsScrollView window] orderFront:nil];
    
    return self;
}

@end
