/*
 Copyright (c) 2015, Apple Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:
 
 1.  Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.
 
 2.  Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation and/or
 other materials provided with the distribution.
 
 3.  Neither the name of the copyright holder(s) nor the names of any contributors
 may be used to endorse or promote products derived from this software without
 specific prior written permission. No license is granted to the trademarks of
 the copyright holders even if such marks are included in this software.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#import <UIKit/UIKit.h>
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKRecorder.h>


NS_ASSUME_NONNULL_BEGIN

@class ORKStep;
@class ORKResult;
@class ORKEditableResult;
@class ORKStepViewController;
@class ORKTaskViewController;
@class ORKStepResult;

/**
 An enumeration of values used in `ORKStepViewControllerDelegate` to indicate the direction of navigation
 requested by the participant.
 */
typedef NS_ENUM(NSInteger, ORKStepViewControllerNavigationDirection) {
    
    /// Forward navigation. Indicates that the user tapped the Continue or Next button.
    ORKStepViewControllerNavigationDirectionForward,
    
    /// Backward navigation. Indicates that the user tapped the Back button.
    ORKStepViewControllerNavigationDirectionReverse
} ORK_ENUM_AVAILABLE;


/**
 The primary implementer of the `ORKStepViewControllerDelegate` protocol is the
 task view controller (`ORKTaskViewController`). The task view controller observes the messages 
 of the protocol to correctly update its `result` property, and to control navigation
 through the task.
 
 If you present step view controllers outside of a task view controller, it
 can be helpful to implement this protocol to facilitate navigation and
 results collection.
 */
@protocol ORKStepViewControllerDelegate <NSObject>

@required
/**
 Tells the delegate when the user has done something that requires navigation, such as
 tap the Back or a Next button, or enter a response to a nonoptional
 survey question.
 
 @param stepViewController     The step view controller providing the callback.
 @param direction              Direction of navigation requested.
 */
- (void)stepViewController:(ORKStepViewController *)stepViewController didFinishWithNavigationDirection:(ORKStepViewControllerNavigationDirection)direction;

/**
 Tells the delegate when a substantial change has occurred to the result.
 
 The result is always available in the step view controller. Although the result is continuously changing
 while the step view controller is active (because the time stamp in the result property is different each time it's called), this method is called only when a substantive change
 to the result occurs, such as when the user enters a survey answer or completes
 an active step.
 
 In your implementation of this delegate method, you can collect the value of `result` from the step view controller.
 
 @param stepViewController     The step view controller providing the callback.
 */
- (void)stepViewControllerResultDidChange:(ORKStepViewController *)stepViewController;

/**
 Tells the delegate when a step fails due to an error.
 
 A step view controller can use this method to report its failure to the task view controller.
 The task view controller sends the error to its delegate indicating that the task has failed (using `ORKTaskViewControllerFinishReasonFailed`).
 Note that recorder errors are reported by calling the `ORKStepViewControllerDelegate` method `stepViewController:recorder:didFailWithError:`.
 
 @param stepViewController     The step view controller providing the callback.
 @param error                  The error detected.
 */
- (void)stepViewControllerDidFail:(ORKStepViewController *)stepViewController withError:(nullable NSError *)error;

/**
 Tells the delegate when a recorder error has been detected during the step.
 
 Recorder errors can occur during active steps, usually due to the
 unavailability of sensor data or disk space in which to record results.
 
 @param stepViewController     The step view controller providing the callback.
 @param recorder               The recorder that detected the error.
 @param error                  The error detected.
 */
- (void)stepViewController:(ORKStepViewController *)stepViewController recorder:(ORKRecorder *)recorder didFailWithError:(NSError *)error;

@optional
/**
 Tells the delegate that the step view controller's view is about to appear.
 
 This method is called from the step view controller's `viewWillAppear:` method.
 You can use this method to customize the appearance of the step view
 controller without subclassing it.
 
 @param stepViewController          The step view controller providing the callback.
*/
- (void)stepViewControllerWillAppear:(ORKStepViewController *)stepViewController;

