//
//  GMSRequestViewController.m
//  GMS Sample
//
/*
 Version: 1.0
 
 Disclaimer: IMPORTANT:  This software is supplied to you by Genesys
 Telecommunications Laboratories Inc ("Genesys") in consideration of your agreement
 to the following terms, and your use, installation, modification or redistribution
 of this Genesys software constitutes acceptance of these terms.  If you do not
 agree with these terms, please do not use, install, modify or redistribute this
 Genesys software.
 
 In consideration of your agreement to abide by the following terms, and subject
 to these terms, Genesys grants you a personal, non-exclusive license, under
 Genesys's copyrights in this original Genesys software (the "Genesys Software"), to
 use, reproduce, modify and redistribute the Genesys Software, with or without
 modifications, in source and/or binary forms; provided that if you redistribute
 the Genesys Software in its entirety and without modifications, you must retain
 this notice and the following text and disclaimers in all such redistributions
 of the Genesys Software.
 
 Neither the name, trademarks, service marks or logos of Genesys Inc. may be used
 to endorse or promote products derived from the Genesys Software without specific
 prior written permission from Genesys.  Except as expressly stated in this notice,
 no other rights or licenses, express or implied, are granted by Genesys herein,
 including but not limited to any patent rights that may be infringed by your
 derivative works or by other works in which the Genesys Software may be
 incorporated.
 
 The Genesys Software is provided by Genesys on an "AS IS" basis.  GENESYS MAKES NO
 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE, REGARDING THE GENESYS SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
 COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL GENESYS BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
 DISTRIBUTION OF THE GENESYS SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
 CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
 GENESYS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2013 Genesys Inc. All Rights Reserved.
 */

#import "GMSRequestViewController.h"
#import "GMSAppDelegate.h"
#import "GMSLogViewController.h"
#import "GMSChatViewController.h"
#import "GMSSettingsSelectViewController.h"
#import "GMSSettingsTableViewController.h"
#import "GMSScheduleTimeTableViewController.h"
#import "GMSUtil.h"

@implementation GMSRequestViewController
{
    GMSAppDelegate *appDelegate;
    UIImagePickerController *imagePicker;
    BOOL imagePicked;
    NSArray *schedTimeSlotArray;
    NSError *schedTimeError;
}

#pragma mark -
#pragma mark Local Methods

- (void)updateSchedTextFields
{
    _schedDesiredTimePicker.minimumDate = [NSDate date];
    BOOL enableTimeSelect = NO;
    if (_schedDesiredTime == nil) {
        _schedDesiredTimeTextField.text = @"Tap to select";
        _schedTimeTextField.text = @"Select desired time above";
    }
    else {
        _schedDesiredTimeTextField.text = [GMSUtil localStringFromDate:_schedDesiredTime];
        if (schedTimeError != nil) {
            if ([self isOfficeClosedMessage:schedTimeError.domain])
                _schedTimeTextField.text = @"Office closed at desired time";
            else
                _schedTimeTextField.text = @"Error requesting time slots";
        }
        else if (schedTimeSlotArray == nil)
            _schedTimeTextField.text = @"Requesting time slots";
        else if ([schedTimeSlotArray count] == 0)
            _schedTimeTextField.text = @"No slots at desired time";
        else if (_schedTime == nil){
            _schedTimeTextField.text = @"Tap to select";
            enableTimeSelect = YES;
        }
        else{
            _schedTimeTextField.text = [GMSUtil localStringFromDate:_schedTime];
            enableTimeSelect = YES;
        }
    }
    
    if (enableTimeSelect) {
        _schedTimeCell.userInteractionEnabled = YES;
        _schedTimeCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }
    else {
        _schedTimeCell.userInteractionEnabled = NO;
        _schedTimeCell.accessoryType = UITableViewCellAccessoryNone;
    }
    [self.tableView reloadData];
}

- (void)initSchedData
{
    _schedTime = nil;
    _schedDesiredTime = nil;
    _schedDesiredTimePicker.date = [NSDate date];
   [self updateSchedTextFields];
}

