/*
   Project: Adun

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This application is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#ifndef ADCONTROLLER
#define ADCONTROLLER

#include "AdunKernel/AdCreation.h"
#include "AdunKernel/AdunCore.h"

@class AdCore;

/**
\ingroup Protocols
Objects adopting this protocol can customise the
core set up procedure. 
\note Expand to include system data sources.
\note This is a prelminary form of this protocol.
The exact form requires finishing AdSystemNode. 
**/

@protocol AdCoreCreationDelegate 
/**
Sent to the delegate before the system is created
*/
- (void) coreWillCreateSystem: (AdCore*) core;
/**
Sent to the delegate before the force field is created
*/
- (void) coreWillCreateForceField: (AdCore*) core;
/**
Sent to the delegate before the simulator is created
*/
- (void) coreWillCreateSimulator: (AdCore*) core;
/**
Sent to the delegate after the system has been created. 
This method is always called after core:replacementObjectForSystem:
*/
- (void) coreDidCreateSystem: (AdCore*) core;
/**
Sent to the delegate after the force field has been created
This method is always called after core:replacementObjectForForceField:
*/
- (void) coreDidCreateForceField: (AdCore*) core;
/**
Sent to the delegate after the simulator has been created
This method is always called after core:replacementObjectForSimulator:
*/
- (void) coreDidCreateSimulator: (AdCore*) core;
/**
Called after the system has been intialised but before any data sources
are set. The delegate can replace the system with a custom object
*/
- (id) core: (AdCore*) core replacementObjectForSystem: (id) object;
/**
Called after the force field has been intialised. 
The delegate can replace the forcefield with a custom object
*/
- (id) core: (AdCore*) core replacementObjectForForceField: (id) object;
/**
Called after the simulator has been intialised.
The delegate can replace the simulator with a custom object
*/
- (id) core: (AdCore*) core replacementObjectForSimulator: (id) object;
@end

/**
\ingroup Protocols

A controller is a object that "controls" a simulation by sending
messages to and manipulating the framework objects that make up the simulator.
The main method of a controller is runSimulation. This is where all work
should take place. 

<b>Controllers and Threads</b>

The controller is expected provide the ability to run its main loop as a thread. This allows the
user to interact with the core, asking for information on simulation status etc.,
while the simulation is running. Creating and managing a thread is relatively
simple. The task is further simplified since a strict sequence
of events must be adhered to regarding controller termination. The class StandardController
provides a detailed template of the creation/termination prcess that other controllers
can use.

\e \b Note: When the thread is detached your controller object is essentially duplicated -
you have one in the simulation thread \e and one in the main thread. 
These two objects will share the same instance variables but otherwise act independantly. 
Thus it is important for the two object to be able to communicate across the threads so
 they can coordinate their actions.

<b>Creating the Simulation Thread</b>

No matter how the simulation thread is created it is vital that some 
inter-thread communication channel exits so it can
notify the controller object in the main thread that it has finished. The StandardController
class uses detachNewThreadSelector:toTarget:withObject to create the thread and an NSConnection
for communication. This method requires around 12 lines of code.

<b>Ending a Simulation</b>

The simulation can end in three ways. All must result in the
simulation thread notifying the main thread that it has finished and
then terminating. 

 -# The controller finishes normally.
 -# The controller on the main thread receives an endSimulation: message
	- The controller must cause the simulation thread to exit.
 -# An exception occurs in the simulation thread.
	- The thread should handle the exception, notify the main thread of the cause, and exit.

The easiest way to notify the main thread of the cause is for controller on the simulation thread to
set an NSError instance variable. The main thread controller can see if there was an error by checking 
if this instance variable has been assigned a value or not

When the controller is notified of its threads termination it 
\e must post an AdSimulationDidFinishNotification on the main thread. The core will recieve
this message and begin the clean up process.

<b>Cleaning Up</b>

Once the core has recieved the AdSimulationDidFinishNotification it will begin the task
of exiting gracefully. As part of this process the controller will receive a cleanUp message.
This is where the controller should perform neccessary outputs etc. before it is deallocated.

**/

@protocol AdController <AdCreation>
/**
Returns an object that can act as a creation delegate
for AdCore. see the AdCoreCreationDelegate protocol.
*/
- (id) coreCreationDelegate;
/**
This method must be called before runSimulation to allow
the controller to perform any setup tasks aswell as to 
obtain a reference to the core.
*/
- (void) coreWillStartSimulation: (AdCore*) core;
/**
Runs the controllers main loop
*/
- (void) runSimulation;
/**
Runs runSimulation in a separate thread. 
**/
- (void) runThreadedSimulation;
/**
Causes the controller to end the simulation 
and the simulator to enter the normal termination
chain (via posting AdSimulationDidFinishNotification)
*/
- (void) stopSimulation: (AdCore*) core;
/**
Causes the controller to terminate the simulation
without entering the normal termination chain
i.e. without posting AdSimulationDidFinishNotification
This method is used when an exception has been caught in the
main thread and hence it is already in the process of terminating
itself. If stopSimulation: was used it would cause a race
condition between the two exit sequences. 
*/
- (void) terminateSimulation: (AdCore*) core;
/**
On receiving this message the controller should
output any necessary files, close streams etc.
*/
- (void) cleanUp;
/**
Returns any controller dependant results or nil if there
is none
*/
- (id) simulationResults;
@end
#endif
