//
//  ThingsViewController.m
//  kneet
//
//  Created by Jason Lee on 3/10/15.
//  Copyright (c) 2015 ntels. All rights reserved.
//
#import "JDObject.h"

#import "RequestHandler.h"
#import "JDJSONModel.h"
#import "DeviceModel.h"


#import "CustomLabel.h"
#import "CustomImageView.h"
#import "CustomTextField.h"
#import "CustomLabelButton.h"
#import "CustomButton.h"
#import "JYRefreshController.h"
#import "WYPopoverController.h"
#import "ImageUtil.h"

#import "UIImageView+WebCache.h"
#import "UIButton+WebCache.h"

#import "CommandClassControlView.h"
#import "ThingsDetailViewController.h"

#import "ThingsViewController.h"
#import "ThingsAddViewController.h"
#import "ThingsAddStartViewController.h"
#import "CustomTableView.h"
#import "JYPullToRefreshController.h"
#import "HomeMemberViewController.h"
#import "HomeHubUpdateGuideViewController.h"
#import "HomeHubUpdateStartViewController.h"
#import "MultiHomeHubViewController.h"

#import "ThingsForcedDelViewController.h"
#import "ThingsGeneralDelViewController.h"

#import "HomeHubSelectPopupView.h"

#define kfThingsTableViewCellHeight 100.0f
#define kiCellInset 5
#define kiCellItem 2
#define kiCellRatio 74
#define kiCellDivision 3

/**
 
 Head Text Color     : kUITextColor01
 Device 명 Text Color : kUITextColor01
 Device 상태표시 Text Color
 - 열림 : kUITextColor02
 - 닫힘 : kUITextColor01
 
 장치 추가 Text Color : kUITextColor01
 
 (이미지 명)
 디바이스 아이콘 bg
 - Default : img_thing_icon_bg_default
 - Active  : img_thing_icon_bg_active
 
 도어 컨텍트 센서 : 40102
 가스 밸브      : 40108
 다윈 플러그     : 40402
 
 **/

@interface ThingsCollectionViewCell () {
    NSInteger _commandStatusElapsedTime;
    
}

@property (weak, nonatomic) NSIndexPath *indexPath;

@end

@implementation ThingsCollectionViewCell

- (void)awakeFromNib {
    _pcontainerView.hidden = NO;
}

- (void)startProgressAni {
    
    //chagne button image
    [UIView animateWithDuration:0.5f delay:0.0f options:UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveLinear animations:^{
        _imgvProgress.transform = CGAffineTransformMakeRotation(M_PI);
    } completion:nil];
}

- (void)stopProgressAni {
    [UIView animateWithDuration:0.0f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear  animations:^{
        _imgvProgress.transform = CGAffineTransformMakeRotation(0);
    } completion:nil];
}

@end

@implementation ThingsAddCollectionCell

@end


@interface ThingsViewController () <UICollectionViewDataSource, UICollectionViewDelegate> {
    NSMutableArray *_deviceList;
    NSMutableArray *_deviceReOrderList;
    NSString *_pagingId, *_pagingType;
    BOOL _isNotFirstLoading, _isReOrderMode, _isDeleteMode;
    
    NSMutableArray<DeviceModel> *_commandArray;
    NSTimer *_devicesBackgroundTimer;
    NSTimer *_deviceCommandsBackgroundTimer;
    
    NSInteger _deviceFlag;
    UIPanGestureRecognizer *_moveCellGesture;
    
    NSIndexPath *_dragIndexPath;
    ThingsCollectionViewCell *_moveCell;
    
    NodeListModel *_nodeListData;
    DeviceModel *_selectHub;
    DataSelectListModel *_homeHubList;
    
    
    UIGestureRecognizer *_titleBarClick;
    
    BOOL checkMaster;
    BOOL checkUpdate;
}

@property (strong, nonatomic) JYPullToRefreshController *refreshController;
@property (nonatomic, strong) UIView *cellFakeView;

@end


#pragma mark - Class Definition

@implementation ThingsViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    checkMaster = YES ;
    checkUpdate = YES ;
    
    [self initProperties];
    [self initUI];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}


- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    [self prepareViewDidLoadRefreshPopup];
}


- (void)viewWillDisappear:(BOOL)animated {
    
    if (_deviceCommandsBackgroundTimer) {
        [_deviceCommandsBackgroundTimer invalidate];
        _deviceCommandsBackgroundTimer = nil;
    }
    
    [self releaseDevicesTimer];
}


- (void)initProperties {
    _deviceFlag = IS_IPHONE_6P ? 2 : 2;
}


- (void)initUI {
    
    //set tableview option
    _collectionView.delegate = self;
    _collectionView.dataSource = self;
    _collectionView.backgroundColor = [UIColor clearColor];
    _collectionView.alwaysBounceVertical = YES;
    
    _lblEditMode.hidden = YES;
    
    [_imgvLogo sd_setImageWithURL:[NSURL URLWithString:[JDFacade facade].loginUser.msoImageUrl] placeholderImage:nil options:SDWebImageRefreshCached];
    
    _imgvLogo.contentMode = UIViewContentModeScaleAspectFit;
    _imgvLogo.hidden = YES;
    
    [self viewOfflineSetDeviceModel:_selectHub];
    
    [_btnClose setHidden:YES];
    [_btnOption setHidden:NO];
    [_viewEditMode setHidden:YES];
    
    //    [self setThingsPopoverOptions];
    [self setMoreBtnArray];
    [self initRefreshController];
}

- (void)viewOfflineSetDeviceModel:(DeviceModel*)deviceModel {
    
    if (deviceModel == nil) {
        deviceModel = [[JDFacade facade].loginUser getHomeHub];
    }
    
    BOOL showOffline = NO ;

    //_btnOfflineMulti.hidden = [JDFacade facade].loginUser.deviceList.count <= 1;
    
    if ([JDFacade facade].loginUser.deviceList.count > 1) {
        
        NSInteger offlineCount = 0;
        NSString *offlineName = @"";
        
        for (DeviceModel *deviceModel in [JDFacade facade].loginUser.deviceList) {
            
            //NSLog(@"isDeviceOnlined : %d, isDeviceConn : %d, is : %d",
            //                  deviceModel.isDeviceOnlined,
            //                  deviceModel.isDeviceConn,
            //                  !deviceModel.isDeviceOnlined || !deviceModel.isDeviceConn);
            //
            if (!deviceModel.isDeviceOnlined || !deviceModel.isDeviceConn) {
                offlineCount++;
                
                if (offlineName.length == 0) {
                    offlineName = deviceModel.prdUserName != nil ? deviceModel.prdUserName : deviceModel.prdName;
                }
            }
        }
        
        
        if (offlineCount == 1) {
            
            _lblOffline.text = [NSString stringWithFormat:@"%@ 오프라인", offlineName];
        }
        else if(offlineCount > 1) {
            
            
            _lblOffline.text = [NSString stringWithFormat:@"%@ 외 %ld건 오프라인", offlineName, offlineCount - 1];
        }

        showOffline = offlineCount > 0;
        
    }
    else {
        
        if (deviceModel != nil && (!deviceModel.isDeviceOnlined || !deviceModel.isDeviceConn)) {
            
            showOffline = YES;
            NSString *name = deviceModel.prdUserName != nil ? deviceModel.prdUserName : deviceModel.prdName;
            _lblOffline.text = [NSString stringWithFormat:@"%@ 오프라인", name];
        }

        //        NSLog(@"showOffline : %d %d %d", deviceModel.isDeviceOnlined,deviceModel.isDeviceConn, showOffline);
    }

    _viewHeight.constant = showOffline ? 54 : 0;
}


