// File: /workspace/github_cpp_makefile_star2_O3/ynilu[P]elastic/simulator.cpp
// Function: get_best_OFDM_WB_light_path(int, int, Event&, Phy_graph&)
LightPath* get_best_OFDM_WB_light_path(int source, int destination, Event& event, Phy_graph& p_graph)
{
    Phy_node& src_node = p_graph.get_node(source);
    Phy_node& dst_node = p_graph.get_node(destination);

    LightPath* best_existing_lightpath = NULL;
    list<CandidatePath>& c_path_list = p_graph.get_path_list(source, destination);
    Spectrum best_path_spectrum;
    double current_weight;
    Path best_p_path;

    best_path_spectrum.slot_st = -1;
    best_path_spectrum.slot_ed = -1;
    best_path_spectrum.weight = DBL_MAX;

    if(dst_node.num_available_OFDM_receiver < 1)
    {
        return NULL;
    }

    for(auto &c_path : c_path_list)
    {
        for(auto &lp : exist_OFDM_light_path_list)
        {
            int split_node_i;
            unsigned int num_hops = lp->p_path.size();

            OFDMTransceiver& transmitter = src_node.OFDMtransmitter[lp->transmitter_index[0]];

            if(transmitter.num_available_sub_transceiver < 1)
            {
                continue;
            }

            if(c_path.path.size() < lp->p_path.size())
            {
                num_hops = c_path.path.size() - 1;
            }
            else
            {
                num_hops = lp->p_path.size() - 1;
            }

            split_node_i = num_hops;

            for(unsigned int node_i = 0; node_i <= num_hops; node_i++)
            {
                if(c_path.path[node_i] != lp->p_path[node_i])
                {
                    split_node_i = node_i - 1;
                    break;
                }
            }

            if(split_node_i < 1)
            {
                continue;
            }

            if(split_node_i == (int)lp->p_path.size()-1) // use OFDM WOB instead
            {
                continue;
            }


            Path trunk(lp->p_path.begin(), lp->p_path.begin() + split_node_i);
            Path branch(lp->p_path.begin() + split_node_i, lp->p_path.end());

            int trunk_require_slots = ceil(1.0 * event.bandwidth / lp->modulation_level / slot_capacity);

            Spectrum transmitter_sp = src_node.OFDMtransmitter[lp->transmitter_index.front()].spectrum;

            int num_used_slots = transmitter_sp.slot_ed - transmitter_sp.slot_st + 1;

            if(transceiver_slot_limit - num_used_slots < trunk_require_slots)
            {
                continue;
            }

            int t_slot_st;  // start slot for trunk
            int t_slot_ed;  // end slot for trunk

            int b_slot_st;  // start slot for branch
            int b_slot_ed;  // end slot for branch

            // spectrum over the exisiting LightPath
            t_slot_st = transmitter_sp.slot_st - trunk_require_slots;
            t_slot_ed = lp->spectrum.slot_st - 1;

            b_slot_st = t_slot_st;
            b_slot_ed = t_slot_ed + num_guardband_slot;

            if(t_slot_st >= 0)  // check for slot boundary
            {
                if(path_spectrum_available(trunk, t_slot_st, t_slot_ed, p_graph) < 0) // trunk spectrum available
                {
                    if(path_spectrum_available(branch, b_slot_st, b_slot_ed, p_graph) < 0) // branch spectrum available
                    {
                        current_weight = weigh_path_spectrum(lp->p_path, b_slot_st, b_slot_ed, p_graph);
                        if(current_weight < best_path_spectrum.weight)
                        {
                            best_p_path = c_path.path;
                            best_path_spectrum.slot_st = b_slot_st;
                            best_path_spectrum.slot_ed = b_slot_ed;
                            best_path_spectrum.weight = current_weight;
                            best_existing_lightpath = lp;
                        }
                    }
                }
            }

            // spectrum under the exisiting LightPath
            t_slot_st = lp->spectrum.slot_ed + 1;
            t_slot_ed = lp->spectrum.slot_ed + trunk_require_slots;

            b_slot_st = t_slot_st - num_guardband_slot;
            b_slot_ed = t_slot_ed;

            if(b_slot_ed < transceiver_slot_limit)  // check for slot boundary
            {
                if(path_spectrum_available(trunk, t_slot_st, t_slot_ed, p_graph) < 0) // trunk spectrum available
                {
                    if(path_spectrum_available(branch, b_slot_st, b_slot_ed, p_graph) < 0) // branch spectrum available
                    {
                        current_weight = weigh_path_spectrum(lp->p_path, b_slot_st, b_slot_ed, p_graph);
                        if(current_weight < best_path_spectrum.weight)
                        {
                            best_p_path = c_path.path;
                            best_path_spectrum.slot_st = b_slot_st;
                            best_path_spectrum.slot_ed = b_slot_ed;
                            best_path_spectrum.weight = current_weight;
                            best_existing_lightpath = lp;
                        }
                    }
                }
            }
        }
    }

    if(best_path_spectrum.slot_st < 0)
    {
        return NULL;
    }

    int require_slots = ceil(1.0 * event.bandwidth / best_existing_lightpath->modulation_level / slot_capacity);
    int available_bitrate = (require_slots - num_guardband_slot * 2) * best_existing_lightpath->modulation_level * slot_capacity - event.bandwidth;

    LightPath* path = new LightPath();
    path->type = LightPath::OFDM_WB;
    path->p_path = best_p_path;
    path->modulation_level = best_existing_lightpath->modulation_level;
    path->available_bitrate = available_bitrate;
    path->weight = best_path_spectrum.weight;
    path->spectrum = best_path_spectrum;
    path->transmitter_index = best_existing_lightpath->transmitter_index;
    path->receiver_index = best_existing_lightpath->receiver_index;
    return path;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %rcx, %r15
movq %rdx, 0x60(%rsp)
movl %esi, %ebx
movl %edi, %ebp
movq %rcx, %rdi
movl %ebp, %esi
callq 0xba88
movq %rax, 0x10(%rsp)
movq %r15, %rdi
movl %ebx, %esi
callq 0xba88
movq %rax, %r14
movq %r15, 0x8(%rsp)
movq %r15, %rdi
movl %ebp, %esi
movl %ebx, %edx
callq 0xbc76
movq %rax, %r15
leaq 0x18(%rsp), %rbx
movq %rbx, %rdi
callq 0x10be4
xorpd %xmm0, %xmm0
movapd %xmm0, 0x40(%rsp)
movq $0x0, 0x50(%rsp)
movq $-0x1, 0x8(%rbx)
movabsq $0x7fefffffffffffff, %rax # imm = 0x7FEFFFFFFFFFFFFF
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x34(%r14)
jle 0x6ea8
movq (%r15), %r10
movq %r15, 0x98(%rsp)
cmpq %r15, %r10
je 0x6ea8
movq $0x0, 0x30(%rsp)
leaq 0x119aa(%rip), %r12     # 0x18448
leaq 0xb0(%rsp), %r15
leaq 0x112c3(%rip), %rax     # 0x17d70
addq $0x10, %rax
movq %rax, 0xa0(%rsp)
movq 0x11988(%rip), %rbx     # 0x18448
cmpq %r12, %rbx
je 0x6db5
leaq 0x18(%r10), %rax
movq %rax, 0x58(%rsp)
movq %r10, 0xa8(%rsp)
movq 0x10(%rbx), %rax
movq 0xc8(%rax), %rcx
movslq (%rcx), %rcx
movq 0x10(%rsp), %rdx
movq 0x68(%rdx), %rdx
imulq $0x58, %rcx, %rcx
cmpl $0x0, 0xc(%rdx,%rcx)
jle 0x6da9
movq 0x68(%rax), %rsi
movq 0x70(%rax), %rax
subq %rsi, %rax
movq 0x18(%r10), %rdx
movq 0x20(%r10), %rcx
subq %rdx, %rcx
sarq $0x2, %rcx
sarq $0x2, %rax
cmpq %rax, %rcx
cmovaeq %rax, %rcx
decl %ecx
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
leal 0x1(%rdi), %r8d
movl (%rdx,%r8,4), %r9d
cmpl (%rsi,%r8,4), %r9d
jne 0x6b46
addl $0x2, %edi
cmpl %ecx, %edi
movl %r8d, %edi
jbe 0x6b2c
movl %ecx, %edi
testl %edi, %edi
jle 0x6da9
decl %eax
cmpl %eax, %edi
je 0x6da9
movl %edi, %r14d
leaq (%rsi,%r14,4), %rdx
leaq 0x80(%rsp), %rdi
movq %r15, %rcx
callq 0x8d80
movq 0x10(%rbx), %rax
shlq $0x2, %r14
addq 0x68(%rax), %r14
movq 0x70(%rax), %rdx
movq %r15, %r13
movq %r15, %rdi
movq %r14, %rsi
leaq 0x68(%rsp), %rcx
callq 0x8d80
movq 0x60(%rsp), %rax
cvtsi2sdl 0x4c(%rax), %xmm0
movq 0x10(%rbx), %r14
cvtsi2sdl 0x40(%r14), %xmm1
divsd %xmm1, %xmm0
xorps %xmm1, %xmm1
cvtsi2sdl 0x11653(%rip), %xmm1 # 0x18208
divsd %xmm1, %xmm0
callq 0x3070
cvttsd2si %xmm0, %ebp
movq 0xc8(%r14), %rax
movslq (%rax), %rax
movq 0x10(%rsp), %rcx
movq 0x68(%rcx), %rcx
movq 0xa0(%rsp), %rdx
movq %rdx, 0x68(%rsp)
imulq $0x58, %rax, %rax
movupd 0x48(%rcx,%rax), %xmm0
leaq 0x70(%rsp), %rax
movupd %xmm0, (%rax)
movl 0x70(%rsp), %r15d
movl 0x74(%rsp), %eax
notl %eax
addl %r15d, %eax
addl 0x11603(%rip), %eax     # 0x1820c
cmpl %ebp, %eax
jl 0x6d5a
subl %ebp, %r15d
js 0x6cb5
movq 0x10(%rbx), %rax
movl 0x58(%rax), %edx
decl %edx
movl 0x115ea(%rip), %r14d    # 0x18214
addl %edx, %r14d
leaq 0x80(%rsp), %rdi
movl %r15d, %esi
movq 0x8(%rsp), %rcx
callq 0x8248
testl %eax, %eax
jns 0x6cb5
movq %r13, %rdi
movl %r15d, %esi
movl %r14d, %edx
movq 0x8(%rsp), %rcx
callq 0x8248
testl %eax, %eax
jns 0x6cb5
movq 0x10(%rbx), %rdi
addq $0x68, %rdi
movl %r15d, %esi
movl %r14d, %edx
movq 0x8(%rsp), %rcx
callq 0x8632
movsd 0x28(%rsp), %xmm1
movsd %xmm0, 0x38(%rsp)
ucomisd %xmm0, %xmm1
jbe 0x6cb5
leaq 0x40(%rsp), %rdi
movq 0x58(%rsp), %rsi
callq 0x8c9c
movsd 0x38(%rsp), %xmm0
movl %r15d, 0x20(%rsp)
movl %r14d, 0x24(%rsp)
movsd %xmm0, 0x28(%rsp)
movq 0x10(%rbx), %rax
movq %rax, 0x30(%rsp)
movq 0x10(%rbx), %rax
movl 0x5c(%rax), %esi
addl %esi, %ebp
cmpl 0x11548(%rip), %ebp     # 0x1820c
jge 0x6d5a
incl %esi
movl %esi, %r14d
subl 0x1153e(%rip), %r14d    # 0x18214
leaq 0x80(%rsp), %rdi
movl %ebp, %edx
movq 0x8(%rsp), %rcx
callq 0x8248
testl %eax, %eax
jns 0x6d5a
movq %r13, %rdi
movl %r14d, %esi
movl %ebp, %edx
movq 0x8(%rsp), %rcx
callq 0x8248
testl %eax, %eax
jns 0x6d5a
movq 0x10(%rbx), %rdi
addq $0x68, %rdi
movl %r14d, %esi
movl %ebp, %edx
movq 0x8(%rsp), %rcx
callq 0x8632
movsd 0x28(%rsp), %xmm1
movsd %xmm0, 0x38(%rsp)
ucomisd %xmm0, %xmm1
jbe 0x6d5a
leaq 0x40(%rsp), %rdi
movq 0x58(%rsp), %rsi
callq 0x8c9c
movsd 0x38(%rsp), %xmm0
movl %r14d, 0x20(%rsp)
movl %ebp, 0x24(%rsp)
movsd %xmm0, 0x28(%rsp)
movq 0x10(%rbx), %rax
movq %rax, 0x30(%rsp)
leaq 0x68(%rsp), %rdi
callq 0x10bf0
movq 0xb0(%rsp), %rdi
testq %rdi, %rdi
je 0x6d81
movq 0xc0(%rsp), %rsi
subq %rdi, %rsi
callq 0x3230
movq 0x80(%rsp), %rdi
testq %rdi, %rdi
movq %r13, %r15
je 0x6da1
movq 0x90(%rsp), %rsi
subq %rdi, %rsi
callq 0x3230
movq 0xa8(%rsp), %r10
movq (%rbx), %rbx
cmpq %r12, %rbx
jne 0x6ada
movq (%r10), %r10
cmpq 0x98(%rsp), %r10
jne 0x6ab9
cmpl $0x0, 0x20(%rsp)
js 0x6ea8
movq 0x60(%rsp), %rax
movl 0x4c(%rax), %ebp
xorps %xmm0, %xmm0
cvtsi2sd %ebp, %xmm0
movq 0x30(%rsp), %r13
movl 0x40(%r13), %r15d
xorps %xmm1, %xmm1
cvtsi2sd %r15d, %xmm1
divsd %xmm1, %xmm0
movl 0x1140c(%rip), %r14d    # 0x18208
xorps %xmm1, %xmm1
cvtsi2sd %r14d, %xmm1
divsd %xmm1, %xmm0
callq 0x3070
movsd %xmm0, 0x10(%rsp)
movl 0x113fa(%rip), %r12d    # 0x18214
movl $0xf8, %edi
callq 0x3220
movq %rax, %rbx
movq %rax, %rdi
callq 0x10a4c
movl $0x2, 0x8(%rbx)
leaq 0x68(%rbx), %rdi
leaq 0x40(%rsp), %rsi
callq 0x8c9c
cvttsd2si 0x10(%rsp), %eax
addl %r12d, %r12d
subl %r12d, %eax
imull %r15d, %r14d
imull %eax, %r14d
subl %ebp, %r14d
movl 0x40(%r13), %eax
movl %eax, 0x40(%rbx)
movl %r14d, 0x44(%rbx)
movsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x48(%rbx)
leaq 0x20(%rsp), %rax
movupd (%rax), %xmm0
movupd %xmm0, 0x58(%rbx)
movl $0xc8, %edi
leaq (%rdi,%r13), %rsi
addq %rbx, %rdi
callq 0x8c9c
movl $0xe0, %eax
addq %rax, %r13
movq %rbx, %rdi
addq %rax, %rdi
movq %r13, %rsi
callq 0x8c9c
jmp 0x6eaa
xorl %ebx, %ebx
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x6ec1
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x3230
leaq 0x18(%rsp), %rdi
callq 0x10bf0
movq %rbx, %rax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %r14
movl $0xf8, %esi
movq %rbx, %rdi
jmp 0x6f3b
jmp 0x6f1b
movq %rax, %r14
leaq 0x68(%rsp), %rdi
callq 0x10bf0
movq 0xb0(%rsp), %rdi
testq %rdi, %rdi
je 0x6f23
movq 0xc0(%rsp), %rsi
subq %rdi, %rsi
callq 0x3230
jmp 0x6f23
movq %rax, %r14
jmp 0x6f40
movq %rax, %r14
movq 0x80(%rsp), %rdi
testq %rdi, %rdi
je 0x6f40
movq 0x90(%rsp), %rsi
subq %rdi, %rsi
callq 0x3230
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x6f57
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x3230
leaq 0x18(%rsp), %rdi
callq 0x10bf0
movq %r14, %rdi
callq 0x3370