//
//  IdeabusPickView.m
//  Health
//
//  Created by WiFi@ on 2017/12/11.
//  Copyright © 2017年 WiFi@MBP. All rights reserved.
//

#import "IdeabusPickView.h"

#define kScreenFrame                    ([UIScreen mainScreen].bounds)

#define ShadeViewAlphaWhenShow          0.4
#define ShadeViewAlphaWhenHide          0

#define PickerBackViewAnimateDuration   0.3

#define PickerRowHieght                 35

#define PickerHeaderHieght              50

#define PickerBackViewPointX            0
#define PickerBackViewPointYWhenHide    kScreenFrame.size.height
#define PickerBackViewPointYWhenShow    (kScreenFrame.size.height - PickerBackViewHieght)
#define PickerBackViewWeight            kScreenFrame.size.width
#define PickerBackViewHieght            (PickerHeaderHieght + PickerHieght)

#define PickerPointX                    0
#define PickerPointY                    PickerHeaderHieght
#define PickerWeight                    kScreenFrame.size.width
#define PickerHieght                    PickerViewHeightTypeMiddle

#define HeaderButtonTitleFontSize       17
#define HeaderButtonMargin              15

#define CancelButtonPointX              0
#define CancelButtonPointY              0
#define CancelButtonWeight              PickerWeight*0.2
#define CancelButtonHieght              PickerHeaderHieght
#define CancelButtonTitleColor          [UIColor blackColor]

#define PickerTitlePointX               0
#define PickerTitlePointY               0
#define PickerTitleWeight               PickerWeight*0.4
#define PickerTitleHieght               PickerHeaderHieght
#define PickerTitleColor                [UIColor blackColor]

#define ConfirmButtonPointX             0
#define ConfirmButtonPointY             0
#define ConfirmButtonWeight             PickerWeight*0.2
#define ConfirmButtonHieght             PickerHeaderHieght
#define ConfirmButtonTitleColor         [UIColor blackColor]



BOOL isString(id obj) {
    return [obj isKindOfClass:[NSString class]];
}

BOOL isArray(id obj) {
    return [obj isKindOfClass:[NSArray class]];
}

typedef NS_ENUM(NSInteger, PickerViewHeightType) {
    PickerViewHeightTypeHeight  = 216,
    PickerViewHeightTypeMiddle  = 180,
    PickerViewHeightTypeLow     = 162
};

typedef NS_ENUM(NSInteger, PickerViewDataType) {
    PickerViewDataTypeForData,
    PickerViewDataTypeForDate,
    PickerViewDataTypeForCountry
};

@interface IdeabusPickView ()<UIPickerViewDelegate,UIPickerViewDataSource>
@property (nonatomic, copy  ) confirmBlock   confirmBlock;
@property (nonatomic, copy  ) cancelBlock    cancelBlock;
@property (nonatomic, copy  ) hideBlock      hideBlock;
@property (nonatomic, copy  ) changedBlock   changedBlock;
@property (nonatomic, copy  ) NSArray        *dataSource;
@property (nonatomic, copy  ) NSString       *selectedItem;         //Single Column of the selected item
@property (nonatomic, strong) NSMutableArray *selectedItems;        //Multiple Column of the selected item
@property (nonatomic, copy  ) NSString       *startingValue;         //Starting Value String
@property (nonatomic, strong) NSMutableArray *startingValues;        //Starting Value Array
@property (nonatomic, assign) BOOL           isSingleColumn;
@property (nonatomic, assign) BOOL           isDataSourceValid;
@property (nonatomic, strong) UIView         *pickerBackView;
@property (nonatomic, strong) UIButton       *shadeView;


@property (nonatomic, strong) NSString      *pickerTitleName;
@property (nonatomic, strong) NSString      *confirmButtonName;
@property (nonatomic, strong) NSString      *cancelButtonName;

@property (nonatomic, assign) PickerViewDataType pickerViewDataType;
@property (nonatomic)         UIDatePickerMode datePickerMode;
@property (nonatomic, strong) NSString      *dateFormat;
@property (nonatomic, strong) NSString      *showDate;
@property (nonatomic, strong) NSString      *minimumDate;
@property (nonatomic, strong) NSString      *maximumDate;
@property (nonatomic, copy  ) NSString      *selectedDate;         //Single Column of the selected date

@end

@implementation IdeabusPickView