/**
 Asks the delegate whether there is a previous step.
 
 If there is a previous step, the step view controller adds a Back button to its
 navigation item; if not, no Back button is added to the navigation item.
 
 @param stepViewController     The step view controller providing the callback.
 
 @return `YES` if a Back button should be visible; otherwise, `NO`.
 */
- (BOOL)stepViewControllerHasPreviousStep:(ORKStepViewController *)stepViewController;

/**
 Asks the delegate whether there is a next step.
 
 Depending on the result of the step, the step view controller can adjust the language for the
 Next button.
 
 @param stepViewController     The step view controller providing the callback.
 
 @return `YES` if there is a step following the current one; otherwise, `NO`.
 */
- (BOOL)stepViewControllerHasNextStep:(ORKStepViewController *)stepViewController;

@end


/**
 The `ORKStepViewController` class is a base class for view controllers that are
 presented by an `ORKTaskViewController` object for the steps in a task.
 
 In the ResearchKit framework, each step collects some information or data from the user. 
 Typically, the task view controller instantiates the step view controller 
 before presenting the next step (`ORKStep`) in the task.
 
 When you create a new type of step, you usually have to subclass
 `ORKStepViewController` to manage the step. For examples of subclasses, see 
 `ORKQuestionStepViewController` and `ORKFormStepViewController`. In contrast, the view
 controller for an active step is typically a subclass of `ORKActiveStepViewController`,
 because active steps include the concept of life cycle.
 
 If you are simply trying to change some of the runtime behaviors of `ORKStepViewController`,
 it's usually not necessary to subclass it. Instead, implement the
 `[ORKTaskViewControllerDelegate taskViewController:stepViewControllerWillAppear:]` method in
 the `ORKTaskViewControllerDelegate` protocol, and modify the appropriate properties
 of the step view controller. For example, to change the title of the Learn More
 or Next buttons, set the `learnMoreButtonTitle` or `continueButtonTitle`
 properties in your implementation of this delegate method.
 */
ORK_CLASS_AVAILABLE
@interface ORKStepViewController : UIViewController

/**
 Returns a new step view controller for the specified step.
 
 @param step    The step to be presented.
 
 @return A newly initialized step view controller.
 */
- (instancetype)initWithStep:(nullable ORKStep *)step;

/**
 The step presented by the step view controller.
 
 If you use a storyboard to initialize the step view controller, `initWithStep:` isn't called,
 so you need to set the `step` property directly before the step view controller is presented.
 
 Setting the value of `step` after the controller has been presented is an error that
 generates an exception.
 Modifying the value of `step` after the controller has been presented is an error that
 has undefined results.
 
 Subclasses that override the setter of this property must call super.
 */
@property (nonatomic, strong, nullable) ORKStep *step;

/**
 The delegate of the step view controller.
 
 The delegate is usually the `ORKTaskViewController` object that presents the step view
 controller. If you need to intercept the delegate methods, you can
 assign an intermediary object as the delegate and forward the messages
 to the task view controller.
 */
@property (nonatomic, weak, nullable) id<ORKStepViewControllerDelegate> delegate;

/**
 A localized string that represents the title of the Continue button.
 
 Most steps display a button that enables forward navigation. This button can have titles
 such as Next, Continue, or Done. Use this property to override the forward navigation
 button title for the step.
 */
@property (nonatomic, copy, nullable) NSString *continueButtonTitle;

/**
 A localized string that represents the title of the Learn More button.
 
 Many steps have a button that lets users view more information about the
 step than can fit on the screen. Use this property to override the title
 of the Learn More button for the step.
 */
@property (nonatomic, copy, nullable) NSString *learnMoreButtonTitle;

