<div class="standardContainer">
    <button onclick="exitToGanList();" class="ui large circular black icon button"><i class="angle left icon"></i></button>
    <div style="max-width: 300px; margin-top: 1em;">
        <button onclick='$("#gannetDetailEdit").slideToggle("fast");' class="ui mini basic right floated circular icon button" style="display: inline-block; margin-top: 2.5em;"><i class="ui edit icon"></i></button>
        <h1 class="ui header">
            <span class="ganetID"></span>
            <div class="sub header ganetName"></div>
        </h1>
        <div class="ui divider"></div>
        <p><span class="ganetDesc"></span></p>
        
    </div>
    <div id="gannetDetailEdit" class="ui form" style="margin-top: 1em; display:none;">
        <div class="ui divider"></div>
        <p>You can change the network name and description below. <br>The name and description is only for easy management purpose and will not effect the network operation.</p>
        <div class="field">
            <label>Network Name</label>
            <input type="text" id="gaNetNameInput" placeholder="">
          </div>
        <div class="field">
          <label>Network Description</label>
          <textarea id="gaNetDescInput" style="resize: none;"></textarea>
          <button onclick="saveNameAndDesc(this);" class="ui basic right floated button" style="margin-top: 0.6em;"><i class="ui save icon"></i> Save</button>
          <button onclick='$("#gannetDetailEdit").slideUp("fast");' class="ui basic right floated button" style="margin-top: 0.6em;"><i class="ui red remove icon"></i> Cancel</button>
        </div>
        <br><br>
    </div>
    <div class="ui divider"></div>
    <h2>Settings</h2>
    <div class="" style="overflow-x: auto;">
        <table class="ui basic celled unstackable table" style="min-width: 560px;">
            <thead>
                <tr>
                    <th colspan="4">IPv4 Auto-Assign</th>
                </tr>
            </thead>
            <tbody id="ganetRangeTable">
                
            </tbody>
        </table>
    </div>
    <br>
    <div class="ui form">
        <h3>Custom IP Range</h3>
        <p>Manual IP Range Configuration. The IP range must be within the selected CIDR range. 
        <br>Use <code>Utilities > IP to CIDR tool</code> if you are not too familiar with CIDR notations.</p>
        <div class="two fields">
            <div class="field">
                <label>IP Start</label>
                <input type="text" class="ganIpStart" placeholder="">
            </div>
            <div class="field">
                <label>IP End</label>
                <input type="text" class="ganIpEnd" placeholder="">
            </div>
        </div>
    </div>
    <button onclick="setNetworkRange();" class="ui basic button"><i class="ui blue save icon"></i> Save Settings</button>

    <div class="ui divider"></div>
    <h2>Members</h2>
    <p>To join this network using command line, type <code>sudo zerotier-cli join <span class="ganetID"></span></code> on your device terminal</p>
    <div class="ui checkbox" style="margin-bottom: 1em;">
        <input id="showUnauthorizedMembers" type="checkbox" onchange="changeUnauthorizedVisibility(this.checked);">
        <label>Show Unauthorized Members</label>
    </div>
    <div class="" style="overflow-x: auto;">
        <table class="ui celled unstackable table">
            <thead>
                <tr>
                    <th>Auth</th>
                    <th>Address</th>
                    <th>Name</th>
                    <th>Managed IP</th>
                    <th>Authorized Since</th>
                    <th>Version</th>
                    <th>Remove</th>
                </tr>
            </thead>
            <tbody id="networkMemeberTable">
                <tr>
                    
                </tr>
            </tbody>
        </table>
    </div>
    <br><br>