- (void)initRefreshController {
    //set refresh controls
    __weak typeof(self) weakSelf = self;
    self.refreshController = [[JYPullToRefreshController alloc] initWithScrollView:self.collectionView];
    self.refreshController.pullToRefreshHandleAction = ^{
        [weakSelf requestDeviceList:@YES];
    };
}


- (void)setThingsPopoverOptions {
    //
    //    //set Popover Contents
    //    __weak typeof(self) weakSelf = self;
    //    _popooverOptionArray = [[NSMutableArray alloc] init];
    //
    //    [_popooverOptionArray addObject:@{@"menuName" : NSLocalizedString(@"새로고침", @"새로고침"),
    //                                      @"iconName": @"img_bg_morepopup_icon_refresh",
    //                                      @"target": weakSelf,
    //                                      @"selector": [NSValue valueWithPointer:@selector(refreshDeviceList)]}];
    //
    ////    if ([JDFacade facade].loginUser.level == 90) {//권한
    ////        [_popooverOptionArray addObject:@{@"menuName" : NSLocalizedString(@"추가", @"추가"),
    ////                                          @"iconName": @"tp_01_img_bg_morepopup_icon_group_deviceadd",
    ////                                          @"target": weakSelf,
    ////                                          @"selector": [NSValue valueWithPointer:@selector(addNewDevice)]}];
    ////
    ////        [_popooverOptionArray addObject:@{@"menuName" : NSLocalizedString(@"삭제", @"삭제"),
    ////                                          @"iconName": @"tp_01_img_bg_morepopup_icon_group_deviceadd",
    ////                                          @"target": weakSelf,
    ////                                          @"selector": [NSValue valueWithPointer:@selector(toggleEditMode)]}];
    ////    }
}


//버튼 말풍선 셋팅
- (void)setMoreBtnArray {
    
    _moreBtnArray = [NSMutableArray array];
    
    if (![[JDFacade facade].loginUser hasHomeHub]) {
        [_btnOption setHidden:YES];
    }
    
    BOOL isOnlineHomeHub = [[JDFacade facade].loginUser onlineHomeHubFromSelectedHub:_selectHub];//멀티일땐 전체에서체크
    
    //멀티이고 하나 선택한 경우
    if (_selectHub != nil)
        isOnlineHomeHub = _selectHub.isDeviceOnlined && _selectHub.isDeviceConn;
    
    if([[JDFacade facade].loginUser.gradeCode isEqualToString:KNEET_MEMBER_MASTER]) {
        for (int i = 0; i < 4; i++) {
            MoreBtnModel *btnModel;
            switch (i) {
                case 0:{
                    btnModel = [[MoreBtnModel alloc] initWithTyep:ReOrder isEnable:YES];
                    btnModel.enable = [_nodeListData isCanReOrder] && isOnlineHomeHub;
                }
                    break;
                case 1:{
                    btnModel = [[MoreBtnModel alloc] initWithTyep:Add isEnable:YES];
                    btnModel.enable = [_nodeListData isCanAddNode] && isOnlineHomeHub;
                }
                    break;
                case 2:{
                    btnModel = [[MoreBtnModel alloc] initWithTyep:Del isEnable:YES];
                    btnModel.enable = [_nodeListData isCanDelNode] && isOnlineHomeHub;
                }
                    break;
                case 3:
                    btnModel = [[MoreBtnModel alloc] initWithTyep:Refresh isEnable:YES];
                    break;
                    
                default:
                    break;
            }
            
            [_moreBtnArray addObject:btnModel];
        }
    }
    else {
        MoreBtnModel *btnModel = [[MoreBtnModel alloc] initWithTyep:Refresh isEnable:YES];
        [_moreBtnArray addObject:btnModel];
    }
}


- (void)updateHomeHubStatusToDevices {
    [self updateTitle];
    
    for (DeviceModel *device in _deviceList) {
        device.onlineState = [JDFacade facade].loginUser.homehubOnlineState;
    }
    [_collectionView reloadData];
}


- (void)prepareViewDidLoadRefreshPopup {
    
    checkMaster = [[[JDFacade facade] objectForKeyFromUserDefaults:USDEF_POPUP_MASTER] boolValue];
    checkUpdate = [[[JDFacade facade] objectForKeyFromUserDefaults:USDEF_POPUP_UPDATE] boolValue];
    
    [self checkProcess];
    
    [self updateTitle];
    
    [self fetchDevicesFromServer];
    
}


- (void)fetchDevicesFromServer {
    
    [self performSelector:@selector(requestHomeHubList) withObject:nil afterDelay:0.0f];
    [self performSelector:@selector(requestDeviceList:) withObject:@YES afterDelay:0.0f];
}



#pragma mark - check
//사용하기전 체크해야 하는 프로세스들
- (void)checkProcess {
    
    NSMutableArray<ContractGroupModel> *ctrtGrpList = [JDFacade facade].loginUser.ctrtGrpList;
    ContractGroupModel *ctrtGrp = ctrtGrpList.count > 0 ? [ctrtGrpList objectAtIndex:0] : nil;
    
    //test
    //    if (checkPhone)
    //        [JDFacade facade].loginUser.phoneAuthYn = @"N";
    //    if (checkMaster)
    //        [JDFacade facade].loginUser.ctrtGrp.masterTransferPopupYn = @"Y";
    //    if (checkUpdate)
    //        [JDFacade facade].loginUser.ctrtGrp.firmwareUpdateYn = @"Y";
    
    
    //    //휴대폰 번호 유효성 체크
    //    if (checkPhone && [JDFacade facade].loginUser.phoneAuthYn
    //        && ![[JDFacade facade].loginUser.phoneAuthYn boolValue]) {
    //
    //        checkPhone = NO;
    //        //vc dissmiss 된 후에 띄워야함
    //        [self performSelector:@selector(precessPhoneAuth) withObject:nil afterDelay:1.0f];
    //    }
    //마스터 권한 양도 수락
    if(checkMaster && ctrtGrp != nil && [ctrtGrp.masterTransferPopupYn boolValue]) {
        
        [[JDFacade facade] storeObjectToUserDefaults:@(NO) forKey:USDEF_POPUP_MASTER];
        [self performSelector:@selector(precessMasterTransfer) withObject:nil afterDelay:1.0f];
    }
    //홈허브 업데이트 건
    else if(checkUpdate && ctrtGrp != nil && [ctrtGrp.firmwareUpdateYn boolValue]) {
        
        [[JDFacade facade] storeObjectToUserDefaults:@(NO) forKey:USDEF_POPUP_UPDATE];
        [self performSelector:@selector(precessUpdateFirmware) withObject:nil afterDelay:1.0f];
    }
    
}

- (void)precessMasterTransfer {
    
    [[JDFacade facade] confirmTitle:@"알림"
                            message:@"마스터 권한을 양도했습니다. 수락하시겠습니까?"
                         btnOKLabel:@"예"
                     btnCancelLabel:@"아니요"
                         completion:^(CustomAlertView *alertView, NSInteger buttonIndex) {
                             
                             [self requestGradeAccept:buttonIndex == 0];
                         }];
}

- (void)precessUpdateFirmware {
    
    [[JDFacade facade] confirmTitle:@"알림"
                            message:@"홈허브를 업데이트할 수 있습니다. 지금 진행하시겠습니까?"
                         btnOKLabel:@"지금"
                     btnCancelLabel:@"나중에"
                         completion:^(CustomAlertView *alertView, NSInteger buttonIndex) {
                             
                             if (buttonIndex == 0) {
                                 
                                 //멀티
                                 MultiHomeHubViewController *vc = [CommonUtil instantiateViewControllerWithIdentifier:@"MultiHomeHubViewController" storyboardName:@"Main"];;
                                 vc.closeWhenOperationComplite = YES;
                                 
                                 UIViewController *viewController = vc;
                                 
                                 //단일
                                 if (![JDFacade facade].loginUser.isMultiHomeHub) {
                                     
                                     HomeHubUpdateGuideViewController *vc = [CommonUtil instantiateViewControllerWithIdentifier:@"HomeHubUpdateGuideViewController" storyboardName:@"HomeHub"];
                                     vc.updateType = UPDATE_ALL;
                                     vc.hubInfo = [[JDFacade facade].loginUser getHomeHub];
                                     vc.closeWhenOperationComplite = YES;
                                     
                                     viewController = vc;
                                 }
                                 
                                 UINavigationController *m_navi =[[UINavigationController alloc]initWithRootViewController:viewController];
                                 
                                 [self presentViewController:m_navi animated:YES completion:nil];
                             }
                             
                         }];
}