/**
 A localized string that represents the title of the "Skip" button.
 
 Many steps are optional and can be skipped. Set this property to override
 the title of the Skip button for the step. Note that setting this property
 has no effect if the Skip button is not visible, which is the case in a required question step.
 */
@property (nonatomic, copy, nullable) NSString *skipButtonTitle;

/**
 The back button item.
 
 The back button item controls the Back button displayed in the navigation bar when
 the step view controller is current.
 This property lets you control the appearance and target of the
 Back button at runtime.
 
 When the value of the property is `nil`, the Back button is not displayed; otherwise, the title, target,
 and action associated with the Back button item are used (other properties of `UIBarButtonItem`
 are ignored).
 
 The back button item is updated during view loading and when the value of the `step` property
 is changed, but they are safe to set in the `taskViewController:stepViewControllerWillAppear:` delegate callback.
 
 Subclasses can safely modify this property any time after calling `viewWillAppear:` on super.
 */
@property (nonatomic, strong, nullable) UIBarButtonItem *backButtonItem;

/**
 The cancel button item.
 
 The cancel button item controls the Cancel button displayed in the navigation bar
 when the step view controller is current.
 This property lets you control the appearance and target of the
 Cancel button at runtime.
 
 When the value of the property is `nil`, the Cancel button is not displayed; otherwise, the title, target,
 and action associated with the Cancel button item are used (other properties of `UIBarButtonItem`
 are ignored).
 
 The cancel button item is updated during view loading and when the value of the `step` property
 is changed, but is safe to
 set in the `taskViewController:stepViewControllerWillAppear:` delegate callback.
 
 Subclasses can safely modify this property any time after calling `viewWillAppear:` on super.
 */
@property (nonatomic, strong, nullable) UIBarButtonItem *cancelButtonItem;

/**
 The current state of the result. (read-only)
 
 The task view controller uses this property to get the results for the
 step, and to collate them into the task result.
 
 The current step result and any subsidiary results representing data collected
 so far are available in this property. You can detect significant changes to the result,
 such as when the user enters a new answer, using the
 `stepViewControllerResultDidChange:` delegate callback.
 
 Subclasses *must* use this property to return the current results.
 Subclasses *may* call super to obtain
 a clean, empty result object appropriate for the step, to which they can
 attach appropriate child results.
 
 The implementations of this method in the ResearchKit framework currently create a new
 result object on every call, so do not call this method unless it is
 actually necessary.
 */
@property (nonatomic, copy, readonly, nullable) ORKStepResult *result;

/**
 Returns a Boolean value indicating whether there is a previous step.
 
 This method is a convenience accessor that subclasses can call to make a delegate callback to
 determine whether a previous step exists. Subclasses can also override this method if the step 
 view controller should always behave as if backward navigation is disabled.
 
 See also: `stepViewControllerHasPreviousStep:`
 
 @return `YES` if there is a previous step; otherwise, `NO`.
 */
- (BOOL)hasPreviousStep;

/**
 Returns a Boolean value indicating whether there is a next step.
 
 This method is a convenience method that subclasses can call to make a delegate callback to
 determine whether a next step exists.
 
 See also: `stepViewControllerHasNextStep:`
 
 @return `YES` if there is a next step; otherwise, `NO`.
 */
- (BOOL)hasNextStep;

/**
 The presenting task view controller. (read-only)
 */
@property (nonatomic, weak, readonly, nullable) ORKTaskViewController *taskViewController;

/**
 Navigates forward to the next step.
 
 When a user taps a Next button, the information passes through this method. You can use this method as an override
 point or a target action for a subclass.
 */
- (void)goForward;

/**
 Navigates backward to the previous step.
 
 When a user taps the Back button, the information passes through this method. You can use this method as an override
 point or a target action for a subclass.
 */
- (void)goBackward;

/**
 A Boolean value indicating whether the view controller has been presented before.
 */
@property (nonatomic, readonly) BOOL hasBeenPresented;

@end

NS_ASSUME_NONNULL_END