- (BOOL) way2ConnectIsScheduled
{
    return [appDelegate.way2Connect rangeOfString:@"SCHEDULED"].location != NSNotFound;
}

- (BOOL) isOfficeClosedMessage:(NSString*)message
{
    return [message hasPrefix:@"Office is closed"];
}

- (NSString*) callbackPath
{
    return [[@"/1/service" stringByAppendingPathComponent:@"callback"]
        stringByAppendingPathComponent:appDelegate.callbackServiceName];
}

#pragma mark -
#pragma mark View LifeCycle

- (id)initWithCoder:(NSCoder*)coder
{
    if ((self = [super initWithCoder:coder])) {
        //We need to create GMSDmenu here, in case of APN. initWithCoder is called before AppDidFinishLaunching, where we use dMenu.
        self.dMenu = [GMSDMenu initWithObject:self.navigationController];
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    appDelegate = (GMSAppDelegate*)[[UIApplication sharedApplication] delegate];
    
    _userNameTextField.text = appDelegate.userID;
    _pwdTextField.text = appDelegate.userPwd;
    _way2Connect.text = appDelegate.way2Connect;
    _infoLevel.text = appDelegate.problemInfoLevel;
    _contentTextField.text = appDelegate.problemContent;
    _appPathTextField.text = appDelegate.appPath;
    [self initSchedData];
    
    // Set up the schedule time objects
    _schedDesiredTimeTextField.inputView = _schedDesiredTimePicker;
    _schedDesiredTimeTextField.inputAccessoryView = _schedDesiredTimePickerToolbar;
    _schedDesiredTimePicker.timeZone = [NSTimeZone localTimeZone];
    
    imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.allowsEditing = NO;
    imagePicker.delegate = self;
    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        // camera is not on this device, don't show the camera button
        _takePictureButton.enabled = NO;
    }
    imagePicked = NO;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)viewDidUnload {
    imagePicker = nil;    
    [self setTakePictureButton:nil];
    [self setImageView:nil];
    [self setSubmitButton:nil];
    [self setWay2Connect:nil];
    [self setInfoLevel:nil];
    [self setSubmitButton:nil];
    [self setUserNameTextField:nil];
    [self setPwdTextField:nil];
    [self setContentTextField:nil];
    [self setAppPathTextField:nil];
    [self setWay2Connect:nil];
    [super viewDidUnload];
}

#pragma mark -
#pragma mark Table View Delegate

// We override this to hide the scheduled callback date and time tables cells
// These are only enabled when method is set to schedule callback
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
    if (cell == _schedDesiredTimeCell || cell == _schedTimeCell) {
        if (![self way2ConnectIsScheduled]) {
            return 0; // hide the cell
        }
    }
    
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

#pragma mark -
#pragma mark Availble Callback Slot Methods