#pragma mark - api
//자동로그인 요청
- (void)requestAutoLogin {;
    
    LoginModel *tmpInfo = [[LoginModel alloc] init];
    tmpInfo.memberId = [[JDFacade facade] objectForKeyFromKeychain:USDEF_SESSION_LOGIN_ID];
    tmpInfo.authToken = [[JDFacade facade] objectForKeyFromKeychain:USDEF_SESSION_AUTOTOKEN];
    
    SocketRequestModel *request = [[SocketRequestModel alloc] initWithMsgType:MSG_TYPE_AUTO_LOGIN];
    NSDictionary *param = @{@"Authorization": tmpInfo.authorization,
                            @"device_token": [JDFacade facade].APNSToken ? [JDFacade facade].APNSToken : ksEmptyString,
                            @"os_type": MOBILE_DEVICE_TYPE};
    
    [request setRequestMsg:param];
    [self sendDataToSocket:request modelClass:[LoginModel class] isLoading:YES];
}


//홈그룹 멤버 권한 양도 수락 거절
- (void)requestGradeAccept:(BOOL)accept{
    
    NSDictionary *parameter = @{@"status":accept ? @"T" : @"C"};
    
    NSString *path = [[JDFacade facade] getUrlWithCustGroupIDAndMemberID:API_PUT_HOMEGROUP_GRADE];
    
    [[RequestHandler handler] sendAsyncPutRequestAPIPath:path
                                              parameters:parameter
                                              modelClass:[JDJSONModel class] completion:^(id responseObject) {
                                                  
                                                  [self requestAutoLogin];
                                                  
                                              } failure:^(id errorObject) {
                                                  
                                                  JDErrorModel *error = (JDErrorModel *)errorObject;
                                                  [[JDFacade facade] alert:error.errorMessage];
                                                  
                                              }];
}


//제어를 요청한 장치상태를 조회함.
- (void)requestPollingCommandStatusOfDeviceInBackground:(DeviceModel *)device {
    if (!_commandArray) {
        _commandArray = (NSMutableArray<DeviceModel> *)[[NSMutableArray alloc] init];
    }
    
    __block BOOL isStatusChanged = NO;
    if (device && [device isKindOfClass:[DeviceModel class]]) {//validate, aleady have,
        if (![_commandArray objectByUsingPredicateFormat:@"deviceId == %@ && nodeId == %@", device.deviceId, device.nodeId]) {//일치하는 디바이스가 있을 경우, 추가하지 않음.
            [_commandArray addObject:device];
            
            isStatusChanged = YES;
        }
    }
    
    if (_commandArray.count) {
        
        NSMutableString *pathParams = [[NSMutableString alloc] init];
        for (DeviceModel *pDevice in _commandArray) {
            NSString *prefix = [pathParams isEmptyString] ? ksEmptyString : @",";
            [pathParams appendFormat:@"%@%@_%@", prefix, pDevice.deviceId, pDevice.nodeId];
        }
        
        //20
        NSString *path = [NSString stringWithFormat:API_GET_DEVICE_NODE_STATUS, pathParams];
        
        dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{//RUN to background thread
            NodeListModel *fdevices = [[RequestHandler handler] sendSyncGetRequestAPIPath:path parameters:nil
                                                                               modelClass:[NodeListModel class] showLoadingView:YES];
            
            if (fdevices && fdevices.nodes && fdevices.nodes.count) {
                
                [_commandArray enumerateObjectsUsingBlock:^(DeviceModel *rdevice, NSUInteger idx, BOOL * _Nonnull stop) {
                    
                    DeviceModel *matchedDevice = (DeviceModel *)[fdevices.nodes objectByUsingPredicateFormat:@"deviceId == %@ && nodeId == %@", rdevice.deviceId, rdevice.nodeId];
                    
                    //실행 여부 및 10초 경과 확인
                    BOOL isOverTimeLimit = [self elapsedSecondsFromNow:rdevice] > 10;
                    
                    //실행 여부 확인
                    NSInteger elapsedTime = [self elapsedSecondsFrom:rdevice to:matchedDevice];
                    BOOL hasChangedStatus = elapsedTime > 0;
                    
                    rdevice.isRequesting = [rdevice.contentValue isEqualToString:matchedDevice.contentValue] && !hasChangedStatus && !isOverTimeLimit;
                    
                    //TODO - home hub check
                    //                    rdevice.requestTime = matchedDevice.requestTime;
                    //                    rdevice.collectTime = matchedDevice.collectTime;
                    rdevice.onlineState = matchedDevice.onlineState;
                    
                    if (!rdevice.isRequesting || !rdevice.isOnline || ![JDFacade facade].loginUser.isHomehubOnline) {//정상적으로 변경됨.
                        rdevice.contentValue = matchedDevice.contentValue;
                        [_commandArray removeObject:rdevice];
                        
                        isStatusChanged = YES;
                    }
                    
#ifdef DEBUG_MODE
                    NSLogInfo(@"==########== device command status = %@, elapsedTime = %zd ==########==", [JDFacade facade].loginUser.homehubOnlineState, elapsedTime);
#endif
                }];
            } else {//
                NSLog(@"no devices");
            }
            
            if (_commandArray.count) {//커맨드 실행 중인 디바이스가 있을 경우,
                //schedul timer.
                if (!_deviceCommandsBackgroundTimer) {
                    _deviceCommandsBackgroundTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(requestPollingCommandStatusOfDeviceInBackground:) userInfo:nil repeats:YES];
                }
            } else {
                [_deviceCommandsBackgroundTimer invalidate];
                _deviceCommandsBackgroundTimer = nil;
            }
            
            //리스트와 상세의 상태를 계속 매핑해줌.
            [self matchDeviceListWithOnCommandsDevices];
            
            //변화가 있을 경우, 컬렉션뷰를 리로드
            if (isStatusChanged) {
                [_collectionView reloadData];
                
                ThingsDetailViewController *vc = (ThingsDetailViewController *)[JDFacade facade].currentViewController;
                if ([vc isKindOfClass:[ThingsDetailViewController class]]) {
                    [vc.tableView reloadData];
                }
            }
        });
    }
}

-(void)requestDeviceControl
{
    [_collectionView reloadData];
    
    ThingsDetailViewController *vc = (ThingsDetailViewController *)[JDFacade facade].currentViewController;
    if ([vc isKindOfClass:[ThingsDetailViewController class]]) {
        [vc.tableView reloadData];
    }
}

- (NSInteger)elapsedSecondsFromNow:(DeviceModel *)runningDevice {
    NSInteger seconds = 0;
    if (runningDevice.requestTime && ![runningDevice.requestTime isEmptyString]) {
        NSDate *rdate = [CommonUtil dateFromDateString:[CommonUtil localDateFromUTC:runningDevice.requestTime]];
        NSTimeInterval elapsed = [[NSDate systemDate] timeIntervalSinceDate:rdate];
        seconds = elapsed;
    }
    return seconds;
}