#pragma mark - init
- (instancetype)initWithPlistName:(NSString *)plistName
                     selectedItem:(id)selectedData
                        titleName:(NSString *)titleName
                confirmButtonName:(NSString *)confirmButtonName
                     confirmBlock:(confirmBlock)confirmBlock
                 cancelButtonName:(NSString *)cancelButtonName
                      cancelBlock:(cancelBlock)cancelBlock
                        hideBlock:(hideBlock)hideBlock {
    NSString *path = [[NSBundle mainBundle] pathForResource:plistName ofType:@"plist"];
    NSArray *dataSource =[[NSArray alloc] initWithContentsOfFile:path];
    return [self initWithDataSource:dataSource selectedItem:selectedData titleName:titleName confirmButtonName:confirmButtonName confirmBlock:confirmBlock cancelButtonName:cancelButtonName cancelBlock:cancelBlock hideBlock:hideBlock];
}

- (instancetype)initWithDataSource:(NSArray *)dataSource
                      selectedItem:(id)selectedData
                         titleName:(NSString *)titleName
                 confirmButtonName:(NSString *)confirmButtonName
                      confirmBlock:(confirmBlock)confirmBlock
                  cancelButtonName:(NSString *)cancelButtonName
                       cancelBlock:(cancelBlock)cancelBlock
                         hideBlock:(hideBlock)hideBlock {
    self = [super initWithFrame:kScreenFrame];
    if (self) {
        self.pickerViewDataType = PickerViewDataTypeForData;
        self.dataSource = dataSource;
        self.pickerTitleName = titleName;
        self.confirmButtonName = confirmButtonName;
        self.cancelButtonName = cancelButtonName;
        self.confirmBlock = confirmBlock;
        self.cancelBlock = cancelBlock;
        self.hideBlock = hideBlock;
        if (isString(selectedData)) {
            self.startingValue = selectedData;
        } else if (isArray(selectedData)){
            self.startingValues = [selectedData mutableCopy];
        }
        [self initData];
        [self initView];
    }
    return self;
}

- (instancetype)initDatePickerWithMode:(UIDatePickerMode)mode
                            dateFormat:(NSString *)format
                              showDate:(NSString *)currentDate
                           minimumDate:(NSString *)minDate
                           maximumDate:(NSString *)maxDate
                             titleName:(NSString *)titleName
                     confirmButtonName:(NSString *)confirmButtonName
                          confirmBlock:(confirmBlock)confirmBlock
                      cancelButtonName:(NSString *)cancelButtonName
                           cancelBlock:(cancelBlock)cancelBlock
                             hideBlock:(hideBlock)hideBlock {
    self = [super initWithFrame:kScreenFrame];
    if (self) {
        self.pickerViewDataType = PickerViewDataTypeForDate;
        self.datePickerMode = mode;
        self.dateFormat = format;
        self.showDate = currentDate;
        self.minimumDate = minDate;
        self.maximumDate = maxDate;
        self.pickerTitleName = titleName;
        self.confirmButtonName = confirmButtonName;
        self.cancelButtonName = cancelButtonName;
        self.confirmBlock = confirmBlock;
        self.cancelBlock = cancelBlock;
        self.hideBlock = hideBlock;
    }
    [self initBackView];
    [self initPickerBackView];
    [self initPickerHeaderView];
    [self initDatePickerView];
    return self;
}

- (instancetype)initWithSelectedCountry:(NSString *)selectedCountry
                              titleName:(NSString *)titleName
                      confirmButtonName:(NSString *)confirmButtonName
                           confirmBlock:(confirmBlock)confirmBlock
                       cancelButtonName:(NSString *)cancelButtonName
                            cancelBlock:(cancelBlock)cancelBlock
                              hideBlock:(hideBlock)hideBlock {
    self = [super initWithFrame:kScreenFrame];
    if (self) {
        self.pickerViewDataType = PickerViewDataTypeForCountry;
        self.dataSource = [NSLocale ISOCountryCodes];
        self.pickerTitleName = titleName;
        self.confirmButtonName = confirmButtonName;
        self.cancelButtonName = cancelButtonName;
        self.confirmBlock = confirmBlock;
        self.cancelBlock = cancelBlock;
        self.hideBlock = hideBlock;
        self.startingValue = selectedCountry?:[NSLocale currentLocale].countryCode;
        [self initData];
        [self initView];
    }
    return self;
}

