/* Controller.m:
* 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 Mai Nguyen, NeXT Developer Support
*
*/

#import <appkit/appkit.h>
#import <dbkit/dbkit.h>
#import <libc.h>
#import "Controller.h"

/* Define localized strings */
#define INSTALL_MODEL NXLocalizedString("Please install SybaseDemo.dbmodela into your project directory and restart.", NULL, "Notify user that SybaseDemo.dbmodela must be installed in his project directory.")
#define EMPTY_STRING NXLocalizedString("Cannot accept empty string", NULL, "Notify user that empty string input is not valid.")
#define INSERT_FAILED NXLocalizedString("Insert operation failed", NULL, "Notify user that insert operation has failed.")

static char newAuthorID[100];

@implementation Controller

/* Extract the actual database and recordlist from the DBModule UI Object
*/
-appDidInit:sender
{
/* Notify the user if the database can't be found */
if (![DBDatabase findDatabaseNamed:"SybaseDemo" connect:YES]) {
NXRunAlertPanel(NULL,INSTALL_MODEL, "OK", NULL, NULL);
return self;
}
dbDatabase = [dbModule database];
dbFetchGroup = [dbModule rootFetchGroup];
dbRecordList = [dbFetchGroup recordList];
recordOrder = DB_AscendingOrder;
dbQualifier = nil;

/* Initialize the retrieval order to be ascending order
*/
sortProp = [[dbModule entity] propertyNamed:"lastName"];

[dbRecordList addRetrieveOrder:recordOrder for:sortProp];

/* Assign the controller object to be the delegate of dbFetchGroup.
* See also the method fetchGroup:didInsertRecordAt:
*/
[dbFetchGroup setDelegate:self];

/* Assign the record list of the root fetchgroup to be the delegate
* of DBBinder. This is a convenient way to make sure that the proper
* qualifier will be used at fetch time.
* See also the method binderWillSelect:
*/
[[dbFetchGroup recordList] setBinderDelegate:self];

/* Create a DBValue instance to be used later for accessing data
* inside a record list.
*/
aValue = [[DBValue alloc] init];

[theWindow makeKeyAndOrderFront:nil];
return self;
}

/* Change the retrieval order for the record list. To be set before pressing
* SELECT.
*/
-changeRetrieveOrder:sender
{
recordOrder = [sender selectedTag];
return self;
}

/* Build the DBQualifier before a SELECT operation. Note that you should give
* the external names as defined in dbModel for properties.
*/
- buildSelectQualifier:sender
{
const char * state;
id stateProperty;

state = [qualifierField stringValue];
if (!strcmp(state,"")) {
dbQualifier = nil;
return nil;
}
else {
stateProperty = [[dbModule entity] propertyNamed:"state"];
dbQualifier = [[DBQualifier allocFromZone:[self zone] ]
initForEntity:[dbModule entity]
fromDescription:"%@ LIKE %s", stateProperty, state];
}
return self;
}

/* This method is called when the SELECT button is pressed.
* NOTE: If the qualifier form has a NULL string, the source is set to nil,
* which means that ALL records will be fetched.
*/
- select:sender
{
id source;

[self buildSelectQualifier:nil];
if (!dbQualifier)
source = nil;
else
source = [dbModule entity];

[dbFetchGroup fetchContentsOf:source usingQualifier:dbQualifier];

/* Update the display */
[self display];
return self;
}

/* This method is called when the INSERT button is pressed. Check for blank
* record fields before the actual INSERT.
*/
- insert:sender
{
if ([self checkInputRecord:sender]==nil)
NXRunAlertPanel(NULL,INSERT_FAILED, "OK", NULL, NULL);
else
[dbModule insertNewRecord:sender];
[self display];
return self;
}

/* Try to highlight the newly added row based on the token "newAuthorID".
* This method is called everytime the SELECT button is pressed.
* If there is no match, the first row is highlighted by default.
*/
- display
{
int rowCount, i, row;
id socSecProperty;
const char *keyValue;

row = 0;
/* Search for a match only if the ID has meaningful data */
if ( strlen(newAuthorID) > 0 ) {
rowCount = [dbTableView rowCount];
socSecProperty = [[dbModule entity] propertyNamed:"authorID"];
for (i= 0; i < rowCount; i++) {
[dbRecordList getValue:aValue forProperty:socSecProperty at:i];
keyValue = (const char *)[aValue stringValue];
if (!strcmp(keyValue, newAuthorID)) {
row = i;
break; }
}
}
[dbFetchGroup setCurrentRecord:row];
[dbTableView display];
return self;
}