- (NSInteger)elapsedSecondsFrom:(DeviceModel *)runningDevice to:(DeviceModel *)fetchedDevice {
    NSInteger seconds = 0;
    if (runningDevice.requestTime && ![runningDevice.requestTime isEmptyString] && fetchedDevice.collectTime && ![fetchedDevice.collectTime isEmptyString]) {
        NSDate *rdate = [CommonUtil dateFromDateString:[CommonUtil localDateFromUTC:runningDevice.requestTime]];
        NSDate *fdate = [CommonUtil dateFromDateString:[CommonUtil localDateFromUTC:fetchedDevice.collectTime]];
        seconds = [fdate secondsAfterDate:rdate];
    }
    return seconds;
}

- (void)addNewDevice {
    
    ThingsAddViewController *vc = [CommonUtil instantiateViewControllerWithIdentifier:@"ThingsAddViewController" storyboardName:@"Things"];
    if ([[JDFacade facade].loginUser isMultiHomeHub] && _selectHub == nil) {
        HomeHubSelectPopupView *hpopup = [[HomeHubSelectPopupView alloc] initFromNib];
        [hpopup showWithCompletion:^(CustomAlertView *alertView, NSInteger buttonIndex) {
            if (buttonIndex == 0) {
                vc.selectHub = hpopup.selectedDeviceModel;
                [self presentViewController:vc animated:YES completion:nil];
            }
        }];
    } else {
        vc.selectHub = _selectHub;
        [self presentViewController:vc animated:YES completion:nil];
    }
}

- (void)refreshDeviceList {
    [self performSelector:@selector(requestDeviceList:) withObject:@YES afterDelay:0.0f];
}

- (void)requestDeviceListRecently {
    DeviceModel *firstDevice = [_deviceList firstObject];
    _pagingType = ksListPagingTypeUpward;
    _pagingId = firstDevice.createDatetime;
    
    [self performSelector:@selector(requestDeviceList:) withObject:@YES afterDelay:0.0f];
}

- (void)requestDeviceListOlder {
    DeviceModel *lastDevice = [_deviceList lastObject];
    _pagingType = ksListPagingTypeDownward;
    _pagingId = lastDevice.createDatetime;
    
    [self performSelector:@selector(requestDeviceList:) withObject:@YES afterDelay:0.0f];
}

- (void)requestHomeHubList {
    
    NSString *path = [[JDFacade facade] getUrlWithCustAndGroupID:API_GET_DEVICE_LIST aditional:@""];
    
    [[RequestHandler handler] sendAsyncRequestAPIPath:path method:ksHTTPRequestGET parameters:nil
                                           modelClass:[DeviceListModel class] showLoadingView:NO completion:^(id responseObject) {
                                               //NSLog(@"Response : %@", responseObject);
                                               if (!responseObject) {//응답결과가 잘못되었거나 없을 경우,
                                                   return;
                                               }
                                               
                                               DeviceListModel *deviceList = (DeviceListModel *)responseObject;
                                               _homeHubList = [[DataSelectListModel alloc] init];
                                               _homeHubList.title = @"홈허브 선택";
                                               
                                               DataSelectModel *data = [[DataSelectModel alloc] init];
                                               data.title = @"전체";
                                               data.value = nil;
                                               [_homeHubList.list addObject:data];
                                               
                                               
                                               //허브 없으면 로그인화면으로 팅김
                                               if (deviceList.list.count == 0) [[JDFacade facade] logout];
                                               
                                               
                                               NSMutableArray *list = [NSMutableArray array];
                                               for (DeviceModel *info in deviceList.list) {
                                                   [list addObject:info];
                                                   
                                                   DataSelectModel *data = [[DataSelectModel alloc] init];
                                                   data.title = info.deviceName;
                                                   if (!info.isDeviceOnlined || !info.isDeviceConn) {
                                                       data.strColorCode = kUITextColorCode06;
                                                   }
                                                   
                                                   //기존 선택한 허브 이름이 바뀌었을 수 있다.
                                                   if (_selectHub != nil && EQUALS(_selectHub.deviceId, info.deviceId)) {
                                                       _selectHub = info;
                                                   }
                                                   
                                                   data.value = info;
                                                   [_homeHubList.list addObject:data];
                                               }
                                               
                                               [JDFacade facade].loginUser.deviceList = list;
                                               
                                           } failure:^(id errorObject) {
                                               //        [self releaseDevicesTimer];
                                               
                                               JDErrorModel *error = (JDErrorModel *)errorObject;
                                               [[JDFacade facade] alert:error.errorMessage];
                                           }];
}

- (void)requestDeviceList:(id)showLoadingView{
    
    if (![JDFacade facade].loginUser.hasHomeHub) {
        return;
    }
    
    //    BOOL showLoadingView = [arg isKindOfClass:[NSTimer class]] ? [((NSTimer *)arg).userInfo boolValue] : [arg boolValue];
    
    //parameters
    
    NSString *device_id = _selectHub ? _selectHub.deviceId : ksEmptyString;
    NSDictionary *parameter = @{@"device_id": device_id};
    
    //    NSString *path = [NSString stringWithFormat:API_GET_DEVICE_LIST];
    // 멀티 홈허브 환경에서 선택된 홈허브 아이디가 있을경우 적용하기
    NSString *path = [[JDFacade facade] getUrlWithCustAndGroupID:API_GET_NODE_LIST aditional:@""];
    
    // TODO : 장치가 없을경우도 처리 하도록 수정하기
    [[RequestHandler handler] sendAsyncRequestAPIPath:path method:ksHTTPRequestPOST parameters:parameter
                                           modelClass:[NodeListModel class] showLoadingView:[showLoadingView boolValue] completion:^(id responseObject) {
                                               if (!responseObject) {//응답결과가 잘못되었거나 없을 경우,
                                                   return;
                                               }
                                               
                                               _nodeListData = (NodeListModel *)responseObject;
                                               
                                               [self initNodeDataRemainCtrt:device_id] ;
                                               [self setMoreBtnArray];
                                               
                                               _deviceList = _nodeListData.nodes;
                                               _deviceReOrderList = [[NSMutableArray alloc] initWithArray:_deviceList];
                                               [self updateTitle];
                                               
                                               if (!_deviceList.count) {//이미 로드된 데이터가 있을 경우는 출력하지 않음.
                                                   
                                                   _lblConnectHub.text = @"등록된 장치가 없습니다";
                                                   _imgvHubAlert.hidden = YES;
                                                   _imgvConnectHub.image = [UIImage imageNamed:@"img_1depth_nodevice"];
                                               }
                                               
                                               //        if (_nodeListData && _nodeListData.nodes && _nodeListData.nodes.count) {
                                               //            _deviceList = _nodeListData.nodes;
                                               //            _deviceReOrderList = [[NSMutableArray alloc] initWithArray:_deviceList];
                                               //            [self updateTitle];
                                               //        } else {
                                               //            if (!_deviceList.count) {//이미 로드된 데이터가 있을 경우는 출력하지 않음.
                                               //                _lblConnectHub.text = @"등록된 장치가 없습니다";
                                               //                _imgvHubAlert.hidden = YES;
                                               //
                                               //                _imgvConnectHub.image = [UIImage imageNamed:@"img_1depth_nodevice"];
                                               //            }
                                               //        }
                                               
                                               [_collectionView reloadData];
                                               
                                               //        [self requestPollingDevicesStatusInBackground];
                                               
                                               //refresh controller
                                               if (self.refreshController && self.refreshController.refreshState == JYRefreshStateLoading) {
                                                   [self.refreshController stopRefreshWithAnimated:YES completion:nil];
                                               }
                                               
                                           } failure:^(id errorObject) {
                                               //        [self releaseDevicesTimer];
                                               
                                               JDErrorModel *error = (JDErrorModel *)errorObject;
                                               [[JDFacade facade] alert:error.errorMessage];
                                           }];
}

