//
//  TKListView.h
//  TelerikUI
//
//  Copyright (c) 2013 Telerik. All rights reserved.
//

@class TKListView;
@class TKListViewCell;
@class TKListViewReusableCell;
@class TKListViewPullToRefreshView;
@class TKListViewLoadOnDemandView;

#import "TKListViewLinearLayout.h"

/**
 This constant takes place in dequeing supplementary views for group headers.
 */
extern NSString *const __nonnull TKListViewElementKindSectionHeader;

/**
 This constant takes place in dequeing supplementary views for group footers.
 */
extern NSString *const __nonnull TKListViewElementKindSectionFooter;

/**
 @enum TKListViewReorderMode
 @discussion Defines the reorder behavior of TKListView.
 */
typedef NS_ENUM(NSInteger, TKListViewReorderMode)
{
    /**
     An item can be reordered with a handle.
     */
    TKListViewReorderModeWithHandle,

    /**
     An item can be reordered after a long press gesture.
     */
    TKListViewReorderModeWithLongPress,
};

/**
 @enum TKListViewSelectionBehavior
 @discussion Defines the selection behavior of TKListView.
 */
typedef NS_ENUM(NSInteger, TKListViewSelectionBehavior)
{
    /**
     No selection is allowed.
     */
    TKListViewSelectionBehaviorNone,
    /**
     Selection on press.
     */
    TKListViewSelectionBehaviorPress,
    /**
     Selection on long press.
     */
    TKListViewSelectionBehaviorLongPress,
};

/**
 @enum TKListViewLoadOnDemandMode
 @discussion Defines the load on demand mode used in TKListView.
 */
typedef NS_ENUM(NSInteger, TKListViewLoadOnDemandMode)
{
    /**
     Load on demand is disabled.
     */
    TKListViewLoadOnDemandModeNone,
    
    /**
     More data will be loaded in list view after clicking on load on demand cell.
     */
    TKListViewLoadOnDemandModeManual,
    
    /**
     More data will be loaded in list view automatically while scrolling.
     */
    TKListViewLoadOnDemandModeAuto
};

/**
 The TKListViewDelegate protocol defines methods that allow you to manage the selection of items in TKListView, to perform actions on those items, and respond to interaction with those items.
 */
@protocol TKListViewDelegate <UIScrollViewDelegate>
@optional

- (void)listView: (TKListView* __nonnull)listView scrollViewDidScroll:(UIScrollView* __nonnull)scrollView;                                               // any offset changes

// called on start of dragging (may require some time and or distance to move)
- (void)listView: (TKListView* __nonnull)listView scrollViewWillBeginDragging:(UIScrollView* __nonnull)scrollView;
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
- (void)listView: (TKListView* __nonnull)listView scrollViewDidEndDragging:(UIScrollView* __nonnull)scrollView willDecelerate:(BOOL)decelerate;
// called on finger up as we are moving
- (void)listView: (TKListView* __nonnull)listView scrollViewDidEndDecelerating:(UIScrollView * __nonnull)scrollView;


/**
 * Returns a boolean value indicating whether the specified item should be highlighted.
 @param listView The TKListView instance requesting this information.
 @param indexPath The index path of the item about to be highlighted.
 
 @return YES if the item should be highlighted.
 */
- (BOOL)listView:(TKListView* __nonnull)listView shouldHighlightItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 This method is called after highliting an item.
 @param listView The TKListView instance.
 @param indexPath The index path of the highlighted item.
 */
- (void)listView:(TKListView * __nonnull)listView didHighlightItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 This method is called after unhighliting an item.
 @param listView The TKListView instance.
 @param indexPath The index path of the unhighlighted item.
 */
- (void)listView:(TKListView * __nonnull)listView didUnhighlightItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 Returns a boolean value indicating whether the specified item should be selected.
 @param listView The TKListView instance requesting this information.
 @param indexPath The index path of the item about to be selected.
 
 @return YES if the item should be selected.
 */
