//
//  SAMLUtility.m
//  SAML
//
//  Created by Vora, Hetal (Contractor) on 6/27/16.
//
//

#import "SAMLUtility.h"
#import "TFHpple.h"
#import "TFHppleElement.h"
#import "XPathQuery.h"

@interface SAMLUtility()
    @property(nonatomic, strong) NSURLSession *session;

@end

@implementation SAMLUtility

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler{
    NSLog(@"did receive auth challenge");
    
    if(challenge.protectionSpace.authenticationMethod  == NSURLAuthenticationMethodServerTrust){
        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
    }else if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM || challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNegotiate){
        
        NSURLCredential *credential = [NSURLCredential credentialWithUser:@"hvore001c" password:@"Welcome1" persistence:NSURLCredentialPersistenceNone];
        
        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
        
    }else {
        
        // Cancel request
        NSURLCredential *credential = [[NSURLCredential alloc] init];
        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, credential);

    }
    
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest * __nullable))completionHandler{
    NSLog(@"in redirection");
    NSURLRequest *newRequest = request;
    completionHandler(newRequest);
    
}

-(void)httpRequest:(NSMutableURLRequest*)request callback:(void(^)(NSData *data, NSString *str))callback{
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    
    //Manage the time out configuration
    configuration.timeoutIntervalForRequest=120;
    configuration.timeoutIntervalForResource=120;
    
    //Now initiate the reuqest
    self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    NSData *data = [[NSData alloc] init];
    
    if((request) != nil) {
        NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            
            if(response){
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                NSLog(@"---- Response Code : %ld",(long)httpResponse.statusCode);
                NSLog(@"---- Header fields Code : %@", httpResponse.allHeaderFields);
                
                if(error){
                    callback(data, error.localizedDescription);
                } else {
                    
                    callback(data, nil);
                }
            }
            else{
                NSLog(@"---- Response is not NSHTTPURLResponse it is %@ -data: %@ - error: %@",response, data, error);
            }
            
            
        }];
        
        [task resume];
    }
    
    callback(data, nil);
}

-(void)performSAMLAuth{
    
    NSString *escapedspEndPoint = [self.ssoUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    NSLog(@"Calling iDP endpoint added encoded %@",escapedspEndPoint);
    
    //call SP login end point
    NSURL *urlObject = [NSURL URLWithString:escapedspEndPoint];
    NSMutableURLRequest *spLoginReq = [NSMutableURLRequest requestWithURL:urlObject];
    
    //Create a session and connect to the specfied url.
    NSLog(@"Going to request  now...");
    
    //TODO: This will result in 302 and go to IdP location do authentication with kerberos
    //other other options and come back...
    
    [self httpRequest:spLoginReq callback:^(NSData *data, NSString *error){
        if(error) {
            NSLog(@"Error: %@",error);
            NSLog(@"Task execution completed with failure");
        } else {
            NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Success: %@", s);
            
            //Parse the IdP response and send back to
            //SP SSO End point
            NSMutableURLRequest *spSsoReq = [self buildSsoRequestFrom:data];
            
            [self httpRequest:spSsoReq callback:^(NSData *data, NSString *error){
                if(error) {
                    NSLog(@"Error: %@",error);
                    NSLog(@"Task execution completed with failure");
                } else {
                    NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                    NSLog(@"Success: %@", s);
                    
                    NSLog(@"spSsoReq completed");
                    NSLog(@"------------------------");
                }
                NSLog(@"Task execution completed");
                NSMutableURLRequest *spSsoReq1 = [self buildSsoRequestFrom:data];
                NSLog(@"SAP SSO Request %@",spSsoReq1);
                if([spSsoReq1.URL.absoluteString isEqualToString:@"https://saphcmqa01.teamcomcast.com/saml2/sp/acs"]){
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"SSOCompleted" object: nil];
                }
                
                NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
                NSLog(@"Cookies Count %lu",(unsigned long)cookies.count);
                if(cookies.count > 0){
                    for(NSHTTPCookie *cookie in cookies){
                        NSLog(@"cookie : %@", cookie.name);
                    }
                }
                
            }];
        }
    }];
    
}

-(NSMutableURLRequest*)buildSsoRequestFrom:(NSData*)samlHtmlResponse{
    TFHpple *doc = [[TFHpple alloc] initWithHTMLData:samlHtmlResponse];
    NSLog(@"Doc %@",doc.data);
            if(doc == nil || (doc.data) == nil) {
                NSLog(@"Bad SAML expected response: %@", doc);
                return nil;
            }
    
    NSArray *elements = [doc searchWithXPathQuery:@"//form"];
    NSLog(@"Elements %@",elements);
    if (elements != nil && elements.count > 0) {

        for(TFHppleElement *element in elements){
            
            //This is form
            TFHppleElement *formElement = (TFHppleElement*)element;
            NSString *spSsoUrlString = [formElement objectForKey:@"action"];
            NSLog(@"--- Now sending back to SP SSO End point : %@", spSsoUrlString);
            
            //Now iterate through all the child elements of type input
            NSURL *spSsoUrl = [NSURL URLWithString:spSsoUrlString];
            NSMutableURLRequest *spSsoRequest = [NSMutableURLRequest requestWithURL:spSsoUrl];
            
            //set method to HTTP POST
            spSsoRequest.HTTPMethod = @"POST";
            
            //set content type for url encoded
            //spSsoRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
            
            //iterate through all the input parameters
            //and extract key = name & value = value of the input
            
            NSArray *inputElements = [formElement childrenWithTagName:@"input"];
            NSMutableString *postBody = [[NSMutableString alloc] init];
            for(TFHppleElement *ie in inputElements) {
                TFHppleElement *tfie = (TFHppleElement*)ie;
                NSString *key = [tfie objectForKey:@"name"];
                NSString *value= [tfie objectForKey:@"value"];
                value = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                value = [value stringByReplacingOccurrencesOfString:@"+" withString:@"%2B" options:NSLiteralSearch range:NSMakeRange(0, value.length)];
                [postBody stringByAppendingFormat:@"%@=%@",key,value];
            }
            NSLog(@"3. POST Body : %@", postBody);
            NSData *postBodyData = [postBody dataUsingEncoding:NSUTF8StringEncoding];
            spSsoRequest.HTTPBody = postBodyData;
            
            return spSsoRequest;
        }
    }
    return nil;

}











@end
