// File: hzeller[P]FlaschenTaschen-PixelPusher-bridge/main.cc
// Function: main
int main(int argc, char *argv[]) {
    int layer_timeout = 15;
    bool as_daemon = false;
    int udp_packet_size = kDefaultPacketSize;
    int brightness = 100;

    enum LongOptionsOnly {
        OPT_LAYER_TIMEOUT = 1002,
    };

    static struct option long_options[] = {
        { "daemon",             no_argument,       NULL, 'd'},
        { "layer-timeout",      required_argument, NULL,  OPT_LAYER_TIMEOUT },
        { 0,                    0,                 0,    0  },
    };

    int opt;
    while ((opt = getopt_long(argc, argv, "I:du:b:", long_options, NULL)) != -1) {
        switch (opt) {
        case 'd':
            as_daemon = true;
            break;
        case OPT_LAYER_TIMEOUT:
            layer_timeout = atoi(optarg);
            break;
        case 'u':
            udp_packet_size = atoi(optarg);
            break;
        case 'b':
            brightness = atoi(optarg);
            break;
        default:
            return usage(argv[0]);
        }
    }

    if (layer_timeout < 1) {
        layer_timeout = 1;
    }
    if (brightness < 0) brightness = 0;
    if (brightness > 100) brightness = 100;

    if (udp_packet_size < 0 || udp_packet_size > kMaxUDPPacketSize) {
        fprintf(stderr, "-u %d is outside usable packet size of 0..%d\n",
                udp_packet_size, kMaxUDPPacketSize);
        return usage(argv[0]);
    }

    FlaschenTaschen *display = new BJKPixelPusher(udp_packet_size, brightness);

    // Start all the services and report problems (such as sockets already
    // bound to) before we become a daemon
    if (!udp_server_init(1337)) {
        return 1;
    }

    fprintf(stderr, "Sending result to %dx%d PixelPusher installation\n",
            display->width(), display->height());

    // Commandline parsed, immediate errors reported. Time to become daemon.
    if (as_daemon && daemon(0, 0) != 0) {  // Become daemon.
        perror("Failed to become daemon");
    }

    display->Send();  // Clear screen.

    ft::Mutex mutex;

    // The display we expose to the user provides composite layering which can
    // be used by the UDP server.
    CompositeFlaschenTaschen layered_display(display, 16);
    layered_display.StartLayerGarbageCollection(&mutex, layer_timeout);

    udp_server_run_blocking(&layered_display, &mutex);  // last server blocks.
    delete display;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0xf, -0x14(%rbp)
movb $0x0, -0x15(%rbp)
movl $0x5b4, -0x1c(%rbp)     # imm = 0x5B4
movl $0x64, -0x20(%rbp)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0x5b52(%rip), %rdx      # 0x8012
leaq 0x9d09(%rip), %rcx      # 0xc1d0
xorl %eax, %eax
movl %eax, %r8d
callq 0x2300
movl %eax, -0x24(%rbp)
cmpl $-0x1, %eax
je 0x2571
movl -0x24(%rbp), %eax
movl %eax, -0xd4(%rbp)
subl $0x62, %eax
je 0x2544
jmp 0x24ed
movl -0xd4(%rbp), %eax
subl $0x64, %eax
je 0x2516
jmp 0x24fa
movl -0xd4(%rbp), %eax
subl $0x75, %eax
je 0x2530
jmp 0x2507
movl -0xd4(%rbp), %eax
subl $0x3ea, %eax            # imm = 0x3EA
je 0x251c
jmp 0x2558
movb $0x1, -0x15(%rbp)
jmp 0x256c
movq 0x9aa5(%rip), %rax      # 0xbfc8
movq (%rax), %rdi
callq 0x22e0
movl %eax, -0x14(%rbp)
jmp 0x256c
movq 0x9a91(%rip), %rax      # 0xbfc8
movq (%rax), %rdi
callq 0x22e0
movl %eax, -0x1c(%rbp)
jmp 0x256c
movq 0x9a7d(%rip), %rax      # 0xbfc8
movq (%rax), %rdi
callq 0x22e0
movl %eax, -0x20(%rbp)
jmp 0x256c
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x2780
movl %eax, -0x4(%rbp)
jmp 0x2735
jmp 0x24b2
cmpl $0x1, -0x14(%rbp)
jge 0x257e
movl $0x1, -0x14(%rbp)
cmpl $0x0, -0x20(%rbp)
jge 0x258b
movl $0x0, -0x20(%rbp)
cmpl $0x64, -0x20(%rbp)
jle 0x2598
movl $0x64, -0x20(%rbp)
cmpl $0x0, -0x1c(%rbp)
jl 0x25a7
cmpl $0xffe3, -0x1c(%rbp)    # imm = 0xFFE3
jle 0x25db
movq 0x9a2a(%rip), %rax      # 0xbfd8
movq (%rax), %rdi
movl -0x1c(%rbp), %edx
leaq 0x5a5f(%rip), %rsi      # 0x801a
movl $0xffe3, %ecx           # imm = 0xFFE3
movb $0x0, %al
callq 0x22a0
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x2780
movl %eax, -0x4(%rbp)
jmp 0x2735
movl $0x20, %edi
callq 0x21e0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xe0(%rbp)
movl -0x1c(%rbp), %esi
movl -0x20(%rbp), %edx
callq 0x6130
jmp 0x25ff
movq -0xe0(%rbp), %rax
movq %rax, -0x30(%rbp)
movl $0x539, %edi            # imm = 0x539
callq 0x2b70
testb $0x1, %al
jne 0x2646
movl $0x1, -0x4(%rbp)
jmp 0x2735
movq -0xe0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
movl $0x20, %esi
callq 0x21f0
jmp 0x2770
movq 0x998b(%rip), %rax      # 0xbfd8
movq (%rax), %rax
movq %rax, -0xf0(%rbp)
movq -0x30(%rbp), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movl %eax, -0xe4(%rbp)
movq -0x30(%rbp), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movq -0xf0(%rbp), %rdi
movl -0xe4(%rbp), %edx
movl %eax, %ecx
leaq 0x59c1(%rip), %rsi      # 0x8048
movb $0x0, %al
callq 0x22a0
testb $0x1, -0x15(%rbp)
je 0x26ae
xorl %esi, %esi
movl %esi, %edi
callq 0x2210
cmpl $0x0, %eax
je 0x26ae
leaq 0x59d1(%rip), %rdi      # 0x807a
callq 0x21b0
movq -0x30(%rbp), %rdi
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
leaq -0x68(%rbp), %rdi
callq 0x27d0
movq -0x30(%rbp), %rsi
leaq -0xd0(%rbp), %rdi
movl $0x10, %edx
callq 0x2f40
jmp 0x26db
movl -0x14(%rbp), %edx
leaq -0xd0(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x35e0
jmp 0x26f0
leaq -0xd0(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x2c70
jmp 0x2702
movq -0x30(%rbp), %rax
movq %rax, -0xf8(%rbp)
cmpq $0x0, %rax
je 0x2720
movq -0xf8(%rbp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
leaq -0xd0(%rbp), %rdi
callq 0x31b0
leaq -0x68(%rbp), %rdi
callq 0x27f0
movl -0x4(%rbp), %eax
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
jmp 0x2767
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0xd0(%rbp), %rdi
callq 0x31b0
leaq -0x68(%rbp), %rdi
callq 0x27f0
movq -0x38(%rbp), %rdi
callq 0x2330
nopl (%rax)