/* DBFetchGroup delegate methods */

/*
* This method is called at each SELECT operation.
*/
- fetchGroupWillFetch:fetchGroup
{
[dbRecordList addRetrieveOrder:recordOrder for:sortProp];
return self;
}

/*
* This method is called at each INSERT operation.
*/

- fetchGroup:fetchGroup didInsertRecordAt:(int)index
{
/* Fill in the record fields before inserting the new record */
[self fillNewRecordAt:index];
return self;
}

/*
* This delegate method is called at each SAVE operation.
*/
- fetchGroupDidSave:fetchGroup
{
[self clearData];
return self;
}

/*
* This binder delegate method is called at each SELECT operation so that
* the proper qualifier is used.
*/

- (BOOL)binderWillSelect:aBinder
{
[aBinder setQualifier:dbQualifier];
return YES;
}

/* checkInputRecord
* Check if any input field is empty.
*/
- checkInputRecord:sender
{
int i;
const char *inputStr;

for ( i = 0; i < 9; i++ ) {
inputStr = (const char *)[formMatrix stringValueAt:i];
/* If the string is empty, abort the operation */
if ( inputStr == NULL){
NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
return nil;
}
}
return self;
}

/* fillNewRecordAt:(int) index
* Method used for INSERT operation
* Get the user input from the form cells.
*/
- fillNewRecordAt:(int)index
{
const char *inputString;
int contractNum;

/* set last name */
inputString = (const char *)[formMatrix stringValueAt:0];
[aValue setStringValue:inputString];
[dbRecordList setValue:aValue
forProperty:[[dbModule entity] propertyNamed:"lastName"]
at:index];

/* set first name */
inputString = (const char *)[formMatrix stringValueAt:1];
[aValue setStringValue:(const char *)inputString];
[dbRecordList setValue: aValue
forProperty: [[dbModule entity] propertyNamed:"firstName"]
at:index];

/* get the ssn or author id */
inputString = (const char *)[formMatrix stringValueAt:2];
[aValue setStringValue:inputString];
[dbRecordList setValue:aValue
forProperty:[[dbModule entity] propertyNamed:"authorID"]
at:index];
strcpy( newAuthorID, inputString);

/* set address */
inputString = (const char *)[formMatrix stringValueAt:3];
[aValue setStringValue: inputString];
[dbRecordList setValue: aValue
forProperty:[[dbModule entity] propertyNamed:"address"]
at:index];

/* set city name */
inputString = (const char *)[formMatrix stringValueAt:4];
[aValue setStringValue: inputString];
[dbRecordList setValue: aValue
forProperty:[[dbModule entity] propertyNamed:"city"]
at:index];

/* set state */
inputString = (const char *)[formMatrix stringValueAt:5];
[aValue setStringValue: inputString];
[dbRecordList setValue: aValue
forProperty:[[dbModule entity] propertyNamed:"state"]
at:index];

/* set zip code */
inputString = (const char *)[formMatrix stringValueAt:6];
[aValue setStringValue: inputString];
[dbRecordList setValue: aValue
forProperty:[[dbModule entity] propertyNamed:"zipCode"]
at:index ];

/* set phone number */
inputString = (const char *)[formMatrix stringValueAt:7];
[aValue setStringValue: inputString];
[dbRecordList setValue:aValue
forProperty:[[dbModule entity] propertyNamed:"phone"]
at:index];

/* set contract number */
contractNum = [formMatrix intValueAt:8];
[aValue setIntValue:contractNum];
[dbRecordList setValue: aValue
forProperty:[[dbModule entity] propertyNamed:"contract"]
at:index];

return self;
}

/* Clear the form cells after each SAVE operation to avoid creating
* duplicate records.
*/
- clearData
{
int i;

for (i = 0; i < 9; i++)
[formMatrix setStringValue:""at:i];
return self;
}

@end