- (BOOL)listView:(TKListView * __nonnull)listView shouldSelectItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 Returns a boolean value indicating whether the specified item should be deselected.
 @param listView The TKListView instance requesting this information.
 @param indexPath The index path of the item about to be deselected.
 
 @return YES if the item should be selected.
 */
- (BOOL)listView:(TKListView * __nonnull)listView shouldDeselectItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 This method is called after selecting an item.
 @param listView The TKListView instance.
 @param indexPath The index path of the selected item.
 */
- (void)listView:(TKListView * __nonnull)listView didSelectItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 This method is called after deselecting an item.
 @param listView The TKListView instance.
 @param indexPath The index path of the deselected item.
 */
- (void)listView:(TKListView * __nonnull)listView didDeselectItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 This method is called when list view is about to reorder an item.
 @param listView The TKListView instance.
 @param indexPath The index path of the item.
 @return YES if the item can be reordered, otherwise NO
 */
- (BOOL)listView:(TKListView * __nonnull)listView willReorderItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 This method is called after reordering an item an item.
 @param listView The TKListView instance.
 @param originalIndexPath The index path we move the item from.
 @param targetIndexPath The index path we move the item to.
 */
- (void)listView:(TKListView * __nonnull)listView didReorderItemFromIndexPath:(NSIndexPath * __nonnull)originalIndexPath toIndexPath:(NSIndexPath * __nonnull)targetIndexPath;

/**
 This method is called when the user starts swiping a cell.
 @param listView The TKListView instance.
 @param cell The TKListViewCell instance being swiped.
 @param indexPath The index path of the cell being swiped.
 */
- (BOOL)listView:(TKListView * __nonnull)listView shouldSwipeCell:(TKListViewCell* __nonnull)cell atIndexPath:(NSIndexPath* __nonnull)indexPath;

/**
 This method is called when the user swipes a cell. This method is called after shouldSwipeCell and before didFinishSwipingCell.
 @param listView The TKListView instance.
 @param cell The TKListViewCell instance being swiped.
 @param indexPath The index path of the cell being swiped.
 @param offset The swipe offset.
 */
- (void)listView:(TKListView * __nonnull)listView didSwipeCell:(TKListViewCell* __nonnull)cell atIndexPath:(NSIndexPath* __nonnull)indexPath withOffset:(CGPoint)offset;

/**
 This method is called after the user has finished swiping a cell.
 @param listView The TKListView instance.
 @param cell The TKListViewCell instance being swiped.
 @param indexPath The index path of the cell being swiped.
 @param offset The swipe offset.
 */
- (void)listView:(TKListView * __nonnull)listView didFinishSwipeCell:(TKListViewCell * __nonnull)cell atIndexPath:(NSIndexPath * __nonnull)indexPath withOffset:(CGPoint)offset;

/**
 This method is called when the user pulls the list view to refresh its data.
 @param listView The TKListView instance.
 @param offset The pull offset.
 */
- (void)listView:(TKListView * __nonnull)listView didPullWithOffset:(CGFloat)offset;

/**
 This method is called after the user long pressed a cell.
 @param listView The TKListView instance.
 @param cell The TKListViewCell instance being long pressed.
 @param indexPath The index path of the cell being long pressed.
 */
- (void)listView:(TKListView * __nonnull)listView didLongPressCell:(TKListViewCell* __nonnull) cell atIndexPath:(NSIndexPath* __nonnull) indexPath;

/**
 Returns a boolean value indicating whether more data will be loaded.
 Called after the user requested loading more data on demand by scrolling over the cellBuffer limit size.
 @param listView The TKListView instance.
 @param indexPath The index path where the buffer limit size was reached.
 */
- (BOOL)listView:(TKListView * __nonnull)listView shouldLoadMoreDataAtIndexPath:(NSIndexPath* __nonnull) indexPath;

/**
 Returns a boolean value indicating whether listView should display activity indicator and wait for fresh data.
 Called after user performs pull-to-refresh gesture.
 @param listView The listview component instance requesting the fresh data.
 */
- (BOOL)listViewShouldRefreshOnPull:(TKListView * __nonnull)listView;


@end

/**
 A delegate class exposing mothods to provide cells and supplementary views matching the source data.
 */
