// File: intheswim[P]FractalTubes/main.cpp
// Function: main
int main (int argc, char *argv[]) {

    Display *dpy;
    Window  win;

    struct argvOptions params;

    parse_arguments (argc, argv, &params); 

    dpy = XOpenDisplay (getenv ("DISPLAY"));

    if (!dpy) 
    {
        fprintf(stderr, "Cannot connect to X server.\n");
        return EXIT_FAILURE;
    }

    char *xwin = getenv ("XSCREENSAVER_WINDOW");

    if (params.useLog)
    {
        printf ("Display : %s\n", getenv("DISPLAY"));

        printf ("xwin : %s\n", xwin);
    }

    int root_window_id = 0;

    if (xwin)
    {
        root_window_id = strtol (xwin, NULL, 0);
    }

    XVisualInfo *vi = NULL;

    if (params.standalone == false) 
    {
		// Get the root window
        if (root_window_id == 0)
        {
		    // root = DefaultRootWindow(dpy);
            printf ("usage as standalone app: %s -window\n", argv[0]);
            return EXIT_FAILURE;
        }
        else
    	{
      		win = root_window_id;

            int screen = DefaultScreen(dpy);  

            if (params.smooth)
            {
                vi = getMultispampleXVisual (dpy, screen);
            }

            if (vi == NULL)
            {
                vi = glXChooseVisual(dpy, screen, att);
            }

            if (vi == NULL) 
            {
	            fprintf(stderr, "\nNo appropriate visual found\n\n");
                return EXIT_FAILURE;
            }

            XSelectInput (dpy, win, ExposureMask | StructureNotifyMask);
    	}
	} 
    else 
	{
		/* Let's create our own window. */
		int screen = DefaultScreen(dpy);
        Window root = DefaultRootWindow(dpy);

        if (params.smooth)
        {
            vi = getMultispampleXVisual (dpy, screen);
        }

        if (vi == NULL)
        {
            vi = glXChooseVisual(dpy, screen, att);
        }

        if (vi == NULL) 
        {
	        fprintf(stderr, "\nNo appropriate visual found\n\n");
            return EXIT_FAILURE;
        } 

        unsigned int mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;

        int border_width = 0;

        Colormap cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);

        XSetWindowAttributes swa;

        swa.background_pixmap = None ;
        swa.background_pixel  = 0    ;
        swa.border_pixel      = 0    ;

        swa.colormap = cmap;
        swa.event_mask = ExposureMask | StructureNotifyMask;

		win = XCreateWindow(dpy, root, 0, 0, 860, 640, border_width,
            vi->depth, InputOutput, vi->visual, mask, &swa);

		XMapWindow(dpy, win);

		XStoreName(dpy, win, "Fractal Tubes");
	}

    // this is to terminate nicely:
	Atom wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(dpy, win, &wmDeleteMessage, 1);

    if (params.useLog) { createLog(); }

    GLXContext glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);

    if (!glc)
    {
        fprintf(stderr, "\nglXCreateContext failed.\n\n");
        return EXIT_FAILURE;
    }

    if (!glXMakeCurrent(dpy, win, glc))
    {
        fprintf(stderr, "\nglXMakeCurren failed.\n\n");
        return EXIT_FAILURE;
    }

    if (params.verbose)
    {
        fprintf (stdout, "OpenGL Version: %s\n", glGetString(GL_VERSION));
    }
 
    glEnable (GL_DEPTH_TEST); 

    XWindowAttributes gwa;

    XGetWindowAttributes(dpy, win, &gwa);

    AppParams::setDetailLevel (params.detail);
    AppParams::setIntervalOption (params.interval);
    AppParams::setPalette (params.palette);
    AppParams::setLightSource (params.light_source);
    AppParams::setTransparencyLevel (params.transparency);
    AppParams::setRotationSpeed (params.rotation_speed);
    AppParams::setLightDistance (params.dist2light);
    AppParams::setLight2Sides (params.two_sided_light);
    AppParams::setShuffle (params.shuffle);

    if (params.gloss_level < 0) // random 
    {
        AppParams::setGlossRandom(true);
    }
    else 
    {
        AppParams::setGlossRandom(false);
        AppParams::setGlossLevel (params.gloss_level);
    }

    GetConfig();

    setFrameSizeForGL (gwa.width, gwa.height);
    
    prepareOpenGL();
 
    while (true) 
    {
        XEvent  event;

        long mask = StructureNotifyMask;

        if (XCheckWindowEvent(dpy, win, mask, &event) ||
		   XCheckTypedWindowEvent (dpy, win, ClientMessage, &event)) // needed to catch ClientMessage
        {
            if (event.type == ConfigureNotify) 
        	{
          		XConfigureEvent xce = event.xconfigure;

		        // This event type is generated for a variety of
          		// happenings, so check whether the window has been
          		// resized.

          		if (xce.width != gwa.width || xce.height != gwa.height) 
          		{
            		gwa.width = xce.width;
            		gwa.height = xce.height;

                    setFrameSizeForGL (gwa.width, gwa.height);
          
            		continue;
          		}
        	}

            else if (event.type == ClientMessage)
        	{
            	if ((Atom)event.xclient.data.l[0] == wmDeleteMessage)
            	{
                	break;
            	}
			}                
        }

        animateOneFrame();

        redrawMethod();
        glXSwapBuffers(dpy, win);

        // sleep for 10 ms
        usleep(1000 * params.delay_ms);
    } 

    CleanupAnimation();

    if (params.useLog) { closeLog (); }

    glXMakeCurrent(dpy, None, NULL);
 	glXDestroyContext(dpy, glc);
 	XDestroyWindow(dpy, win);
 	XCloseDisplay(dpy);

    return EXIT_SUCCESS;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r14