- (void) requestCallbackAvailability
{
    schedTimeError = nil;
    schedTimeSlotArray = nil;
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    // Request time in a range + and - 5 hours from desired time and display the 5 that are closest to desired
    NSDate *start = [_schedDesiredTime dateByAddingTimeInterval:-5*3600];
    NSDate *end = [_schedDesiredTime dateByAddingTimeInterval:5*3600];
    // Limit start and end to not be earlier than now
    NSDate *now = [NSDate date];
    start = [start laterDate:now];
    end = [end laterDate:start];
    
    [params setValue:[GMSUtil apiStringFromDate:start] forKey:@"start"];
    [params setValue:[GMSUtil apiStringFromDate:end] forKey:@"end"];
    
    NSString *path = [[self callbackPath] stringByAppendingPathComponent:@"availability"];
    
    GMSRequestViewController *myself = self;
    void (^completionBlock)(NSDictionary *responseDict);
    completionBlock = ^(NSDictionary *responseDict){
        NSString *message = [responseDict objectForKey:@"message"];
        if (message != nil) {
            myself->schedTimeError = [NSError errorWithDomain:message code:0 userInfo:nil];
            [myself updateSchedTextFields];
            if (![myself isOfficeClosedMessage:message]) {
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error requesting time slots"
                                                                message:message
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
                [alert show];
            }
        }
        else {
            // The dictionary contents should consist of data for N slots, where the data
            // for each slot is a datetime (in the key), number available at this datetime (in the value)
            if ([responseDict count] > 0) {
                // Enumerate over the keys to build the array of time values
                NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity:[responseDict count]];
                for (NSString *dateStr in [responseDict allKeys]) {
                    // Note, if conversion fails a null value will be inserted and and error will be displayed for it
                    [tmpArray addObject:[GMSUtil dateFromApiString:dateStr]];
                }
                
                // First sorttime values by the absolutue amount of time the desired time
                NSArray *tmpArray2 = [tmpArray sortedArrayUsingComparator: ^(id obj1, id obj2) {
                    NSNumber *dt1 = [NSNumber numberWithDouble: fabs([obj1 timeIntervalSinceDate:myself->_schedDesiredTime]) ];
                    NSNumber *dt2 = [NSNumber numberWithDouble: fabs([obj2 timeIntervalSinceDate:myself->_schedDesiredTime]) ];
                    return [dt1 compare:dt2];
                }];
                
                // Take the first 5 values which will be the nearest centered on the desired
                NSRange range;
                range.location = 0;
                range.length = tmpArray2.count > 5 ? 5: tmpArray2.count;
                NSArray *tmpArray3 = [tmpArray2 subarrayWithRange:range];
                
                // Set the final array to the selected 5 sorted ascending
                myself->schedTimeSlotArray = [tmpArray3 sortedArrayUsingComparator: ^(id obj1, id obj2) {
                    return [(NSDate*)obj1 compare:(NSDate*)obj2];
                }];
            }
            else {
                // No slots, set to an empty array
                myself->schedTimeSlotArray = [[NSArray alloc] init];
            }
            
            [myself updateSchedTextFields];
        }
    };
    
    [GMSUtil submitRequestWithPath:path method:@"GET" params:params headers:@{@"gms_user": appDelegate.userID} completionBlock:completionBlock];
}

#pragma mark -
#pragma mark Scedule Date Picker Actions

- (IBAction)schedDesiredTimePickerCancel:(id)sender
{
    [_schedDesiredTimeTextField resignFirstResponder];
}

- (IBAction)schedDesiredTimePickerDone:(id)sender
{
    _schedDesiredTime = _schedDesiredTimePicker.date;
    _schedTime = nil;
    [_schedDesiredTimeTextField resignFirstResponder];
    [self requestCallbackAvailability];
    [self updateSchedTextFields];
}

#pragma mark -
#pragma mark Photo Actions

- (IBAction)takePhoto:(id)sender {
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    [self.navigationController presentModalViewController:imagePicker animated:YES];
}

- (IBAction)choosePhoto:(id)sender {
    imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    [self.navigationController presentModalViewController:imagePicker animated:YES];
}

- (IBAction)clearPhoto:(id)sender {
    imagePicked = NO;
    _imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"placeholder" ofType:@"png"]];
}

#pragma mark -
#pragma mark UIImagePickerControllerDelegate

// this get called when an image has been chosen from the library or taken from the camera
//
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    _imageView.image = [info valueForKey:UIImagePickerControllerOriginalImage];
    imagePicked = YES;
    [picker dismissModalViewControllerAnimated:YES];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
     [picker dismissModalViewControllerAnimated:YES];
}


#pragma mark -
#pragma mark - TextField delegates

- (void)updateFromTextField:(UITextField *)textField textToUpdate:(NSString *)txtStr {
    if (textField == _userNameTextField) {
        appDelegate.userID = txtStr;
    }
    else if (textField == _pwdTextField) {
        appDelegate.userPwd = txtStr;
    }
    else if (textField == _contentTextField) {
        appDelegate.problemContent = textField.text;
    }
    else if (textField == _appPathTextField) {
        appDelegate.appPath = txtStr;
    }
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [self updateFromTextField:textField textToUpdate:textField.text];
}