</div>
<script>
    $(".checkbox").checkbox();
    var currentGANetID = "";
    var currentGANNetMemeberListener = undefined;
    var currentGaNetDetails = {};
    var currentGANMemberList = [];
    var netRanges = {
            "10.147.17.*": "10.147.17.0/24",
            "10.147.18.*": "10.147.18.0/24",
            "10.147.19.*": "10.147.19.0/24",
            "10.147.20.*": "10.147.20.0/24",
            "10.144.*.*": "10.144.0.0/16",
            "10.241.*.*": "10.241.0.0/16",
            "10.242.*.*": "10.242.0.0/16",
            "10.243.*.*": "10.243.0.0/16",
            "10.244.*.*": "10.244.0.0/16",
            "172.22.*.*": "172.22.0.0/15",
            "172.23.*.*": "172.23.0.0/16",
            "172.24.*.*": "172.24.0.0/14",
            "172.25.*.*": "172.25.0.0/16",
            "172.26.*.*": "172.26.0.0/15",
            "172.27.*.*": "172.27.0.0/16",
            "172.28.*.*": "172.28.0.0/15",
            "172.29.*.*": "172.29.0.0/16",
            "172.30.*.*": "172.30.0.0/15",
            "192.168.191.*": "192.168.191.0/24",
            "192.168.192.*": "192.168.192.0/24",
            "192.168.193.*": "192.168.193.0/24",
            "192.168.194.*": "192.168.194.0/24",
            "192.168.195.*": "192.168.195.0/24",
            "192.168.196.*": "192.168.196.0/24"
        }

    function generateIPRangeTable(netRanges) {
        $("#ganetRangeTable").empty();
        const tableBody = document.getElementById('ganetRangeTable');
        const cidrs = Object.values(netRanges);
        
        // Set the number of rows and columns to display in the table
        const numRows = 6;
        const numCols = 4;

        let row = document.createElement('tr');
        let col = 0;
        for (let i = 0; i < cidrs.length; i++) {
            if (col >= numCols) {
            tableBody.appendChild(row);
            row = document.createElement('tr');
            col = 0;
            }

            const td = document.createElement('td');
            td.setAttribute('class', `clickable iprange`);
            td.setAttribute('CIDR', cidrs[i]);
            td.innerHTML = cidrs[i];
            let thisCidr = cidrs[i];
            td.onclick = function(){
                selectNetworkRange(thisCidr, td);
            };
            
            row.appendChild(td);
            col++;
        }

        // Add any remaining cells to the table
        if (col > 0) {
            for (let i = col; i < numCols; i++) {
                row.appendChild(document.createElement('td'));
            }
            tableBody.appendChild(row);
        }
    }

    function highlightCurrentGANetCIDR(){
        var currentCIDR = currentGaNetDetails.routes[0].target;
        $(".iprange").each(function(){
            if ($(this).attr("CIDR") == currentCIDR){
                $(this).addClass("active");
                populateStartEndIpByCidr(currentCIDR);
            }
        })
    }

    function populateStartEndIpByCidr(cidr){
        function cidrToRange(cidr) {
            var range = [2];
            cidr = cidr.split('/');
            var start = ip2long(cidr[0]);
            range[0] = long2ip(start);
            range[1] = long2ip(Math.pow(2, 32 - cidr[1]) + start - 1);
            return range;
        }
        var cidrRange = cidrToRange(cidr);
        $(".ganIpStart").val(cidrRange[0]);
        $(".ganIpEnd").val(cidrRange[1]);
    }

    function selectNetworkRange(cidr, object){
        populateStartEndIpByCidr(cidr);

        $(".iprange.active").removeClass("active");
        $(object).addClass("active");
    }

    function setNetworkRange(){
        var ipstart = $(".ganIpStart").val().trim();
        var ipend = $(".ganIpEnd").val().trim();

        if (ipstart == ""){
            $(".ganIpStart").parent().addClass("error");
        }else{
            $(".ganIpStart").parent().removeClass("error");
        }

        if (ipend == ""){
            $(".ganIpEnd").parent().addClass("error");
        }else{
            $(".ganIpEnd").parent().removeClass("error");
        }

        //Get CIDR from selected range group
        var cidr = $(".iprange.active").attr("cidr");

        $.ajax({
            url: "/api/gan/network/setRange",
            metohd: "POST",
            data:{
                netid: currentGANetID,
                cidr: cidr,
                ipstart: ipstart,
                ipend: ipend
            },
            success: function(data){
                if (data.error != undefined){
                    msgbox(data.error, false, 5000)
                }else{
                    msgbox("Network Range Updated")
                }
            }
        })
    }


    function saveNameAndDesc(object=undefined){
        var name = $("#gaNetNameInput").val();
        var desc = $("#gaNetDescInput").val();
        if (object != undefined){
            $(object).addClass("loading");
        }
        $.ajax({
            url: "/api/gan/network/name",
            method: "POST",
            data: {
                netid: currentGANetID,
                name: name,
                desc: desc,
            },
            success: function(data){
                initNetNameAndDesc();
                if (object != undefined){
                    $(object).removeClass("loading");
                    msgbox("Network Metadata Updated");
                }
                $("#gannetDetailEdit").slideUp("fast");
            }
        });
    }

    function initNetNameAndDesc(){
        //Get the details of the net
        $.get("/api/gan/network/name?netid=" + currentGANetID, function(data){
            if (data.error !== undefined){
                msgbox(data.error, false, 6000);
            }else{
                $("#gaNetNameInput").val(data[0]);
                $(".ganetName").html(data[0]);
                $("#gaNetDescInput").val(data[1]);
                $(".ganetDesc").text(data[1]);
            }
        });
    }

    function initNetDetails(){
         //Get the details of the net
         $.get("/api/gan/network/list?netid=" + currentGANetID, function(data){
            if (data.error !== undefined){
                msgbox(data.error, false, 6000);
            }else{
                currentGaNetDetails = data;
                highlightCurrentGANetCIDR();
            }
        });
    }

    //Handle delete IP from memeber
    function deleteIpFromMemeber(memberid, ip){
        $.ajax({
            url: "/api/gan/members/ip",
            metohd: "POST",
            data: {
                netid: currentGANetID, 
                memid: memberid,
                opr: "del",
                ip: ip,
            },
            success: function(data){
                if (data.error != undefined){
                    msgbox(data.error, false, 5000);
                }else{
                    msgbox("IP removed from member " + memberid)
                }
                renderMemeberTable();
            }
        });
    }

    function addIpToMemeberFromInput(memberid, newip){
        function isValidIPv4Address(address) {
            // Split the address into its 4 components
            const parts = address.split('.');
            
            // Check that there are 4 components
            if (parts.length !== 4) {
                return false;
            }
            
            // Check that each component is a number between 0 and 255
            for (let i = 0; i < 4; i++) {
                const part = parseInt(parts[i], 10);
                if (isNaN(part) || part < 0 || part > 255) {
                return false;
                }
            }
            
            // The address is valid
            return true;
        }

        if (!isValidIPv4Address(newip)){
            msgbox(newip + " is not a valid IPv4 address", false, 5000)
            return
        }

        $.ajax({
            url: "/api/gan/members/ip",
            metohd: "POST",
            data: {
                netid: currentGANetID, 
                memid: memberid,
                opr: "add",
                ip: newip,
            },
            success: function(data){
                if (data.error != undefined){
                    msgbox(data.error, false, 5000);
                }else{
                    msgbox("IP added to member " + memberid)
                }
                renderMemeberTable();
            }
        })
    }

    //Member table populate
    function renderMemeberTable(forceUpdate = false) {
        $.ajax({
            url: '/api/gan/members/list?netid=' + currentGANetID + '&detail=true',
            type: 'GET',
            success: function(data) {
                const tableBody = $('#networkMemeberTable');
                data.sort((a, b) => a.address.localeCompare(b.address));
                //Check if the new object equal to the old one
                if (objectEqual(currentGANMemberList, data) && !forceUpdate){
                    //Do not need to update it
                    return;
                }
                tableBody.empty();
                currentGANMemberList = data;

                var authroziedCount = 0;
                data.forEach((member) => {
                    let lastAuthTime = new Date(member.lastAuthorizedTime).toLocaleString();
                    if (member.lastAuthorizedTime == 0){
                        lastAuthTime = "Never";
                    }

                    let version = `${member.vMajor}.${member.vMinor}.${member.vProto}.${member.vRev}`;
                    if (member.vMajor == -1){
                        version = "Unknown";
                    }

                    let authorizedCheckbox = `<div class="ui fitted checkbox">
                        <input type="checkbox" addr="${member.address}" name="isAuthrozied" onchange="handleMemberAuth(this);">
                        <label></label>
                    </div>`;
                    if (member.authorized){
                        authorizedCheckbox = `<div class="ui fitted checkbox">
                            <input type="checkbox" addr="${member.address}" name="isAuthrozied" onchange="handleMemberAuth(this);" checked="">
                            <label></label>
                        </div>`
                    }

                    let rowClass = "authorized";
                    let unauthorizedStyle = "";
                    if (!$("#showUnauthorizedMembers")[0].checked && !member.authorized){
                        unauthorizedStyle = "display:none;";
                    }
                    if (!member.authorized){
                        rowClass = "unauthorized";
                    }else{
                        authroziedCount++;
                    }
                    
                    let assignedIp = "";

                    if (member.ipAssignments.length == 0){
                        assignedIp = "Not assigned"
                    }else{
                        assignedIp = `<div class="ui list">`
                        member.ipAssignments.forEach(function(thisIp){
                            assignedIp += `<div class="item" style="width: 100%;">${thisIp} <a style="cursor:pointer; float: right;" title="Remove IP" onclick="deleteIpFromMemeber('${member.address}','${thisIp}');"><i class="red remove icon"></i></a></div>`;
                        })
                        assignedIp += `</div>`
                    }
                    const row = $(`<tr class="GANetMemberEntity ${rowClass}" style="${unauthorizedStyle}">`);
                    row.append($(`<td class="GANetMember ${rowClass}" style="text-align: center;">`).html(authorizedCheckbox));
                    row.append($('<td>').text(member.address));
                    row.append($('<td>').html(`<span class="memberName" addr="${member.address}"></span> <a style="cursor:pointer; float: right;" title="Edit Memeber Name" onclick="renameMember('${member.address}');"><i class="grey edit icon"></i></a>`));
                    row.append($('<td>').html(`${assignedIp}
                        <div class="ui action mini fluid input" style="min-width: 200px;">
                            <input type="text" placeholder="IPv4" onchange="$(this).val($(this).val().trim());">
                            <button onclick="addIpToMemeberFromInput('${member.address}',$(this).parent().find('input').val());" class="ui basic icon button">
                                <i class="add icon"></i>
                            </button>
                        </div>`));
                    row.append($('<td>').text(lastAuthTime));
                    row.append($('<td>').text(version));
                    row.append($(`<td title="Deauthorize & Delete Memeber" style="text-align: center;" onclick="handleMemberDelete('${member.address}');">`).html(`<button class="ui basic mini icon button"><i class="red remove icon"></i></button>`));

                    tableBody.append(row);
                });

                if (data.length == 0){
                    tableBody.append(`<tr>
                        <td colspan="7"><i class="green check circle icon"></i> No member has joined this network yet.</td>
                    </tr>`);
                }

                if (data.length > 0 && authroziedCount == 0 && !$("#showUnauthorizedMembers")[0].checked){
                    //All nodes are unauthorized. Show tips to enable unauthorize display
                    tableBody.append(`<tr>
                        <td colspan="7"><i class="yellow exclamation circle icon"></i> Unauthorized nodes detected. Enable "Show Unauthorized Member" to change member access permission.</td>
                    </tr>`);
                }

                initNameForMembers();
            },
            error: function(xhr, status, error) {
                console.log('Error:', error);
            }
        });
    }

    function initNameForMembers(){
        $(".memberName").each(function(){
            let addr = $(this).attr("addr");
            let targetDOM = $(this);
            $.ajax({
                url: "/api/gan/members/name",
                method: "POST",
                data: {
                    netid: currentGANetID,
                    memid: addr,
                },
                success: function(data){
                    if (data.error != undefined){
                        $(targetDOM).text("N/A");
                    }else{
                        $(targetDOM).text(data.Name);
                    }
                }
            });
        })
    }

    function renameMember(targetMemberAddr){
        if (targetMemberAddr == ""){
            msgbox("Member address cannot be empty", false, 5000)
            return
        }

        let newname = prompt("Enter a easy manageable name for " + targetMemberAddr, "");
        if (newname != null && newname.trim() != "") {
          $.ajax({
            url: "/api/gan/members/name",
            method: "POST",
            data: {
                netid: currentGANetID,
                memid: targetMemberAddr,
                name: newname
            },
            success: function(data){
                if (data.error != undefined){
                    msgbox(data.error, false, 6000);
                }else{
                    msgbox("Member Name Updated"); 
                }
                renderMemeberTable(true);
            }
          })
        }
    }

    //Helper function to check if two objects are equal recursively
    function objectEqual(obj1, obj2) {
        // compare types
        if (typeof obj1 !== typeof obj2) {
            return false;
        }

        // compare values
        if (typeof obj1 !== 'object' || obj1 === null) {
            return obj1 === obj2;
        }

        const keys1 = Object.keys(obj1);
        const keys2 = Object.keys(obj2);

        // compare keys
        if (keys1.length !== keys2.length) {
            return false;
        }

        for (const key of keys1) {
            if (!keys2.includes(key)) {
            return false;
            }

            // recursively compare values
            if (!objectEqual(obj1[key], obj2[key])) {
                return false;
            }
        }

        return true;
    }


    function changeUnauthorizedVisibility(visable){
        if(visable){
            $(".GANetMemberEntity.unauthorized").show();
        }else{
            $(".GANetMemberEntity.unauthorized").hide();
        }
    }

    function handleMemberAuth(object){
        let targetMemberAddr = $(object).attr("addr");
        let isAuthed = object.checked;
        $.ajax({
            url: "/api/gan/members/authorize",
            method: "POST",
            data: {
                netid:currentGANetID, 
                memid: targetMemberAddr, 
                auth: isAuthed
            },
            success: function(data){
                if (data.error != undefined){
                    msgbox(data.error, false, 6000);
                }else{
                    if (isAuthed){
                        msgbox("Member Authorized");
                    }else{
                        msgbox("Member Deauthorized");
                    }
                    
                }

                renderMemeberTable(true);
            }
        })
    }

    function handleMemberDelete(addr){
        if (confirm("Confirm delete member " + addr + " ?")){
            $.ajax({
                url: "/api/gan/members/delete",
                method: "POST",
                data: {
                    netid:currentGANetID, 
                    memid: addr, 
                },
                success: function(data){
                    if (data.error != undefined){
                        msgbox(data.error, false, 6000);
                    }else{
                        msgbox("Member Deleted");
                    }
                    renderMemeberTable(true);
                }
            });
        }
       
    }

    //Entry points
    function initGanetDetails(ganetId){
        currentGANetID = ganetId;
        $(".ganetID").text(ganetId);
        initNetNameAndDesc(ganetId);
        generateIPRangeTable(netRanges);
        initNetDetails();
        renderMemeberTable(true);

        //Setup a listener to listen for member list change
        if (currentGANNetMemeberListener == undefined){
            currentGANNetMemeberListener = setInterval(function(){
                if ($('#networkMemeberTable').length > 0 && currentGANetID){
                    renderMemeberTable();
                }
            }, 3000);
        }
        
    }

    //Exit point
    function exitToGanList(){
        $("#gan").load("./components/gan.html", function(){
            if (tabSwitchEventBind["gan"]){
                tabSwitchEventBind["gan"]();
            }
        });
    }

    
</script>