// File: /workspace/github_cpp_makefile_star2_O2/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 0x98a8
movq %rax, 0x20(%rsp)
movq %r15, %rdi
movl %ebx, %esi
callq 0x98a8
movq %rax, %r14
movq %r15, 0x10(%rsp)
movq %r15, %rdi
movl %ebp, %esi
movl %ebx, %edx
callq 0x99d8
movq %rax, %r13
leaq 0x28(%rsp), %rbx
movq %rbx, %rdi
callq 0xe148
xorpd %xmm0, %xmm0
andq $0x0, 0x80(%rsp)
movapd %xmm0, 0x70(%rsp)
orq $-0x1, 0x8(%rbx)
movabsq $0x7fefffffffffffff, %rax # imm = 0x7FEFFFFFFFFFFFFF
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x34(%r14)
jle 0x51bc
movq $0x0, 0x18(%rsp)
leaq 0x13652(%rip), %r15     # 0x18420
pushq $-0x1
popq %r14
leaq 0x48(%rsp), %rbp
leaq 0x12fa2(%rip), %rax     # 0x17d80
addq $0x10, %rax
movq %rax, 0xa0(%rsp)
movq %r13, %r12
movq %r13, 0xa8(%rsp)
movq (%r12), %r12
cmpq %r13, %r12
je 0x50dd
leaq 0x18(%r12), %rax
movq %rax, 0x68(%rsp)
movq %r15, %r13
movq 0x20(%rsp), %rax
movq 0x68(%rax), %rax
movq (%r13), %r13
cmpq %r15, %r13
je 0x50d0
movq 0x10(%r13), %rcx
movq 0xc8(%rcx), %rdx
movslq (%rdx), %rdx
imulq $0x58, %rdx, %rdx
cmpl $0x0, 0xc(%rax,%rdx)
jle 0x4e18
movq 0x68(%rcx), %rsi
movq 0x70(%rcx), %rcx
subq %rsi, %rcx
movq 0x18(%r12), %r8
movq 0x20(%r12), %rdi
subq %r8, %rdi
sarq $0x2, %rdi
sarq $0x2, %rcx
cmpq %rcx, %rdi
cmovaeq %rcx, %rdi
decl %edi
movl %r14d, %edx
leal 0x1(%rdx), %r9d
cmpl %edi, %r9d
ja 0x4e85
movl %r9d, %r10d
movl (%r8,%r10,4), %r11d
cmpl (%rsi,%r10,4), %r11d
jne 0x4e87
movl %r9d, %edx
jmp 0x4e6a
movl %edi, %edx
testl %edx, %edx
jle 0x4e18
decl %ecx
cmpl %ecx, %edx
je 0x4e18
movl %edx, %ebx
leaq (%rsi,%rbx,4), %rdx
leaq 0xb0(%rsp), %rdi
movq %rbp, %rcx
callq 0x6940
movq 0x10(%r13), %rax
shlq $0x2, %rbx
addq 0x68(%rax), %rbx
movq 0x70(%rax), %rdx
movq %rbp, %rdi
movq %rbx, %rsi
leaq 0x88(%rsp), %rcx
callq 0x6940
movq 0x60(%rsp), %rax
cvtsi2sdl 0x4c(%rax), %xmm0
movq 0x10(%r13), %rbx
cvtsi2sdl 0x40(%rbx), %xmm1
divsd %xmm1, %xmm0
cvtsi2sdl 0x132f7(%rip), %xmm1 # 0x181e0
divsd %xmm1, %xmm0
callq 0x2060
cvttsd2si %xmm0, %esi
movq 0xc8(%rbx), %rax
movslq (%rax), %rax
movq 0x20(%rsp), %rcx
movq 0x68(%rcx), %rcx
movq 0xa0(%rsp), %rdx
movq %rdx, 0x88(%rsp)
imulq $0x58, %rax, %rax
movupd 0x48(%rcx,%rax), %xmm0
leaq 0x90(%rsp), %rax
movupd %xmm0, (%rax)
movl 0x90(%rsp), %ebp
movl 0x94(%rsp), %eax
notl %eax
addl %ebp, %eax
addl 0x1329d(%rip), %eax     # 0x181e4
cmpl %esi, %eax
jl 0x50a4
movl %esi, 0xc(%rsp)
subl %esi, %ebp
js 0x4fef
movq 0x10(%r13), %rax
movl 0x58(%rax), %edx
decl %edx
movl 0x13282(%rip), %ebx     # 0x181ec
addl %edx, %ebx
leaq 0xb0(%rsp), %rdi
movl %ebp, %esi
movq 0x10(%rsp), %rcx
callq 0x5fb5
testl %eax, %eax
jns 0x4fef
leaq 0x48(%rsp), %rdi
movl %ebp, %esi
movl %ebx, %edx
movq 0x10(%rsp), %rcx
callq 0x5fb5
testl %eax, %eax
jns 0x4fef
movq 0x10(%r13), %rdi
addq $0x68, %rdi
movl %ebp, %esi
movl %ebx, %edx
movq 0x10(%rsp), %rcx
callq 0x62ef
movsd 0x38(%rsp), %xmm1
movsd %xmm0, 0x40(%rsp)
ucomisd %xmm0, %xmm1
jbe 0x4fef
leaq 0x70(%rsp), %rdi
movq 0x68(%rsp), %rsi
callq 0x6876
movsd 0x40(%rsp), %xmm0
movl %ebp, 0x30(%rsp)
movl %ebx, 0x34(%rsp)
movsd %xmm0, 0x38(%rsp)
movq 0x10(%r13), %rax
movq %rax, 0x18(%rsp)
movq 0x10(%r13), %rax
movl 0x5c(%rax), %esi
movl 0xc(%rsp), %edx
addl %esi, %edx
cmpl 0x131e2(%rip), %edx     # 0x181e4
jge 0x50a4
incl %esi
movl %esi, %ebx
subl 0x131da(%rip), %ebx     # 0x181ec
leaq 0xb0(%rsp), %rdi
movl %edx, 0xc(%rsp)
movq 0x10(%rsp), %rcx
callq 0x5fb5
testl %eax, %eax
jns 0x50a4
leaq 0x48(%rsp), %rdi
movl %ebx, %esi
movl 0xc(%rsp), %edx
movq 0x10(%rsp), %rcx
callq 0x5fb5
testl %eax, %eax
jns 0x50a4
movq 0x10(%r13), %rdi
addq $0x68, %rdi
movl %ebx, %esi
movl 0xc(%rsp), %edx
movq 0x10(%rsp), %rcx
callq 0x62ef
movsd 0x38(%rsp), %xmm1
movsd %xmm0, 0x40(%rsp)
ucomisd %xmm0, %xmm1
leaq 0x48(%rsp), %rbp
jbe 0x50a9
leaq 0x70(%rsp), %rdi
movq 0x68(%rsp), %rsi
callq 0x6876
movsd 0x40(%rsp), %xmm0
movl %ebx, 0x30(%rsp)
movl 0xc(%rsp), %eax
movl %eax, 0x34(%rsp)
movsd %xmm0, 0x38(%rsp)
movq 0x10(%r13), %rax
movq %rax, 0x18(%rsp)
leaq 0x48(%rsp), %rbp
leaq 0x88(%rsp), %rdi
callq 0xe154
movq %rbp, %rdi
callq 0x6f54
leaq 0xb0(%rsp), %rdi
callq 0x6f54
jmp 0x4e0f
movq 0xa8(%rsp), %r13
jmp 0x4df5
cmpl $0x0, 0x30(%rsp)
js 0x51bc
movq 0x60(%rsp), %rax
movl 0x4c(%rax), %ebp
cvtsi2sd %ebp, %xmm0
movq 0x18(%rsp), %rax
movl 0x40(%rax), %r15d
cvtsi2sd %r15d, %xmm1
divsd %xmm1, %xmm0
movl 0x130d3(%rip), %r14d    # 0x181e0
cvtsi2sd %r14d, %xmm1
divsd %xmm1, %xmm0
callq 0x2060
movsd %xmm0, 0x20(%rsp)
movl 0x130c4(%rip), %r12d    # 0x181ec
movl $0xf8, %edi
callq 0x21f0
movq %rax, %rbx
movq %rax, %rdi
callq 0xe020
movl $0x2, 0x8(%rbx)
leaq 0x68(%rbx), %rdi
leaq 0x70(%rsp), %rsi
callq 0x6876
cvttsd2si 0x20(%rsp), %eax
addl %r12d, %r12d
subl %r12d, %eax
imull %r15d, %r14d
imull %eax, %r14d
subl %ebp, %r14d
movq 0x18(%rsp), %rcx
movl 0x40(%rcx), %eax
movl %eax, 0x40(%rbx)
movl %r14d, 0x44(%rbx)
movsd 0x38(%rsp), %xmm0
movsd %xmm0, 0x48(%rbx)
leaq 0x30(%rsp), %rax
movupd (%rax), %xmm0
movupd %xmm0, 0x58(%rbx)
movl $0xc8, %edi
leaq (%rcx,%rdi), %rsi
addq %rbx, %rdi
callq 0x6876
movl $0xe0, %eax
movq 0x18(%rsp), %rsi
addq %rax, %rsi
movq %rbx, %rdi
addq %rax, %rdi
callq 0x6876
jmp 0x51be
xorl %ebx, %ebx
leaq 0x70(%rsp), %rdi
callq 0x6f54
leaq 0x28(%rsp), %rdi
callq 0xe154
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
callq 0x2200
jmp 0x522c
jmp 0x5217
movq %rax, %r14
leaq 0x88(%rsp), %rdi
callq 0xe154
leaq 0x48(%rsp), %rdi
callq 0x6f54
jmp 0x521f
movq %rax, %r14
jmp 0x522c
movq %rax, %r14
leaq 0xb0(%rsp), %rdi
callq 0x6f54
leaq 0x70(%rsp), %rdi
callq 0x6f54
leaq 0x28(%rsp), %rdi
callq 0xe154
movq %r14, %rdi
callq 0x2320