pushq %rbx
subq $0x2f0, %rsp            # imm = 0x2F0
movl $0x0, -0x14(%rbp)
movl %edi, -0x18(%rbp)
movq %rsi, -0x20(%rbp)
leaq -0x64(%rbp), %rdi
callq 0x44c0
movl -0x18(%rbp), %edi
movq -0x20(%rbp), %rsi
leaq -0x64(%rbp), %rdx
callq 0x3fa0
leaq 0xa710(%rip), %rdi      # 0xe09c
callq 0x3470
movq %rax, %rdi
callq 0x3540
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
jne 0x39c8
movq 0xf635(%rip), %rax      # 0x12fe0
movq (%rax), %rdi
leaq 0xa6ef(%rip), %rsi      # 0xe0a4
movb $0x0, %al
callq 0x3590
movl $0x1, -0x14(%rbp)
jmp 0x3f91
leaq 0xa6f2(%rip), %rdi      # 0xe0c1
callq 0x3470
movq %rax, -0x70(%rbp)
testb $0x1, -0x62(%rbp)
je 0x3a0d
leaq 0xa6b7(%rip), %rdi      # 0xe09c
callq 0x3470
movq %rax, %rsi
leaq 0xa6e1(%rip), %rdi      # 0xe0d5
movb $0x0, %al
callq 0x3040
movq -0x70(%rbp), %rsi
leaq 0xa6dd(%rip), %rdi      # 0xe0e3
movb $0x0, %al
callq 0x3040
movl $0x0, -0x74(%rbp)
cmpq $0x0, -0x70(%rbp)
je 0x3a2d
movq -0x70(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x3560
movl %eax, -0x74(%rbp)
movq $0x0, -0x80(%rbp)
movb -0x64(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x3b01
cmpl $0x0, -0x74(%rbp)
jne 0x3a6d
movq -0x20(%rbp), %rax
movq (%rax), %rsi
leaq 0xa694(%rip), %rdi      # 0xe0ee
movb $0x0, %al
callq 0x3040
movl $0x1, -0x14(%rbp)
jmp 0x3f91
movslq -0x74(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rax
movl 0xe0(%rax), %eax
movl %eax, -0x84(%rbp)
cmpl $0x0, -0x34(%rbp)
je 0x3a9e
movq -0x28(%rbp), %rdi
movl -0x84(%rbp), %esi
callq 0x3860
movq %rax, -0x80(%rbp)
cmpq $0x0, -0x80(%rbp)
jne 0x3abf
movq -0x28(%rbp), %rdi
movl -0x84(%rbp), %esi
leaq 0xf90a(%rip), %rdx      # 0x133c0
callq 0x35b0
movq %rax, -0x80(%rbp)
cmpq $0x0, -0x80(%rbp)
jne 0x3aea
movq 0xf513(%rip), %rax      # 0x12fe0
movq (%rax), %rdi
leaq 0xa63c(%rip), %rsi      # 0xe113
movb $0x0, %al
callq 0x3590
movl $0x1, -0x14(%rbp)
jmp 0x3f91
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movl $0x28000, %edx          # imm = 0x28000
callq 0x31e0
jmp 0x3c95
movq -0x28(%rbp), %rax
movl 0xe0(%rax), %eax
movl %eax, -0x88(%rbp)
movq -0x28(%rbp), %rax
movq 0xe8(%rax), %rax
movq -0x28(%rbp), %rcx
movslq 0xe0(%rcx), %rcx
shlq $0x7, %rcx
addq %rcx, %rax
movq 0x10(%rax), %rax
movq %rax, -0x90(%rbp)
cmpl $0x0, -0x34(%rbp)
je 0x3b52
movq -0x28(%rbp), %rdi
movl -0x88(%rbp), %esi
callq 0x3860
movq %rax, -0x80(%rbp)
cmpq $0x0, -0x80(%rbp)
jne 0x3b73
movq -0x28(%rbp), %rdi
movl -0x88(%rbp), %esi
leaq 0xf856(%rip), %rdx      # 0x133c0
callq 0x35b0
movq %rax, -0x80(%rbp)
cmpq $0x0, -0x80(%rbp)
jne 0x3b9e
movq 0xf45f(%rip), %rax      # 0x12fe0
movq (%rax), %rdi
leaq 0xa588(%rip), %rsi      # 0xe113
movb $0x0, %al
callq 0x3590
movl $0x1, -0x14(%rbp)
jmp 0x3f91
movl $0x2809, -0x94(%rbp)    # imm = 0x2809
movl $0x0, -0x98(%rbp)
movq -0x28(%rbp), %rdi
movq -0x90(%rbp), %rsi
movq -0x80(%rbp), %rax
movq (%rax), %rdx
xorl %ecx, %ecx
callq 0x31f0
movq %rax, -0xa0(%rbp)
movq $0x0, -0x110(%rbp)
movq $0x0, -0x108(%rbp)
movq $0x0, -0xf8(%rbp)
movq -0xa0(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq $0x28000, -0xc8(%rbp) # imm = 0x28000
movq -0x28(%rbp), %rdi
movq -0x90(%rbp), %rsi
movl -0x98(%rbp), %r14d
movq -0x80(%rbp), %rax
movl 0x14(%rax), %ebx
movq -0x80(%rbp), %rax
movq (%rax), %r11
movl -0x94(%rbp), %eax
movl %eax, %r10d
xorl %ecx, %ecx
movl $0x35c, %r8d            # imm = 0x35C
movl $0x280, %r9d            # imm = 0x280
leaq -0x110(%rbp), %rax
movl %ecx, %edx
movl %r14d, (%rsp)
movl %ebx, 0x8(%rsp)
movl $0x1, 0x10(%rsp)
movq %r11, 0x18(%rsp)
movq %r10, 0x20(%rsp)
movq %rax, 0x28(%rsp)
callq 0x3620
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x3400
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
leaq 0xa4a2(%rip), %rdx      # 0xe132
callq 0x30b0
movq -0x28(%rbp), %rdi
leaq 0xa4a0(%rip), %rsi      # 0xe140
xorl %edx, %edx
callq 0x3280
movq %rax, -0x118(%rbp)
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
leaq -0x118(%rbp), %rdx
movl $0x1, %ecx
callq 0x31a0
testb $0x1, -0x62(%rbp)
je 0x3cd2
callq 0x4530
movq -0x28(%rbp), %rdi
movq -0x80(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
movl $0x1, %ecx
callq 0x3480
movq %rax, -0x120(%rbp)
cmpq $0x0, -0x120(%rbp)
jne 0x3d1d
movq 0xf2e0(%rip), %rax      # 0x12fe0
movq (%rax), %rdi
leaq 0xa447(%rip), %rsi      # 0xe151
movb $0x0, %al
callq 0x3590
movl $0x1, -0x14(%rbp)
jmp 0x3f91
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq -0x120(%rbp), %rdx
callq 0x32e0
cmpl $0x0, %eax
jne 0x3d5a
movq 0xf2a3(%rip), %rax      # 0x12fe0
movq (%rax), %rdi
leaq 0xa426(%rip), %rsi      # 0xe16d
movb $0x0, %al
callq 0x3590
movl $0x1, -0x14(%rbp)
jmp 0x3f91
testb $0x1, -0x63(%rbp)
je 0x3d93
movq 0xf261(%rip), %rax      # 0x12fc8
movq (%rax), %rax
movq %rax, -0x2d0(%rbp)
movl $0x1f02, %edi           # imm = 0x1F02
callq 0x31c0
movq -0x2d0(%rbp), %rdi
movq %rax, %rdx
leaq 0xa3fa(%rip), %rsi      # 0xe186
movb $0x0, %al
callq 0x3590
movl $0xb71, %edi            # imm = 0xB71
callq 0x3340
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
leaq -0x1a8(%rbp), %rdx
callq 0x36d0
movl -0x5c(%rbp), %edi
callq 0xb520
movl -0x58(%rbp), %edi
callq 0xb860
movl -0x54(%rbp), %edi
callq 0xb770
movl -0x50(%rbp), %edi
callq 0xb5f0
movl -0x48(%rbp), %edi
callq 0xb3e0
movl -0x4c(%rbp), %edi
callq 0xb4a0
cvtsi2ssl -0x40(%rbp), %xmm0
callq 0xb6b0
movb -0x38(%rbp), %al
andb $0x1, %al
movzbl %al, %edi
callq 0xb640
movb -0x37(%rbp), %al
andb $0x1, %al
movzbl %al, %edi
callq 0xba10
cmpl $0x0, -0x3c(%rbp)
jge 0x3e17
movl $0x1, %edi
callq 0xb910
jmp 0x3e26
xorl %edi, %edi
callq 0xb910
movl -0x3c(%rbp), %edi
callq 0xb970
callq 0x6540
movl -0x1a0(%rbp), %edi
movl -0x19c(%rbp), %esi
callq 0x45d0
callq 0x4660
movq $0x20000, -0x270(%rbp) # imm = 0x20000
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq -0x270(%rbp), %rdx
leaq -0x268(%rbp), %rcx
callq 0x3230
cmpl $0x0, %eax
jne 0x3e8e
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movl $0x21, %edx
leaq -0x268(%rbp), %rcx
callq 0x3510
cmpl $0x0, %eax
je 0x3f1c
cmpl $0x16, -0x268(%rbp)
jne 0x3efb
leaq -0x2c8(%rbp), %rdi
leaq -0x268(%rbp), %rsi
movl $0x58, %edx
callq 0x3300
movl -0x290(%rbp), %eax
cmpl -0x1a0(%rbp), %eax
jne 0x3ecb
movl -0x28c(%rbp), %eax
cmpl -0x19c(%rbp), %eax
je 0x3ef9
movl -0x290(%rbp), %eax
movl %eax, -0x1a0(%rbp)
movl -0x28c(%rbp), %eax
movl %eax, -0x19c(%rbp)
movl -0x1a0(%rbp), %edi
movl -0x19c(%rbp), %esi
callq 0x45d0
jmp 0x3e41
jmp 0x3f1a
cmpl $0x21, -0x268(%rbp)
jne 0x3f18
movq -0x230(%rbp), %rax
cmpq -0x118(%rbp), %rax
jne 0x3f16
jmp 0x3f44
jmp 0x3f18
jmp 0x3f1a
jmp 0x3f1c
callq 0x6170
callq 0x4790
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x3700
imull $0x3e8, -0x60(%rbp), %edi # imm = 0x3E8
callq 0x3580
jmp 0x3e41
callq 0x6530
testb $0x1, -0x62(%rbp)
je 0x3f54
callq 0x4550
movq -0x28(%rbp), %rdi
xorl %eax, %eax
movl %eax, %edx
movq %rdx, %rsi
callq 0x32e0
movq -0x28(%rbp), %rdi
movq -0x120(%rbp), %rsi
callq 0x3210
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x3640
movq -0x28(%rbp), %rdi
callq 0x3730
movl $0x0, -0x14(%rbp)
movl -0x14(%rbp), %eax
addq $0x2f0, %rsp            # imm = 0x2F0
popq %rbx
popq %r14
popq %rbp
retq