//노드 데이터에서 디바이스 별로 남은 추가 장치 수 계산해서 NodeListModel 셋팅해줌
- (void)initNodeDataRemainCtrt:(NSString*)deviceID {
    
    
    NSMutableArray *devices = _nodeListData.devices;
    
    NSInteger cnt = 0;
    
    for (DeviceModel *device in devices) {
        
        if (EQUALS(deviceID, @"")) {
            
            //전체 카운트
            cnt += [device.totalCtrtCnt integerValue];
        }
        else if(EQUALS(deviceID, device.deviceId)) {
            
            //자기 디바이스의 노드 카운트만
            cnt += [device.totalCtrtCnt integerValue];
        }
        
    }
    
    _nodeListData.ctrtCnt = [NSString stringWithFormat:@"%ld", cnt];
}

- (void)requestDeviceOrderReset {
    NSString *path = [[JDFacade facade] getUrlWithCustAndGroupID:API_PUT_NODE_ORDER_RESET aditional:nil];
    NSDictionary *parameter = @{@"type": @"node"};
    
    [[RequestHandler handler] sendAsyncPutRequestAPIPath:path parameters:parameter modelClass:[JDJSONModel class] completion:^(id responseObject) {
        //NSLog(@"Reset Result : %@", responseObject);
        [self refreshDeviceList];
        
    } failure:^(id errorObject) {
        
        JDErrorModel *error = (JDErrorModel *)errorObject;
        [[JDFacade facade] alert:error.errorMessage];
    }];
}

- (void)requestDeviceOrderChange {
    
    NSString *path = [[JDFacade facade] getUrlWithCustAndGroupID:API_PUT_NODE_ORDER_CHANGE aditional:nil];
    NSMutableArray *nodeOrder = [NSMutableArray array];
    
    for (DeviceModel *info in _deviceReOrderList) {
        NSDictionary *orderInfo  = @{
                                     @"device_id": info.deviceId,
                                     @"node_id": info.nodeId};
        [nodeOrder addObject:orderInfo];
    }
    
    NSDictionary *parameter = @{@"nodes": nodeOrder};
    [[RequestHandler handler] sendAsyncPutRequestAPIPath:path parameters:parameter modelClass:[JDJSONModel class] completion:^(id responseObject) {
        //NSLog(@"ReOrder Result : %@", responseObject);
        //        [self refreshDeviceList];
    } failure:^(id errorObject) {
        
        JDErrorModel *error = (JDErrorModel *)errorObject;
        [[JDFacade facade] alert:error.errorMessage];
    }];
    
}


//디바이스 상태를 3초마다 갱신함.
//- (void)requestPollingDevicesStatusInBackground {
//    return;
//    //schedul timer.
//    if (!_devicesBackgroundTimer) {
//        _devicesBackgroundTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(requestDeviceList:) userInfo:@NO repeats:YES];
//    }
//}

-(void)showHomeHubSelect {
    
    [[JDFacade facade] selectDatas:self listInfo:_homeHubList completion:^(DataSelectModel *seleced) {
        
        _selectHub = (DeviceModel *)seleced.value;
        [JDFacade facade].loginUser.selectedHomeHubID = _selectHub.deviceId;
        
        [self updateTitle];
        [self requestDeviceList:@YES];
        
    }];
}

- (void)setTitleClickable:(BOOL)isAdd {
    
    if (_titleBarClick == nil) {
        _titleBarClick=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showHomeHubSelect)];
    }
    [_viewTitle removeGestureRecognizer:_titleBarClick];
    if (isAdd) {
        [_viewTitle addGestureRecognizer:_titleBarClick];
    }
}

- (void)updateTitle {
    
    _imgvArrow.hidden = ![[JDFacade facade].loginUser isMultiHomeHub];
    
    [self setTitleClickable:[[JDFacade facade].loginUser isMultiHomeHub]];
    
    if (_imgvArrow.hidden) {
        
        DeviceModel *info = [[JDFacade facade].loginUser getHomeHub];
        _lblTitle.text = [NSString stringWithFormat:@"%@", info.deviceName == nil ? @"" :  info.deviceName];
        
        [self viewOfflineSetDeviceModel:info];
        
    } else {
        
        if (_selectHub == nil) {
            _lblTitle.text = @"전체";
        } else {
            _lblTitle.text = [NSString stringWithFormat:@"%@", _selectHub.deviceName == nil ? @"" : _selectHub.deviceName];
        }
        
        [self viewOfflineSetDeviceModel:_selectHub];
    }
    
    
    _lblCount.text = [NSString stringWithFormat:@"%zd", _deviceList.count];
    
    if (![JDFacade facade].loginUser.hasHomeHub) {//홈허브 아이디가 없는 경우,
        [_mainView bringSubviewToFront:_addHubContainerView];
        _addHubContainerView.hidden = NO;
        _collectionView.hidden = YES;
        _btnOption.hidden = NO;
        _btnClose.hidden = YES;
        
        if (![JDFacade facade].loginUser.homegrpId) {//연결한 적이 없음
            _lblConnectHub.text = @"초대를 받아서\n시작해 보세요";
            _imgvHubAlert.hidden = YES;
            
            _imgvConnectHub.image = [UIImage imageNamed:@"img_1depth_invitation"];
            
            _lblLeaveAccount.hidden = YES;
            _lblSimpleMemberInfo.hidden = YES;
            
        } else {//홈허브가 삭제됨.
            _lblTitle.text = @"홈허브 삭제됨";
            
            _imgvHubAlert.hidden = NO;
            _lblConnectHub.text = @"홈허브를 다시 연결하려면\n고객센터에 문의해주세요";
            
            _imgvConnectHub.image = [UIImage imageNamed:@"img_things_homehub_img_hubdelete_cscenter"];
            
            if ([JDFacade facade].loginUser.level < 90) {//일반 유저일 경우,
                _imgvConnectHub.image = [UIImage imageNamed:@"img_things_homehub_img_hubdelete_wait"];
                _lblLeaveAccount.hidden = NO;
                _lblSimpleMemberInfo.hidden = NO;
                [_lblLeaveAccount setUnderLine:_lblLeaveAccount.text];
                
                if (!_lblLeaveAccount.touchHandler) {
                    [_lblLeaveAccount addTouchEventHandler:^(id label) {
                        [self leaveHomegroup];
                    }];
                }
            }
        }
        
    } else {
        if (![JDFacade facade].loginUser.isHomehubOnline) {
            _imgvHubAlert.hidden = NO;
            _lblTitle.text = @"홈허브 오프라인";
            [_lblTitle setColor:kUITextColor01 text:_lblTitle.text];
        } else {
            _imgvHubAlert.hidden = YES;
        }
        
        [_mainView bringSubviewToFront:_collectionView];
        _addHubContainerView.hidden = YES;
        _collectionView.hidden = NO;
        _btnOption.hidden = NO;
        
    }
    
    if ([_lblTitle.text rangeOfString:@"장치 전체"].location != NSNotFound) {
        [_lblTitle setColor:kUITextColor03 text:[NSString stringWithFormat:@"%zd", _deviceList.count]];
    }
}

- (void)leaveHomegroup {
    HomeMemberViewController *vc = [[HomeMemberViewController alloc] init];
    [vc leaveHomegroup];
}

- (void)matchDeviceListWithOnCommandsDevices {
    
    for (DeviceModel *rdevice in _commandArray) {
        DeviceModel *matchedDevice = [_deviceList objectByUsingPredicateFormat:@"deviceId == %@", rdevice.deviceId]; //일치하는 디바이스가 있을 경우, 추가하지 않음.
        //        DeviceModel *matchedDevice = [_deviceList objectByUsingPredicateFormat:@"deviceId == %@ && nodeId == %@", rdevice.deviceId, rdevice.nodeId]; //일치하는 디바이스가 있을 경우, 추가하지 않음.
        if (matchedDevice) {
            matchedDevice.isRequesting = rdevice.isRequesting;
            matchedDevice.requestTime = rdevice.requestTime;
        }
    }
    
    //    [_collectionView reloadData];
}

