/* 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 <objc/List.h>
#import <objc/NXBundle.h>
#import <sys/param.h>
#import <libc.h>

#import "Controller.h"
#import "AddressView.h"


#define FAILURE NXLocalizedString("Failure:", NULL, "Message given to user when connection to database can't be made")
#define CANNOT_CONNECT NXLocalizedString("Couldn't connect to database", NULL, "Message given to user to explain what fails. ")
#define CANNOT_ADD NXLocalizedString("Add operation failed", NULL, "Message given to user that add operation has failed")
#define CANNOT_UPDATE NXLocalizedString("Update operation failed",NULL,"Message given to user that update operation has failed")
#define CANNOT_DELETE NXLocalizedString("Delete operation failed",NULL,"Message given to user that delete operation has failed")

@implementation Controller

- appDidInit:sender
{
		/* Try to connect to the database specified using the Sybase Adaptor
		 * and the default login sa, NULL password, SYBASE server, and
		 * pubs database.
		 */
   	database = [[DBDatabase alloc]init];	   
	[database connectUsingAdaptor:"SybaseAdaptor"
								 andString:"sa@SYBASE/pubs"];

	if ( ![database isConnected] ) {
			NXRunAlertPanel(FAILURE, CANNOT_CONNECT, "OK", NULL, NULL);
			return self;
			}
		/* Once successfully connected, build the data to be displayed in the
		 * matrix
		 */
	[self initRecordList];
    [addressView loadCellsFrom:self];

		/* Assign the controller to become the database delegate */
	[database setDelegate:self];

   	cellMatrix = [addressView cellMatrix];
	
	 	/* Select a cell as a start */
    [[cellMatrix selectCellAt:0 :0] sendAction];
    	/* Bring the main application window up front */
	[theWindow makeKeyAndOrderFront:nil];
				
   	return self;
}

/* Set up the DBRecordList object. Create a list of properties which contains
 * all properties needed for display or updating.
 */
- initRecordList
{
	id firstName, lastName, phone;
	id state, city, address, zipCode, contract;
	List	*keyList;
	
	if (recordList)
		[recordList free];
	if (propertyList)
		[propertyList free];

			/* get the author table from the database */	
	authorEntity = [database entityNamed:"authors"];
	
			/* get the properties  */
	lastName = [authorEntity propertyNamed:"au_lname"];
	firstName = [authorEntity propertyNamed:"au_fname"];
	authId = [authorEntity propertyNamed:"au_id"];
	
 	phone = [authorEntity propertyNamed:"phone"];
	address = [authorEntity propertyNamed:"address"];
	city = [authorEntity propertyNamed:"city"];
	state = [authorEntity propertyNamed:"state"];
	zipCode = [authorEntity propertyNamed:"zip"];	  
	contract = [authorEntity propertyNamed:"contract"];
	
  		/* Set up the property list 
		 * Note that certain properties need to be defined in order
		 * for an Insert or Update operation to work. This depends
		 * on how your data dictionary has been defined. Here pubs
		 * is being used as the model.
		 */
	propertyList = [[List alloc] init];
	[propertyList addObject:authId];
  	[propertyList addObject:lastName];
	[propertyList addObject:firstName];
  	[propertyList addObject:phone];
	[propertyList addObject:address];
	[propertyList addObject:city];
	[propertyList addObject:state];
	[propertyList addObject:zipCode];
  	[propertyList addObject:contract];

   	recordList = [[DBRecordList alloc] init];
	
	
		/* A unique key is needed if you want to update or insert new
		 * data via the record list into the database. If no key is defined,
		 * the data retrieved via the  record list is read-only.
		 * This is needed here, since we do not use a dbmodel to define
		 * the key.
		 */
	keyList = (List *)[[List alloc] init];
	[keyList addObject:authId];
	[recordList setKeyProperties:keyList];
	[keyList free];
	
	/* You must set the properties FIRST before setting the retrieve order */
	[recordList setProperties:propertyList ofSource:authorEntity];
	
	[recordList addRetrieveOrder:DB_AscendingOrder for:lastName];
	[recordList addRetrieveOrder:DB_AscendingOrder for:firstName];					
	[recordList fetchUsingQualifier:nil];							 	
   	recordCount = [recordList count];
	
   	return self;
}
	
/* This method is called when selecting "Insert"
 */
- addRecords:sender
{	
	
	int row;

	if (recordCount > 0) {
	
		if ( ![addressView addRecordFrom:sender at:(recordCount-1)]) {
			NXRunAlertPanel(NULL, CANNOT_ADD, NULL, NULL, NULL);
			return self;
		}
		
	[self initRecordList];
 	[addressView loadCellsFrom:self];
		/* Find the row of the newly inserted record */
	row = [addressView getNewRow];
   	[cellMatrix scrollCellToVisible:row :0];
  	[[cellMatrix selectCellAt:row:0] sendAction];
  	}
  	else
  		fprintf(stderr, "empty record list - NOP\n");
  	return self;
}

/* This method gets called when selecting "Update"
 */
- updateRecords:sender
{
	int row;
	
	row = [cellMatrix selectedRow];
	if ( ![addressView updateRecordFrom:sender at:row]) {
		NXRunAlertPanel(NULL, CANNOT_UPDATE, NULL, NULL, NULL);
		return self;
	}
		/* Redisplay the records */
	[self initRecordList];
 	[addressView loadCellsFrom:self];
		/* find the row of the updated record */
	row = [addressView getNewRow];
   	[cellMatrix scrollCellToVisible:row :0];
  	[[cellMatrix selectCellAt:row:0] sendAction];

	return self;
}


- deleteRecords:sender
{	
	
	int row;
	
	row = [cellMatrix selectedRow];
	if (recordCount > 0) {
	
	if (![addressView deleteSelectedRecord:sender]) {
			NXRunAlertPanel(NULL, CANNOT_DELETE, NULL, NULL, NULL);
			return self;
		}

	[self initRecordList];
 	[addressView loadCellsFrom:self];
   	[cellMatrix scrollCellToVisible:row :0];
  	[[cellMatrix selectCellAt:row:0] sendAction];
  	}
  	else
  		fprintf(stderr, "empty record list - NOP\n");
	
	return self;
}	
- getRecordList
{
	return recordList;
}

- getPropertyList
{
	return propertyList;
}

- (int)getRecordCount
{
	return recordCount;
}

- showSQLPanel:sender
{
	[SQLPanel makeKeyAndOrderFront:nil];
	return self;
}

- showInfoPanel:sender
{
	if (!infoPanel) {
		infoPanel = [NXApp loadNibSection:"InfoPanel.nib" owner:NXApp
														 withNames:NO]; 
		}
    [infoPanel orderFront:nil];
	return self;
}

- appWillTerminate:sender
{
	/* deallocate what has been allocated */
	if (recordList)
		[recordList free];
	if (propertyList)
		[propertyList free];
	return self;
}

/* DBDatabase delegate methods to log error messages and SQL queries */

- (BOOL)db:aDb willEvaluateString:(const unsigned char*)aString
	 usingBinder:aBinder
{
	[textObj appendToText:"SQL Query:\n"];
	[textObj appendToText:aString];
	[textObj appendToText:"\n"];
	return YES;
}

@end

@implementation Text(printResults)

- appendToText:(const char *)newText
{
	int currentLength = [self textLength];

	[self setSel:currentLength :currentLength];
	[self replaceSel:newText];
	[self scrollSelToVisible];
	return self;
}

@end