@protocol TKListViewDataSource <NSObject>
@required

/**
 Returns the number of items conatined in specific section.
 @param listView The TKListView instance requesting the information.
 @param section The index for the section.
 */
- (NSInteger)listView:(TKListView * __nonnull)listView numberOfItemsInSection:(NSInteger)section;


/**
 Returns a TKListViewCell instance for a given index path.
 The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
 @param listView The TKListView instance requesting the cell.
 @param indexPath The index path we need a cell for.
 */
- (TKListViewCell * __nullable)listView:(TKListView * __nonnull) listView cellForItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

@optional

/**
 Returns the number of sections.
 @param listView The TKListView instance requesting the cell.
 */
- (NSInteger)numberOfSectionsInListView:(TKListView * __nonnull)listView;

/**
 Returns a view to be used as a section header or footer in TKListView.
 The cell that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:
 @param listView The TKListView instance requesting the cell.
 @param kind The kind of the supplementary view e.g. TKListViewElementKindSectionHeader or TKListViewElementKindSectionFooter
 @param indexPath The index path we need a cell for.
 */
- (TKListViewReusableCell * __nullable)listView:(TKListView * __nonnull)listView viewForSupplementaryElementOfKind:(NSString * __nonnull)kind atIndexPath:(NSIndexPath * __nonnull)indexPath;

@end

/**
 @discussion TKListView provides means for displaying lists of data. The items of the list can be arranged in a columns layout or wrap layout. It provides UI virtualization, pull-to-refresh, load-on-demand, cells swipe, cell reorder, single/multiple selection, grouping.
 */
@interface TKListView : UIView <UICollectionViewDataSource, UICollectionViewDelegate>

/**
 A delegate used to manage the selection of items in TKListView, perform actions on those items and respond to interaction with those items.
 */
@property (nonatomic, weak, nullable) id<TKListViewDelegate> delegate;

/**
 A datasource delegate used to provide data for the cells, headers and footers.
 */
@property (nonatomic, weak, nullable) id<TKListViewDataSource> dataSource;

/**
 The layout object used to arrange cells.
 */
@property (nonatomic, strong) UICollectionViewLayout * __nonnull layout;

/**
 Indicates whether user is able to select multiple items.
 */
@property (nonatomic) BOOL allowsMultipleSelection;

/**
 Indicates whether user is able to reorder cells.
 */
@property (nonatomic) BOOL allowsCellReorder;

/**
 Indicates whether the end-user is able to swipe cells.
 */
@property (nonatomic) BOOL allowsCellSwipe;

/**
 Restricts the swipe direction based on the current scroll orientation.
 */
@property (nonatomic) BOOL autoRestrictSwipeDirection;

/**
 Indicates whether user is able to perform the pull-to-refresh gesture.
 */
@property (nonatomic) BOOL allowsPullToRefresh;

/**
 Defines whether to deselect an already selected item with a second tap. This property value is respected only when using single selection mode.
 */
@property (nonatomic) BOOL deselectOnSecondTap;

/**
 Defines the reorder mode.
 */
@property (nonatomic) TKListViewReorderMode reorderMode;

/**
 The maximum distance a cell can be swiped by the end-user.
 */
@property (nonatomic) UIEdgeInsets cellSwipeLimits;

/**
 The cell swipe treshold - the distance defining whether the cell will revert to original position or animate to the swipe limits if the end-user does not finish the swipe gesture.
 */
@property (nonatomic) CGFloat cellSwipeTreshold;

/**
 The cell swipe animation duration.
 */
@property (nonatomic) CGFloat cellSwipeAnimationDuration;

/**
 The distance from the edge where autoscroll commences while dragging/reordering a cell.
 */
@property (nonatomic) CGFloat autoScrollTreshold;

/**
 The pull distance at which pull-to-refresh activates.
 */
@property (nonatomic) CGFloat pullToRefreshTreshold;

/**
 Defines the load on demand mode.
 */
@property (nonatomic) TKListViewLoadOnDemandMode loadOnDemandMode;

/**
 Defines the number of cells from the bottom of TKListView up at which to start requesting load-on-demand data.
 */