- (void)releaseDevicesTimer {
    if (_devicesBackgroundTimer) {
        [_devicesBackgroundTimer invalidate];
        _devicesBackgroundTimer = nil;
    }
}

#pragma mark - UICollectionView Delegate
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    NSInteger auth = [JDFacade facade].loginUser.level == 90
    && !_isDeleteMode
    && [_nodeListData isCanAddNode]
    && [[JDFacade facade].loginUser onlineHomeHubFromSelectedHub:_selectHub]
    && [[JDFacade facade].loginUser connectedHomeHubFromSelectedHub:_selectHub];
    
    //    NSLog(@"authCount : %ld", auth);
    //    NSLog(@"[JDFacade facade].loginUser.level : %ld", [JDFacade facade].loginUser.level);
    //    NSLog(@"_isDeleteMode: %d", _isDeleteMode);
    //    NSLog(@"[_nodeListData isCanAddNode] : %d", [_nodeListData isCanAddNode]);
    //    NSLog(@"[[JDFacade facade].loginUser onlineHomeHubFromSelectedHub:_selectHub] : %d", [[JDFacade facade].loginUser onlineHomeHubFromSelectedHub:_selectHub]);
    
    NSInteger count = _deviceList.count % _deviceFlag == 0 ? _deviceList.count + auth : _deviceList.count + auth; //홀수일 경우, 멤버 초대 버튼을 추가해줌.
    //    NSInteger count = _deviceList.count;
    return count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    UICollectionViewCell *rcell = nil;
    UIPanGestureRecognizer *drag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHandler:)];
    
    if (indexPath.row < _deviceList.count) {
        ThingsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ThingsCellIdentifier" forIndexPath:indexPath];
        //        [cell.btnDelete setHidden:YES];
        //        [cell.btnChangeOrder setHidden:YES];
        
        DeviceModel *device =_deviceList[indexPath.row];
        cell.indexPath = indexPath;
        
        if ([device.prdName isEqualToString:device.prdUserName] || [device.prdUserName isEqualToString:@""]) {
            cell.lblDeviceName.text = device.prdName;
        } else {
            cell.lblDeviceName.text = device.prdUserName;
        }
        
        
        //        [cell.btnDevice sd_setImageWithURL:[NSURL URLWithString:device.imageFileName] forState:UIControlStateNormal
        //                          placeholderImage:nil options:SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
        //            [cell layoutIfNeeded];
        //        }];
        [cell.imgDevice setImage:[UIImage imageNamed:device.deviceclassTypeId]];
        [cell.btnDevice addTarget:self action:@selector(btnDeviceTouched:) forControlEvents:UIControlEventTouchUpInside];
        [cell.btnDelete addTarget:self action:@selector(btnDeviceDelete:) forControlEvents:UIControlEventTouchUpInside];
        cell.btnDevice.value = indexPath;
        cell.btnDelete.value = indexPath;
        
        //커맨드 클래스 뷰를 초기화함.
        [[cell.controlContainer subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            UIView *subview = (UIView *)obj;
            [subview removeFromSuperview];
        }];
        
        // TODO : 어떤 부분인지 내용 확인 필요
        cell.pcontainerView.hidden = !device.isRequesting;
        if (!cell.pcontainerView.hidden) {
            [cell startProgressAni];
        } else {
            [cell stopProgressAni];
        }
        
        //허브 On-Off line check
        //        cell.lblDeviceStatus.hidden = !([[JDFacade facade].loginUser.homehubOnlineState isEqualToString:@"OFF"] || [device.onlineState isEqualToString:@"OFF"]);
        //        cell.controlContainer.hidden = !cell.lblDeviceStatus.hidden;
        
        cell.btnDelete.hidden = !_isDeleteMode;
        cell.btnChangeOrder.hidden = !_isReOrderMode;
        
        if(_isDeleteMode || _isReOrderMode)
        {
            //            cell.btnDevice.enabled = NO;
            cell.btnDeviceControl.hidden = YES;
            _btnOption.hidden = YES;
            _imgvLogo.hidden = YES;
        }
        else
        {
            //            cell.btnDevice.enabled = YES;
            cell.btnDeviceControl.hidden = NO;
            _btnOption.hidden = NO;
            _imgvLogo.hidden = YES;
        }
        
        
        
        [cell.btnChangeOrder addGestureRecognizer:drag];
        cell.btnChangeOrder.value = indexPath;
        
        // 이부분 확인해 볼것
        if (!cell.controlContainer.hidden) {//커맨드 클래스 타입별 컨트롤 호출
            [cell.btnDevice setBackgroundImage:[device backgroundImageForMandatary:device.contentValue] forState:UIControlStateNormal];
            
            CommandClassControlView *controlView = [CommandClassControlView viewForCommandClass:device.cmdclsType];
            controlView.device = device;
            if(_isDeleteMode || _isReOrderMode)
            {
                controlView.isReOrderMode = YES;
            }
            else {
                controlView.isReOrderMode = NO;
            }
            
            cell.controlContainer.hidden = !controlView;
            if (!cell.controlContainer.hidden) {
                UIView *superview = cell.controlContainer;
                [superview addSubview:controlView];
                
                //                controlView.width = IS_IPHONE_6P ? 98.0f : 120;
                //                NSLog(@"Controll View : %f", ViewWidth(superview));
                //                controlView.width = ViewWidth(superview);
                [controlView mas_makeConstraints:^(MASConstraintMaker *make) {
                    //                    make.size.mas_equalTo(superview.frame.size);
                    //                    make.center.equalTo(superview);
                    make.top.equalTo(superview.mas_top).with.offset(0); //with is an optional semantic filler
                    make.left.equalTo(superview.mas_left).with.offset(0);
                    make.bottom.equalTo(superview.mas_bottom).with.offset(0);
                    make.right.equalTo(superview.mas_right).with.offset(0);
                }];
            }
            
        }
        
        if (!device.isOnline || !device.isDeviceConn) {
            
            cell.lblDeviceStatus.text = @"OFFLINE";
            cell.lblDeviceStatus.textColor = kUITextColor01;
            
            [cell.btnDevice setBackgroundImage:[UIImage imageNamed:@"img_thing_icon_bg_default"] forState:UIControlStateNormal];
        }
        
        
        rcell = cell;
    } else {
        
        ThingsAddCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ThingsAddCellIdentifier" forIndexPath:indexPath];
        
        //
        if (![cell.btnAdd actionsForTarget:self forControlEvent:UIControlEventTouchUpInside]) {
            [cell.btnAdd addTarget:self action:@selector(addNewDevice) forControlEvents:UIControlEventTouchUpInside];
        }
        
        rcell = cell;
    }
    
    return rcell;
}

//- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
//    return CGSizeZero;
//
//    //FIXME : 권한 추가
////    if (_memberList.count % 2 == 1 || [JDFacade facade].loginUser.level < 90 || _isDeleteMode)  {//마스터 권한이 아니거나, 짝수가 아닐 경우
//    if (_deviceList.count % 2 == 1 || _isDeleteMode)  {//마스터 권한이 아니거나, 짝수가 아닐 경우
//    }
//
//    return CGSizeMake(IPHONE_WIDTH, 160.0f);
//}

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
{
    return CGSizeMake(ViewWidth(_collectionView), (((ViewWidth(_collectionView)-kiCellInset)+kiCellRatio) / kiCellItem) / kiCellDivision+(kiCellItem*kiCellItem));
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    return CGSizeMake((ViewWidth(_collectionView)-kiCellInset) / kiCellItem, ((ViewWidth(_collectionView)-kiCellInset)+kiCellRatio) / kiCellItem);
}

// Cell 사이 최소 간격
- (CGFloat) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return kiCellInset;
}