- (BOOL)textFieldShouldClear:(UITextField *)textField {
    [self updateFromTextField:textField textToUpdate:@""];
    return YES;
}

//Dismiss keyboard when Return key is pressed
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementStr {
    NSString *proposedNewString = [[textField text] stringByReplacingCharactersInRange:range withString:replacementStr];
    [self updateFromTextField:textField textToUpdate:proposedNewString];
    return YES;
}

//find Chat View Controller in Tab Bar
- (GMSChatViewController *)findChatController {
    for (id vc in [super tabBarController].viewControllers) {
        if ([vc isKindOfClass:[GMSChatViewController class]] ) {
            return vc;
        }
    }
    return nil;
}

#pragma mark -
#pragma mark - Request Callback

- (IBAction)submitGMS:(id)sender {
    
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"dd-MMM-YYYY HH:mm z"];
        
    if ([self way2ConnectIsScheduled]) {
        if (_schedTime == nil) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Callback Time Not Set"
                                                            message:@"The scheduled callback time must be selected."
                                                           delegate:nil
                                                  cancelButtonTitle:@"OK"
                                                  otherButtonTitles:nil];
            [alert show];
            return;
        }
        [params setValue:[GMSUtil apiStringFromDate:_schedTime] forKey:@"_desired_time"];
    }
    
    
//    //Remove non-digits from phone
//    NSString *phoneN = appDelegate.contactNumber;
//    phoneN = [phoneN stringByReplacingOccurrencesOfString:@"[^0-9]"
//                                               withString:@""
//                                                  options:NSRegularExpressionSearch
//                                                    range:NSMakeRange(0, [phoneN length])];
//    //Remove leading "1"
//    if ([phoneN length] == 11 && [phoneN hasPrefix:@"1"]) {
//        phoneN = [phoneN substringFromIndex:1];
//    }

    //Add parameter for simulated APN from Settings
    if ([sender isKindOfClass:[GMSSettingsTableViewController class]]) {
        [params setValue:@"true" forKey:@"_simulate_proactive_event"];                                              //Simulate proactive APN
    }

#if (TARGET_IPHONE_SIMULATOR)
    [params setValue:@"comet" forKey:@"_device_os"];
#else
    [params setValue:@"ios" forKey:@"_device_os"];