#pragma mark - initData
- (void)initData {
    if (self.dataSource == nil || self.dataSource.count == 0) {
        self.isDataSourceValid = NO;
        return;
    } else {
        self.isDataSourceValid = YES;
    }
    
    __weak typeof(self) weakSelf = self;
    [self.dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        static Class cls;
        if (idx == 0) {
            cls = [obj class];
            
            if (isArray(obj)) {
                weakSelf.isSingleColumn = NO;
            } else if (isString(obj)) {
                weakSelf.isSingleColumn = YES;
            } else {
                weakSelf.isDataSourceValid = NO;
                return;
            }
        } else {
            if (isArray(obj)) {
                if (((NSArray *)obj).count == 0) {
                    weakSelf.isDataSourceValid = NO;
                    *stop = YES;
                    return;
                } else {
                    for (id subObj in obj) {
                        if (!isString(subObj)) {
                            weakSelf.isDataSourceValid = NO;
                            *stop = YES;
                            return;
                        }
                    }
                }
            }
        }
    }];
    
    if (self.isSingleColumn) {
        if (self.startingValue == nil) {
            self.startingValue = self.dataSource.firstObject;
        }
    } else {
        self.selectedItems = [NSMutableArray array];
        BOOL isSelectedItemsValid = YES;
        for (id obj in self.startingValues) {
            if (!isString(obj)) {
                isSelectedItemsValid = NO;
                break;
            }
        }
        
        if (self.startingValues == nil || self.startingValues.count != self.dataSource.count || !isSelectedItemsValid) {
            NSMutableArray *mutableArray = [NSMutableArray array];
            for (NSArray* componentItem in self.dataSource) {
                [mutableArray addObject:componentItem.firstObject];
            }
           self.startingValues = [NSMutableArray arrayWithArray:mutableArray];
        }

    }
    
}

#pragma mark - initView
- (void)initView {
    [self initBackView];
    [self initPickerBackView];
    [self initPickerHeaderView];
    [self initPickerView];
}

-(void)initBackView {
    self.shadeView = [[UIButton alloc] initWithFrame:self.frame];
    self.shadeView.userInteractionEnabled = YES;
    [self.shadeView addTarget:self action:@selector(shadowViewClick:) forControlEvents:UIControlEventTouchUpInside];
    self.shadeView.backgroundColor = [UIColor blackColor];
    self.shadeView.alpha = ShadeViewAlphaWhenHide;
    [self addSubview:self.shadeView];
}

- (void)initPickerBackView {
    self.pickerBackView = [[UIView alloc] initWithFrame:CGRectMake(PickerBackViewPointX, PickerBackViewPointYWhenHide, PickerBackViewWeight, PickerBackViewHieght)];
    self.pickerBackView.backgroundColor = [UIColor whiteColor];
    [self addSubview:self.pickerBackView];
}

- (void)initPickerHeaderView {
    CGRect cancelButtonFrame  = CGRectMake(CancelButtonPointX, CancelButtonPointY, CancelButtonWeight, CancelButtonHieght);
    
    CGRect pickerTitleFrame   = CGRectMake(PickerTitlePointX, PickerTitlePointY, PickerTitleWeight, PickerTitleHieght);
    
    CGRect confirmButtonFrame = CGRectMake(ConfirmButtonPointX, ConfirmButtonPointY, ConfirmButtonWeight, ConfirmButtonHieght);
    
    UIButton *cancelButton = [[UIButton alloc] initWithFrame:cancelButtonFrame];
    [cancelButton setTitle:self.cancelButtonName forState:UIControlStateNormal];
    [cancelButton setTitleColor:CancelButtonTitleColor forState:UIControlStateNormal];
    [cancelButton addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside];
    cancelButton.titleLabel.font = [UIFont systemFontOfSize:HeaderButtonTitleFontSize];
    cancelButton.titleLabel.adjustsFontSizeToFitWidth = YES;
    cancelButton.center = CGPointMake(self.pickerBackView.frame.size.width*0.13, CancelButtonHieght*0.5);
    [self.pickerBackView addSubview:cancelButton];
    
    UILabel *pickerTitle = [[UILabel alloc] initWithFrame:pickerTitleFrame];
    pickerTitle.text = self.pickerTitleName;
    pickerTitle.font = [UIFont systemFontOfSize:HeaderButtonTitleFontSize];
    pickerTitle.textAlignment = NSTextAlignmentCenter;
    pickerTitle.adjustsFontSizeToFitWidth = YES;
    pickerTitle.center = CGPointMake(self.pickerBackView.frame.size.width*0.5, PickerTitleHieght*0.5);
    [self.pickerBackView addSubview:pickerTitle];
    
    UIButton *confirmButton = [[UIButton alloc] initWithFrame:confirmButtonFrame];
    [confirmButton setTitle:self.confirmButtonName forState:UIControlStateNormal];
    [confirmButton setTitleColor:ConfirmButtonTitleColor forState:UIControlStateNormal];
    [confirmButton addTarget:self action:@selector(confirm) forControlEvents:UIControlEventTouchUpInside];
    confirmButton.titleLabel.font = [UIFont systemFontOfSize:HeaderButtonTitleFontSize];
    confirmButton.titleLabel.adjustsFontSizeToFitWidth = YES;
    confirmButton.center = CGPointMake(self.pickerBackView.frame.size.width*0.87, ConfirmButtonHieght*0.5);
    [self.pickerBackView addSubview:confirmButton];
}