// Line 별 최소 간격
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
    return kiCellInset;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
    
    if (_isReOrderMode || _isDeleteMode) {
        //        [collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];
        return;
    }
    
    if (indexPath.row < _deviceList.count) {//디바이스인 경우,
        //        DeviceModel *device = _deviceList[indexPath.row];
        //
        //        ThingsDetailViewController *vc = (ThingsDetailViewController *)[CommonUtil instantiateViewControllerWithIdentifier:@"ThingsDetailViewController" storyboardName:@"Things"];
        //        vc.refDevice = device;
        //        [self presentViewController:vc animated:YES completion:nil];
        [self moveToDetail:indexPath];
    }
}


-(BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
{
    return _isReOrderMode;
}

-(BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)toIndexPath
{
    return _isReOrderMode;
}


- (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return _isReOrderMode;
}


-(void)panGestureHandler:(UIGestureRecognizer *)sender
{
    CGPoint locationPoint = [self getCellCenter:[sender locationInView:_collectionView]];
    
    
    switch (sender.state) {
        case UIGestureRecognizerStateBegan:
        {
            
            NSIndexPath *indexPathOfPoint = [self.collectionView indexPathForItemAtPoint:locationPoint];
            _moveCell = (ThingsCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPathOfPoint];
            UIGraphicsBeginImageContext(_moveCell.bounds.size);
            [_moveCell.layer renderInContext:UIGraphicsGetCurrentContext()];
            UIImage *cellImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            
            
            _cellFakeView = [[UIImageView alloc] initWithImage:cellImage];
            [_cellFakeView setCenter:locationPoint];
            [_collectionView addSubview:_cellFakeView];
            
            _dragIndexPath = indexPathOfPoint;
            _moveCell.hidden = YES;
            
        }
        case UIGestureRecognizerStateChanged:
        {
            [_cellFakeView setCenter:locationPoint];
        }
            break;
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded:
            //            [self.collectionView performBatchUpdates:^{
            //                //update cell indexPath
            //                _reorderingCellIndexPath = toIndexPath;
            //                [self.collectionView moveItemAtIndexPath:atIndexPath toIndexPath:toIndexPath];
            //                //did move
            //                if ([self.datasource respondsToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath:)]) {
            //                    [self.datasource collectionView:self.collectionView itemAtIndexPath:atIndexPath didMoveToIndexPath:toIndexPath];
            //                }
            //            } completion:nil];
            
            //
            //            _dragIndexPath= nil;
            //            [_cellFakeView removeFromSuperview];
            
            //
            [self moveItemIfNeeded];
            break;
        default:
            break;
    }
}

- (void)moveItemIfNeeded
{
    // TODO : 버그 수정
    NSIndexPath *atIndexPath = _dragIndexPath;
    NSIndexPath *toIndexPath = [_collectionView indexPathForItemAtPoint:_cellFakeView.center];
    if (toIndexPath != nil && ![atIndexPath isEqual:toIndexPath]) {
        [_collectionView performBatchUpdates:^{
            
            [_collectionView moveItemAtIndexPath:atIndexPath toIndexPath:toIndexPath];
            [self updateDataSource:atIndexPath toIndexPath:toIndexPath];
            
        } completion:nil];
    }
    
    
    _moveCell.hidden = NO;
    [_cellFakeView removeFromSuperview];
    _dragIndexPath = nil;
    //    [_cellInfo]
}

-(CGPoint)getCellCenter:(CGPoint)point
{
    CGPoint btnCenter = _moveCell.btnChangeOrder.center;
    CGPoint cellCenter = _moveCell.contentView.center;
    
    CGPoint result = CGPointMake(point.x-(btnCenter.x-cellCenter.x), point.y-(btnCenter.y-cellCenter.y));
    
    
    return result;
}

-(void)updateDataSource:(NSIndexPath *)atIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
    
    DeviceModel *device =_deviceReOrderList[atIndexPath.item];
    
    [_deviceReOrderList removeObjectAtIndex:atIndexPath.item];
    [_deviceReOrderList insertObject:device atIndex:toIndexPath.item];
}

-(void)moveToDetail:(NSIndexPath *)indexPath
{
    DeviceModel *device = _deviceList[indexPath.row];
    
    ThingsDetailViewController *vc = (ThingsDetailViewController *)[CommonUtil instantiateViewControllerWithIdentifier:@"ThingsDetailViewController" storyboardName:@"Things"];
    vc.refDevice = device;
    vc.selectHub = _selectHub;
    
    [self presentViewController:vc animated:YES completion:nil];
}


#pragma mark - UI Events

/**
 첫번째 이미지
 - img_bg_morepopup_icon_thingschange
 - img_bg_morepopup_icon_thingschange_press
 두번째 이미지 :
 - img_bg_morepopup_icon_add
 - img_bg_morepopup_icon_add_press
 세번째 이미지 :
 - img_bg_morepopup_icon_delete
 - img_bg_morepopup_icon_delete_press
 네번째 이미지 :
 - img_bg_morepopup_icon_refresh
 - img_bg_morepopup_icon_refresh_press
 **/

- (IBAction)btnOfflineMultiTouched:(id)sender {
    
    UIViewController *vc = [CommonUtil instantiateViewControllerWithIdentifier:@"HomeHubViewController" storyboardName:@"Main"];
    
    if ([JDFacade facade].loginUser.isMultiHomeHub) {
        
        vc = [CommonUtil instantiateViewControllerWithIdentifier:@"MultiHomeHubViewController" storyboardName:@"Main"];
    }
    
    
    UINavigationController *m_navi =[[UINavigationController alloc]initWithRootViewController:vc];
    [self presentViewController:m_navi animated:YES completion:nil];
}



- (IBAction)btnOptionTouched:(id)sender {
    
    [self toggleOptionsWithArray:sender btnArray:_moreBtnArray];
}

- (IBAction)btnReFreshTouched:(id)sender {
    [[JDFacade facade] confirmTitle:@"알림" message:@"장치 목록의 순서를\n장치가 등록된 순으로 초괴화합니다." btnOKLabel:@"확인" btnCancelLabel:@"취소" completion:^(CustomAlertView *alertView, NSInteger buttonIndex) {
        if (buttonIndex == 0) {
            [self requestDeviceOrderReset];
            [self toggleReOrderMode:NO];
        }
    }];
}

- (IBAction)btnConfirmTouched:(id)sender {
    
    [[JDFacade facade] confirmTitle:@"알림" message:@"현재 편집된 장치 목록 순서를\n저장하시겠습니까?" btnOKLabel:@"확인" btnCancelLabel:@"취소" completion:^(CustomAlertView *alertView, NSInteger buttonIndex) {
        
        if (buttonIndex == 0) {
            // TODO : 데이터 업데이트 하기
            
            NSLog(@"d List : %@", _deviceList);
            NSLog(@"r List : %@", _deviceReOrderList);
            
            _deviceList = [[NSMutableArray alloc] initWithArray:_deviceReOrderList];
            [self requestDeviceOrderChange];
            [self toggleReOrderMode:NO];
        }
    }];
    
    //    _deviceList = _deviceReOrderList;
    //    [self toggleReOrderMode:NO];
}

- (IBAction)btnCloseTouched:(id)sender {
    if (_isReOrderMode) {
        [[JDFacade facade] confirmTitle:@"알림" message:@"장치 목록 순서를 저장하지 않고\n이전화면으로 이동합니다." btnOKLabel:@"확인" btnCancelLabel:@"취소" completion:^(CustomAlertView *alertView, NSInteger buttonIndex) {
            if (buttonIndex == 0) {
                [self toggleReOrderMode:NO];
            }
        }];
    }
    else {
        [self toggleEditMode:NO];
    }
}