@property (nonatomic) NSInteger loadOnDemandBufferSize;

/**
 The content insets relative to its view size.
 */
@property (nonatomic) UIEdgeInsets contentInset;

/**
 The content offset.
 */
@property (nonatomic) CGPoint contentOffset;

/**
 Defines the scroll direction. Applicable if the current layout supports it.
 */
@property (nonatomic) TKListViewScrollDirection scrollDirection;

/**
 Defines whether cells are selected on press, long press, or can't be selected at all.
 */
@property (nonatomic) TKListViewSelectionBehavior selectionBehavior;

/**
 The UIView containing the activity indicator while TKListView is refreshing data after the pull-to-refresh gesture.
 */
@property (nonatomic, strong) TKListViewPullToRefreshView * __nonnull pullToRefreshView;

/**
 The UIView containing the activity indicator while TKListView is loading data on demand and has scrolled to the end of the content size.
 */
@property (nonatomic, strong) TKListViewLoadOnDemandView * __nonnull loadOnDemandView;

/**
 A view that will be automatically resized to track the size of the collection view and placed behind all cells and supplementary views.
 */
@property (nonatomic, retain) UIView * __nullable backgroundView;

/**
 Returns an array with the index paths of the selected items.
 */
@property (nonatomic, strong, readonly, nullable) NSArray * indexPathsForSelectedItems;

/**
 Returns the number of sections.
 */
@property (nonatomic, readonly) NSInteger numberOfSections;

/**
 Returns the number for currently visible cells.
 */
@property (nonatomic, strong, readonly, nonnull) NSArray<__kindof TKListViewCell *> * visibleCells;

/**
 Returns the index paths for the currently visible cells.
 */
@property (nonatomic, strong, readonly, nonnull) NSArray<NSIndexPath *> *indexPathsForVisibleItems;

/**
 Reloads all data.
 */
- (void)reloadData;

/**
 Restores the swiped cell to its initial state.
 @param animated Determines whether to animate the cell.
 */
- (void)endSwipe:(BOOL)animated;

/**
 Deselects all selected items.
 */
- (void)clearSelectedItems;

/**
 Selects an item at the given index path.
 @param indexPath The index path of the item to select.
 @param animated Determines whether to animate the selection.
 @param scrollPosition The scroll position.
 */
- (void)selectItemAtIndexPath:(NSIndexPath * __nonnull)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition;

/**
 Deselects an item at the given index path.
 @param indexPath The index path of the item to deselect.
 @param animated Determines whether to animate the selection.
 */
- (void)deselectItemAtIndexPath:(NSIndexPath * __nonnull)indexPath animated:(BOOL)animated;

/**
 Returns a TKListVIewCell to be provided in the listView:cellForItemAtIndexPath:ndexPath delegate method.
 
 @param identifier A string identifier of the cell type.
 @param indexPath The index path of the item we need a cell for.
 */
- (id __nullable)dequeueReusableCellWithReuseIdentifier:(NSString * __nonnull)identifier forIndexPath:(NSIndexPath* __nonnull)indexPath;

/**
 Returns a header or footer view to be provided in the listView:viewForSupplementaryElementOfKind:atIndexPath:
 
 @param elementKind The element kind - header or footer.
 @param identifier A string identifier of the view type.
 @param indexPath The index path of the supplementary view.
 */
- (id __nullable)dequeueReusableSupplementaryViewOfKind:(NSString* __nonnull)elementKind withReuseIdentifier:(NSString * __nonnull)identifier forIndexPath:(NSIndexPath* __nonnull)indexPath;

/**
 Returns a TKListViewCell that should be used as load on demand cell when loadOnDemandMode is set to manual.
 @param indexPath The index path.
 */
- (TKListViewCell* __nullable)dequeueLoadOnDemandCellForIndexPath:(NSIndexPath* __nonnull)indexPath;

/**
 Registers a class to be used to represent load on demand cell in listview.
 @param cellClass The cell class.
 */
- (void)registerLoadOnDemandCell:(Class __nonnull)cellClass;