- (void)initPickerView {
    self.pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(PickerPointX, PickerPointY, PickerWeight, PickerHieght)];
        
    [self.pickerBackView addSubview:self.pickerView];
    
    if (!self.isDataSourceValid)  return;
    
    self.pickerView.delegate = self;
    self.pickerView.dataSource = self;
    
    [self pickerViewSelectRowWithAnimated:NO];
    
}

- (void)pickerViewSelectRowWithAnimated:(BOOL)animated {
    __weak typeof(self) weakSelf = self;
    if (self.isSingleColumn) {
        [self.dataSource enumerateObjectsUsingBlock:^(NSString *rowItem, NSUInteger rowIdx, BOOL *stop) {
            if ([weakSelf.startingValue isEqualToString:rowItem]) {
                weakSelf.selectedItem = rowItem;
                [weakSelf.pickerView selectRow:rowIdx inComponent:0 animated:animated];
                *stop = YES;
            }
        }];
    } else {
        [self.selectedItems removeAllObjects];
        [self.dataSource enumerateObjectsUsingBlock:^(NSArray *rowItems, NSUInteger rowIdx, BOOL *stop) {
            [rowItems enumerateObjectsUsingBlock:^(NSString *rowItem, NSUInteger idx, BOOL *stop) {
                if ([[weakSelf.startingValues objectAtIndex:rowIdx] isEqualToString:rowItem]) {
                    [weakSelf.selectedItems addObject:rowItem];
                    [weakSelf.pickerView selectRow:idx inComponent:rowIdx animated:animated];
                    *stop = YES;
                }
            }];
        }];
    }
}