-(void)toggleReOrderMode:(Boolean)isReOrder
{
    //    _imgvLogo.hidden = !isReOrder;
    _isReOrderMode = isReOrder;
    _viewEditMode.hidden = !isReOrder;
    _btnOption.hidden = isReOrder;
    [_collectionView reloadData];
    
    _viewTitle.hidden = isReOrder;
    _lblEditMode.hidden = !isReOrder;
    
    _lblEditMode.text = @"장치 목록 순서 편집";
}

-(void)toggleEditMode:(Boolean)isEdit
{
    //    _imgvLogo.hidden = !isEdit;
    _isDeleteMode = isEdit;
    _viewEditMode.hidden = !isEdit;
    _btnOption.hidden = isEdit;
    [_collectionView reloadData];
    
    _viewTitle.hidden = isEdit;
    _lblEditMode.hidden = !isEdit;
    
    _lblEditMode.text = @"장치 삭제";
    
    _btnEditSave.hidden = !isEdit;
    _btnEditRefresh.hidden = !isEdit;
}



//로그인 이후 처리.
- (void)actionForLoginSucceed:(LoginModel *)loginInfo {
    
    if (loginInfo) {//API 성공함
        
        [JDFacade facade].loginUser = loginInfo;
        
        NSLog(@"loginUser : %@", [JDFacade facade].loginUser);
        
        if ([[JDFacade facade].loginUser.emailId isEqualToString:[JDFacade facade].tmpEmailId]) {
            [JDFacade facade].tmpEmailId = ksEmptyString;
        }
        
        if ([[JDFacade facade].loginUser.emailId isEqualToString:[JDFacade facade].loginUser.newEmailId]) {//이메일 변경 요청 중
            [JDFacade facade].loginUser.newEmailId = ksEmptyString;
        }
        
        [RequestHandler handler].authorization = loginInfo.authorization;
    }
}


-(void)moreBtnAction:(id)sender
{
    NSInteger tag = [(UIButton *)sender tag];
    NSLog(@"MoreBtn Action : %li", (long)tag);
    switch (tag) {
        case ReOrder:
        {
            [self toggleReOrderMode:YES];
        }
            break;
        case Add:
        {
            [self addNewDevice];
        }
            break;
        case Del:
        {
            [self toggleEditMode:YES];
        }
            break;
        case Refresh:
        {
            [self refreshDeviceList];
        }
            break;
            
        default:
            break;
    }
}


-(void)btnDeviceTouched:(id)sender
{
    NSIndexPath *indexPath = (NSIndexPath *) ((CustomButton *)sender).value;
    //
    //    DeviceModel *device =_deviceList[indexPath.row];
    //    NSLog(@"Device : %@", device);
    [self moveToDetail:indexPath];
}


-(void)btnDeviceDelete:(id)sender
{
    NSIndexPath *indexPath = (NSIndexPath *) ((CustomButton *)sender).value;
    
    DeviceModel *device =_deviceList[indexPath.row];
    
    if (![device isOnline]) {
        ThingsForcedDelViewController *vc = [CommonUtil instantiateViewControllerWithIdentifier:@"ThingsForcedDelViewController" storyboardName:@"Things"];
        
        vc.delDevice = device;
        //        vc.providesPresentationContextTransitionStyle = YES;
        //        vc.definesPresentationContext = YES;
        //
        //        [vc setModalPresentationStyle:UIModalPresentationOverCurrentContext];
        //
        //        [self presentViewController:vc animated:NO completion:nil];
        [self showTransparencyModalView:vc removeSelf:NO];
        
    } else {
        ThingsGeneralDelViewController *vc = [CommonUtil instantiateViewControllerWithIdentifier:@"ThingsGeneralDelViewController" storyboardName:@"Things"];
        
        vc.delDevice = device;
        //        vc.providesPresentationContextTransitionStyle = YES;
        //        vc.definesPresentationContext = YES;
        //
        //        [vc setModalPresentationStyle:UIModalPresentationOverCurrentContext];
        //
        //        [self presentViewController:vc animated:NO completion:nil];
        [self showTransparencyModalView:vc removeSelf:NO];
    }
    
    //    [self requestDeviceList:@NO];
}


-(void)finishDeviveDelete
{
    
    [self toggleEditMode:NO];
    [self requestDeviceList:@YES];
}



#pragma mark - SocketService
- (void) socketDidReceiveMessage:(id)message result:(SocketModel *)result
{
    SWITCH(result.messageType)
    {
        CASE(MSG_TYPE_AUTO_LOGIN)
        {
            if (result.isSuccess) {
                
                LoginModel *loginInfo = (LoginModel *)message;
                loginInfo.memberId = [[JDFacade facade] objectForKeyFromKeychain:USDEF_SESSION_LOGIN_ID];
                loginInfo.authToken = [[JDFacade facade] objectForKeyFromKeychain:USDEF_SESSION_AUTOTOKEN];
                
                [self actionForLoginSucceed:loginInfo];
                [self prepareViewDidLoadRefreshPopup];
            }
            else {
                
                [[JDFacade facade] alertTitle:@"알림" message:result.resultMsg];
            }
            
            break;
        }
        DEFAULT
        {
            break;
        }
    }
}

- (void) socketDidReceiveMessage:(id)message info:(NSDictionary *)info
{
    SocketModel *result = (SocketModel *)message;
    NSLog(@"Result Info : %@", result);
    SWITCH(result.messageType)
    {
        
        CASE (@"node.register")
        {
            
        }
        CASE (@"node.delete")
        {
            
        }
        CASE(@"nodes.reload")
        {
            
            
        }
        DEFAULT
        {
            break;
        }
    }
}

- (void) socketDidFailWithError:(NSError *)error {
    [[JDFacade facade] loadIndicator:NO allowUserInteraction:YES];
}

-(void) receiveSocketData:(NSNotification *)notification {
    SocketModel *result = [[SocketModel alloc] initWithDictionary:notification.object error:nil];
    
    //    CommandModel *response = [[CommandModel alloc] initWithDictionary:notification.object error:nil];
    
    NSLog(@"Result : %@", result);
    
    if ([result.messageType isEqualToIgnoreCase:MSG_TYPE_NODE_CONTENT]) {
        ContentModel *response = [[ContentModel alloc] initWithDictionary:notification.object error:nil];
        for (DeviceModel *info in _deviceList) {
            if ([info.deviceId isEqualToString:response.deviceId] && [info.nodeId isEqualToString:response.nodeId]) {
                info.collectTime = response.collectTime;
                
                id contentValue = [NSJSONSerialization JSONObjectWithData:[response.contentValue dataUsingEncoding:NSUTF8StringEncoding]
                                                                  options:NSJSONReadingAllowFragments
                                                                    error:nil];
                
                info.contentValue = contentValue[info.cmdclsId];
                if (info.isRequesting) {
                    info.isRequesting = NO;
                }
                [_collectionView reloadData];
                break;
                //                NSLog(@"Info : %@", contentValue[info.cmdclsId]);
            }
        }
    }
    else if ([result.messageType isEqualToIgnoreCase:MSG_TYPE_NODE_COMMAND_RES]) {
        
    }
    else if ([result.messageType isEqualToIgnoreCase:MSG_TYPE_NODE_REGIST_RES] ||
             [result.messageType isEqualToIgnoreCase:MSG_TYPE_NODE_DELETE_RES]) {
        
        [self requestDeviceList:@NO];
        
    }
    else if([result.messageType isEqualToIgnoreCase:MSG_TYPE_DEVICE_CONTENT] ||
            [result.messageType isEqualToIgnoreCase:MSG_TYPE_DEVICE_CONN]) {
        
        if (_selectHub != nil) {
            
            [JDFacade facade].loginUser.selectedHomeHubID = _selectHub.deviceId;
        }
        
        [self requestHomeHubList]; //타이틀 허브 리스트 재조회(온라인, 연결상태)
        [self requestDeviceList:@NO];
    }
}


@end
