//
//  keychain_sync_test.c
//  sec
//
//  Created by Mitch Adler on 7/8/16.
//
//

#include "keychain_sync_test.h"

#include "secToolFileIO.h"

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#include <utilities/SecCFWrappers.h>
#include <utilities/SecCFRelease.h>

#import <Foundation/Foundation.h>

#include <Security/SecureObjectSync/SOSCloudCircle.h>

#import "NSFileHandle+Formatting.h"

static char boolToChars(bool val, char truechar, char falsechar) {
    return val? truechar: falsechar;
}

int
keychain_sync_test(int argc, char * const *argv)
{
    NSFileHandle *fhout = [NSFileHandle fileHandleWithStandardOutput];
    NSFileHandle *fherr = [NSFileHandle fileHandleWithStandardError];
    /*
     "Keychain Syncing test"

     */
    int result = 0;
    __block CFErrorRef cfError = NULL;

    static int verbose_flag = 0;
    bool dump_pending = false;

    static struct option long_options[] =
    {
        /* These options set a flag. */
        {"verbose",     no_argument,        &verbose_flag, 1},
        {"brief",       no_argument,        &verbose_flag, 0},
        /* These options don’t set a flag.
         We distinguish them by their indices. */
        {"enabled-peer-views",      required_argument, 0, 'p'},
        {"message-pending-state",   no_argument,       0, 'm'},
        {0, 0, 0, 0}
    };
    static const char * params = "p:m";

    /* getopt_long stores the option index here. */
    int option_index = 0;

    NSArray<NSString*>* viewList = nil;

    int opt_result = 0;
    while (opt_result != -1) {
        opt_result = getopt_long (argc, argv, params, long_options, &option_index);
        switch (opt_result) {
            case 'p': {
                NSString* parameter = [NSString stringWithCString: optarg encoding:NSUTF8StringEncoding];

                viewList = [parameter componentsSeparatedByString:@","];
                
                }
                break;
            case 'm':
                dump_pending = true;
                break;
            case -1:
                break;
            default:
                return SHOW_USAGE_MESSAGE;
        }

    }

    if (viewList) {
        CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef) viewList, &cfError);
        if (result != NULL) {
            [fhout writeFormat: @"Views: %@\n", viewList];
            [fhout writeFormat: @"Enabled on other peers: %@\n", CFBooleanGetValue(result) ? @"yes" : @"no"];
        }
    }

    if (dump_pending) {
        CFArrayRef peers = SOSCCCopyPeerPeerInfo(&cfError);
        if (peers != NULL) {
            [fhout writeFormat: @"Dumping state for %ld peers\n", CFArrayGetCount(peers)];

            CFArrayForEach(peers, ^(const void *value) {
                SOSPeerInfoRef thisPeer = (SOSPeerInfoRef) value;
                if (thisPeer) {
                    CFReleaseNull(cfError);
                    bool message = SOSCCMessageFromPeerIsPending(thisPeer, &cfError);
                    if (!message && cfError != NULL) {
                        [fherr writeFormat: @"Error from SOSCCMessageFromPeerIsPending: %@\n", cfError];
                    }
                    CFReleaseNull(cfError);
                    bool send = SOSCCSendToPeerIsPending(thisPeer, &cfError);
                    if (!message && cfError != NULL) {
                        [fherr writeFormat: @"Error from SOSCCSendToPeerIsPending: %@\n", cfError];
                    }
                    CFReleaseNull(cfError);

                    [fhout writeFormat: @"Peer: %c%c %@\n", boolToChars(message, 'M', 'm'), boolToChars(send, 'S', 's'), thisPeer];
                } else {
                    [fherr writeFormat: @"Non SOSPeerInfoRef in array: %@\n", value];
                }
            });
        }
    }

    if (cfError != NULL) {
        [fherr writeFormat: @"Error: %@\n", cfError];
    }

    return result;
}