/**
 Registers a class to be used to represent cells in listview.
 @param cellClass The class of the UIView to represent a cell.
 @param identifier A string identifier of the cell type.
 */
- (void)registerClass:(Class __nonnull)cellClass forCellWithReuseIdentifier:(NSString * __nonnull)identifier;

/**
 Registers a class to be used to represent headers and footers.
 @param viewClass The class of the UIView to represent a header or footer.
 @param elementKind The element kind - header or footer.
 @param identifier A string identifier of the supplementary view type.
 */
- (void)registerClass:(Class __nonnull)viewClass forSupplementaryViewOfKind:(NSString * __nonnull)elementKind withReuseIdentifier:(NSString * __nonnull)identifier;

/**
 Registers a nib file to be used to represent cells in listview.
 @param nib The nib instance to represent a cell.
 @param identifier A string identifier of the cell type.
 */
- (void)registerNib:(UINib* __nullable)nib forCellReuseIdentifier:(NSString * __nonnull)identifier;

/**
 Registers a class to be used to represent headers and footers.
 @param nib The nib instance to represent a header or footer.
 @param elementKind The element kind - header or footer.
 @param identifier A string identifier of the supplementary view type.
 */
- (void)registerNib:(UINib* __nullable)nib forSupplementaryViewOfKind:(NSString* __nonnull)elementKind withReuseIdentifier:(NSString * __nonnull)identifier;

/**
 Returns the visible cell object at the specified index path.
 @param indexPath The index path for the cell.
 */
- (TKListViewCell* __nullable)cellForItemAtIndexPath:(NSIndexPath * __nonnull)indexPath;

/**
 Inserts new items at the specified index paths.
 @param indexPaths The index paths of the newly inserted items.
 */
- (void)insertItemsAtIndexPaths:(NSArray * __nonnull)indexPaths;

/**
 Moves an item from one location to another in the list view.
 @param indexPath The old index path.
 @param newIndexPath The new index path.
 */
- (void)moveItemAtIndexPath:(NSIndexPath * __nonnull)indexPath toIndexPath:(NSIndexPath * __nonnull)newIndexPath;

/**
 Deletes the items at the specified index paths.
 @param indexPaths The index paths of the deleted items.
 */
- (void)deleteItemsAtIndexPaths:(NSArray * __nonnull)indexPaths;

/**
 Reloads the items at the specified index paths.
 @param indexPaths The index paths of items to reload.
 */
- (void)reloadItemsAtIndexPaths:(NSArray * __nonnull)indexPaths;

/**
 Allows multiple insert/delete/reload/move calls to be animated.
 @param updates The updates to apply.
 @param completion Will be executed upon completion.
 */
- (void)performBatchUpdates:(void (^ __nullable)(void))updates completion:(void (^ __nullable)(BOOL finished))completion;

/**
 Returns the number of items conatined in specific section.
 @param section The index of the section.
 */
- (NSInteger)numberOfItemsInSection:(NSInteger)section;

/**
 Returns the index path for the item at the specified location.
 @param point The point where the item is located.
 */
- (NSIndexPath * __nullable)indexPathForItemAtPoint:(CGPoint)point;

/**
 Returns the index path for specific cell.
 @param cell The cell.
 */
- (NSIndexPath * __nonnull)indexPathForCell:(UICollectionViewCell * __nullable)cell;

/**
 Scrolls to specific item.
 @param indexPath The index path for the item.
 @param scrollPosition The scroll position.
 @param animated Determines whether to animate the scrolling.
 */
- (void)scrollToItemAtIndexPath:(NSIndexPath * __nonnull)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated;

/**
 Sets the scroll offset with the given amount in a horizontal and vertical direction by either using animation or not.
 @param contentOffset a CGPoint instance representing the horizontal and vertical amount of scroll offset to be applied.
 @param animated a bool value determining whether animation is to be used or not.
 */
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;

/**
 Notifies the list view that a new data requested on demand is ready to be shown.
 */
- (void)didLoadDataOnDemand;

/*
 Notifies the list view that a fresh data is available after a pull-to-refresh gesture takes place.
 */
- (void)didRefreshOnPull;

@end