#endif
    [params setValue:appDelegate.notifyToken forKey:@"_device_notification_id"];                                    //APN Token
    [params setValue:(appDelegate.serverAPNDebug) ? @"true" : @"false" forKey:@"_use_debug_push_certificate"];
    [params setValue:appDelegate.userID forKey:@"_chat_user_display_name"];                                         //User ID
    [params setValue:appDelegate.userID forKey:@"userDisplayName"];                                                 //User ID
    [params setValue:appDelegate.userPwd forKey:@"_user_password"];                                                 //User Password
    [params setValue:appDelegate.problemInfoLevel forKey:@"problem_info_level"];                                   //Problem Info Level
    [params setValue:appDelegate.problemContent forKey:@"problem"];                                                //Problem Content
    [params setValue:appDelegate.appPath forKey:@"app_path"];                                                      //Application Path
    [params setValue:appDelegate.customerSegment forKey:@"customer_segment"];                                      //Customer Segment
    [params setValue:appDelegate.themeFlavor forKey:@"_theme_flavor"];                                              //Theme Flavor
    [params setValue:appDelegate.contactNumber forKey:@"_customer_number"];                                         //Contact Number
    [params setValue:[[NSLocale preferredLanguages] objectAtIndex:0] forKey:@"_language"];                          //Language Selected
    [params setValue:[NSString stringWithFormat:@"%f", appDelegate.location.latitude] forKey:@"location_lat"];     //Location
    [params setValue:[NSString stringWithFormat:@"%f", appDelegate.location.longitude] forKey:@"location_long"];
    [params setValue:[dateFormat stringFromDate:appDelegate.date] forKey:@"date"];                                 //Date

    if (![appDelegate.way2Connect isEqualToString:@"SERVER-DECIDE"]) {
        if ([appDelegate.way2Connect rangeOfString:@"WAIT"].location == NSNotFound)
            [params setValue:@"false" forKey:@"_wait_for_agent"];                                                   //Way to connect
        else
            [params setValue:@"true" forKey:@"_wait_for_agent"];                                                    //Way to connect
        
        if ([appDelegate.way2Connect hasSuffix:@"USERTERM"])                                                        //Call Direction
            [params setValue:@"USERTERMINATED" forKey:@"_call_direction"];
        else                                                                                                        //Call Direction
            [params setValue:@"USERORIGINATED" forKey:@"_call_direction"];
        
        if ([appDelegate.way2Connect hasPrefix:@"CHAT"]) {                                                          //Chat
            [params setValue:@"chat" forKey:@"_media_type"];
            [params setValue:@"GMS Sample" forKey:@"subject"];                                                      //Chat Subject
        }
        else
            [params setValue:@"voice" forKey:@"_media_type"];
    }
    
    [params setValue:@"CUSTOMER" forKey:@"_call_origination"];                                                      //Call Origination
    [params setValue:(appDelegate.loginRequired) ? @"true" : @"false" forKey:@"_login_required"];                   //Login required
    [params setValue:(appDelegate.provideCode) ? @"true" : @"false" forKey:@"_provide_code"];                       //Provide DTMF code
    if (imagePicked) {
        NSData *photoData = UIImagePNGRepresentation(_imageView.image);                                             //Photo
        [params setValue:photoData forKey:@"photo"];
    }
    
    _submitButton.enabled = NO;

    _dMenu.audioEnabled = appDelegate.audioEnabled;
    _dMenu.audioRecordEnabled = appDelegate.audioRecordEnabled;
    __weak UIBarButtonItem *wButton = _submitButton;
    void (^completionBlock) (NSDictionary *responseDict);
    completionBlock = ^(NSDictionary *responseDict){
        wButton.enabled = YES;
        if ([responseDict isKindOfClass:[NSDictionary class]]) {
            appDelegate.serviceID = responseDict[@"_id"];
        }
    };
    
    GMSChatViewController *vc = [self findChatController];
    _dMenu.startChatBlock = ^(NSDictionary *actionDict){
        //Start Chat
        [vc startWithURL:actionDict[@"_start_chat_url"]
                cometURL:actionDict[@"_comet_url"]
              userHeader:actionDict[@"_user_header"]
              chatParams:actionDict[@"_chat_parameters"]];
        [super tabBarController].selectedViewController = vc;
    };
    _dMenu.endChatBlock = ^{
        [vc endChat:nil];
    };
    [_dMenu submitRequestWithPath:[self callbackPath] method:@"POST" params:params headers:@{@"gms_user" : appDelegate.userID}
              completionBlock:completionBlock];
}

#pragma mark -
#pragma mark - PrepareForSegue

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"informationLevel"]) {
        GMSSettingsSelectViewController *vc = segue.destinationViewController;
        vc.currentSelection = _infoLevel;
        vc.updateBlock = ^(NSString *title){
            appDelegate.problemInfoLevel = title;
        };
    } else if ([segue.identifier isEqualToString:@"way2Connect"]) {
        GMSSettingsSelectViewController *vc = segue.destinationViewController;
        vc.currentSelection = _way2Connect;
        vc.updateBlock = ^(NSString *title){
            if (![appDelegate.way2Connect isEqualToString:title]) {
                appDelegate.way2Connect = title;
                [self initSchedData];
                [self.tableView reloadData]; // Need to redraw because some fields depend on way2Connect
            }
        };
    } else if ([segue.identifier isEqualToString:@"scheduleTime"]) {
        GMSScheduleTimeTableViewController *vc = (GMSScheduleTimeTableViewController*) segue.destinationViewController;
        _schedTime = nil;
        vc.timeSlotArray = schedTimeSlotArray;
        vc.dMenu = _dMenu;
        vc.setSelectedTime = ^(NSDate *time){
            _schedTime = time;
            [self updateSchedTextFields];
        };
    }
}

@end