- (void)initDatePickerView {
    self.datePickerView = [[UIDatePicker alloc] initWithFrame:CGRectMake(PickerPointX, PickerPointY, PickerWeight, PickerHieght)];
    
    self.selectedItems = [NSMutableArray array];
    
    self.datePickerView.datePickerMode = self.datePickerMode;
    self.datePickerView.calendar = [[NSCalendar alloc]
                                    initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    if (@available(iOS 13.4, *)) {
        self.datePickerView.preferredDatePickerStyle = UIDatePickerStyleWheels;
    }
    
    NSString *new = [self dateNSDateToNSString:[NSDate date] withFormat:self.dateFormat];
    
    NSString *maximumDate = (self.maximumDate.length > 0)?self.maximumDate:new;
    
    NSString *showDate = (self.showDate.length > 0)?self.showDate:new;

    self.datePickerView.maximumDate = [self dateNSStringToNSDate:maximumDate withFormat:self.dateFormat];
    self.datePickerView.date = [self dateNSStringToNSDate:showDate withFormat:self.dateFormat];
    if (self.minimumDate.length > 0) {
        self.datePickerView.minimumDate = [self dateNSStringToNSDate:self.minimumDate withFormat:self.dateFormat];
    }
    
    [self.datePickerView addTarget:self action:@selector(dateChanged:) forControlEvents:UIControlEventValueChanged];
    
    [self.pickerBackView addSubview:self.datePickerView];
}

#pragma mark - 時間處理工具
/**
 文字轉時間

 @param str 文字
 @param format 時間格式
 @return 時間
 */
- (NSDate *)dateNSStringToNSDate:(NSString *)str
                      withFormat:(NSString *)format {
    NSDateFormatter *dFormatter = [NSDateFormatter new];
    [dFormatter setCalendar: [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian]];
    [dFormatter setTimeZone:[NSTimeZone systemTimeZone]];
    [dFormatter setDateFormat:format];
    NSDate *datetime = [dFormatter dateFromString:str];
    return datetime;
}

/**
 時間轉文字

 @param date 時間
 @param format 時間格式
 @return 文字
 */
- (NSString *)dateNSDateToNSString:(NSDate *)date
                        withFormat:(NSString *)format {
    NSDateFormatter *dFormatter = [NSDateFormatter new];
    [dFormatter setCalendar: [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian]];
    [dFormatter setTimeZone:[NSTimeZone systemTimeZone]];
    [dFormatter setDateFormat:format];
    return [dFormatter stringFromDate:date];
}

#pragma mark - Action
-(void)shadowViewClick:(UIButton *)btn {
    [self hide:^{
        if (self.hideBlock) {
            self.hideBlock();
        }
    }];
}

- (void)confirm {
    [self hide:^{
        if(self.confirmBlock) {
            switch (self.pickerViewDataType) {
                case PickerViewDataTypeForDate: {
                    self.selectedDate = self.selectedDate?:[self dateNSDateToNSString:self.datePickerView.date withFormat:self.dateFormat];
                    self.selectedItems[0] = self.selectedDate;
                    self.selectedItems[1] = self.datePickerView.date;
                    self.confirmBlock([self.selectedItems copy]);
                }
                    break;
                case PickerViewDataTypeForData: {
                    if (self.isSingleColumn) {
                        self.confirmBlock([self.selectedItem copy]);
                    } else {
                        self.confirmBlock([self.selectedItems copy]);
                    }
                }
                    break;
                case PickerViewDataTypeForCountry:
                    
                    break;
                default:
                    break;
            }
        }
    }];
}

- (void)cancel {
    [self hide:^{
        if(self.cancelBlock) {
            switch (self.pickerViewDataType) {
                case PickerViewDataTypeForData: {
                    self.selectedDate = self.selectedDate?:[self dateNSDateToNSString:self.datePickerView.date withFormat:self.dateFormat];
                    self.selectedItems[0] = self.selectedDate;
                    self.selectedItems[1] = self.datePickerView.date;
                    self.cancelBlock([self.selectedItems copy]);
                }
                    break;
                case PickerViewDataTypeForDate: {
                    if (self.isSingleColumn) {
                        self.cancelBlock([self.selectedItem copy]);
                    } else {
                        self.cancelBlock([self.selectedItems copy]);
                    }
                }
                    break;
                case PickerViewDataTypeForCountry:
                    
                    break;
                default:
                    break;
            }
        }
    }];
}

- (void)hide:(void (^)(void))completion{
    [UIView animateWithDuration:PickerBackViewAnimateDuration
                     animations:^{
                         self.shadeView.alpha = ShadeViewAlphaWhenHide;
                         self.pickerBackView.frame = CGRectMake(PickerBackViewPointX, PickerBackViewPointYWhenHide, PickerBackViewWeight, PickerBackViewHieght);
                     }
                     completion:^(BOOL finished) {
                         if (finished) {
                             if (completion) {
                                 completion();
                             }
                             dispatch_async(dispatch_get_main_queue(), ^{
                                 [self removeFromSuperview];
                             });
                             
                         }
                     }
     ];
}

- (void)changed:(changedBlock)completion {
    self.changedBlock = ^(id item) {
        completion(item);
    };
}

- (void)show {
    [[UIApplication sharedApplication].keyWindow addSubview:self];
    [UIView animateWithDuration:PickerBackViewAnimateDuration
                     animations:^{
                         self.shadeView.alpha = ShadeViewAlphaWhenShow;
                         self.pickerBackView.frame = CGRectMake(PickerBackViewPointX, PickerBackViewPointYWhenShow, PickerBackViewWeight, PickerBackViewHieght);
                     }
                     completion:nil
     ];
}

#pragma mark - UIDatePickerAction
- (void)dateChanged:(UIDatePicker *)pickerView {
    self.selectedDate = [self dateNSDateToNSString:pickerView.date withFormat:self.dateFormat];
    self.selectedItems[0] = self.selectedDate;
    self.selectedItems[1] = pickerView.date;
    if (self.changedBlock) {
        self.changedBlock([self.selectedItems copy]);
    }
}

#pragma mark - UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    if (self.isSingleColumn) {
        return 1;
    } else {
        return self.dataSource.count;
    }
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
    return PickerRowHieght;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    if (self.isSingleColumn) {
        return self.dataSource.count;
    } else {
        return ((NSArray*)self.dataSource[component]).count;
    }
}

#pragma mark - UIPickerViewDelegate
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    UILabel *pickerLabel = (UILabel*)view;
    if (!pickerLabel) {
        pickerLabel = [UILabel new];
    }
    pickerLabel.text = [self pickerView:pickerView titleForRow:row forComponent:component];
    [pickerLabel sizeToFit];
    return pickerLabel;
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
    if (self.isSingleColumn) {
        return self.dataSource[row];
    } else {
        return ((NSArray*)self.dataSource[component])[row];
    }
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    if (self.isSingleColumn) {
       self.selectedItem = self.dataSource[row];
    } else {
        self.selectedItems[component] = ((NSArray*)self.dataSource[component])[row];
    }
    if (self.changedBlock) {
        if (self.isSingleColumn) {
            self.changedBlock([self.selectedItem copy]);
        } else {
            self.changedBlock([self.selectedItems copy]);
        }
    }
}

@end
