/*
This routines in this file are specific to the membership functionality. So far, it's
supporting the IMemV1 and IERC721ExV1M interfaces.

interface IMemV1:
    function memInfo() external view returns (uint256 renewPennies, uint256 penniesPerDay, uint256 mintHours, uint256 renewHours);
    function memIsTimeLeft(uint256 _tokenId) external view returns(bool bActive, uint256 remainingPrePaidHours, uint256 remainingIntrinsicHours);
    function memBalance(uint256 _tokenId) external view returns(uint256 BalanaceWei, uint256 UnsettledWei);
    function memWithdraw(uint256 _tokenId) external returns(bool);
    function memSettleTitled(uint256 _tokenId) external;
    function memGrantHours(uint256 _tokenId, uint256 _addHours) external;
    function memRenew(uint256 _tokenId) external payable;
    *function memLockStatus(uint256 _tokenId) external view returns(bool bLockedState);
    *function memLockToggle(uint256 _tokenId, bool _bState) external;
    function memTreasuryBalance() external view returns(uint256 BalanceWei);

interface IERC721ExV1M:
    function tokenOf(address _theOwner) external view returns (uint256 tokenId);
    function IsSoulBound() external returns (bool bSoulBound);

Information routines are at the top.
Helper functions in the middle.
Button handler functions are at the bottom.
Main two functions are at the bottom.
*/

// Routines that are specific to IMemV1

function writeMemInfo(_index) {
    let minInfo = arrProjects[_index]['D']['memInfoObj'];
    //console.log("mintHours: " + minInfo['mintHours']);
    // memMintHoursId
    let theObj = document.getElementById("memMintHoursId" + _index);
    if (null != theObj) {
        theObj.innerHTML = Number(minInfo['mintHours']);
    }
    //console.log("penniesPerDay: " + minInfo['penniesPerDay']);
    // memChargeRateId
    theObj = document.getElementById("memChargeRateId" + _index);
    if (null != theObj) {
        theObj.innerHTML = '$' + (Number(minInfo['penniesPerDay']) / 100);
    }
    //console.log("renewHours: " + minInfo['renewHours']);
    // memRenewHoursId
    theObj = document.getElementById("memRenewHoursId" + _index);
    if (null != theObj) {
        theObj.innerHTML = Number(minInfo['renewHours']);
    }
    let theRenewCost = '$' + (Number(minInfo['renewPennies']) / 100);
    //console.log("renewPennies: " + minInfo['renewPennies']);
    // memCostRenewId
    theObj = document.getElementById("memCostRenewId" + _index);
    if (null != theObj) {
        theObj.innerHTML = theRenewCost;
    }

    // set innerHTML of $memRenewMinId
    theObj = document.getElementById("memRenewMinId" + _index);
    if (null != theObj) {
        theObj.innerHTML = "Renew Min: " + theRenewCost + ", ";;
    }

}

function writeIsTimeLeft(_index) {

    let memIsTimeLeftObj = arrProjects[_index]['D']['memIsTimeLeftObj'];

    if (memIsTimeLeftObj != null) {
        // Active/Inactive status
        let theObj = document.getElementById("memActiveId" + _index);
        if (null != theObj) {
            if (memIsTimeLeftObj['bActive']) {
                // membership is active
                theObj.innerHTML = 'Active';
            } else {
                // membership is inactive
                theObj.innerHTML = 'Inactive';
            }
        }
        // Timeleft
        let theTotalHours = parseInt(Number(memIsTimeLeftObj['remainingIntrinsicHours']) + Number(memIsTimeLeftObj['remainingPrePaidHours']));
        //console.log("TotalHours: " + theTotalHours);
        let theDays;
        let theRemainingHours;
        if (theTotalHours > 24) {
            theDays = parseInt(theTotalHours / 24);
            theRemainingHours = parseInt(theTotalHours - (theDays * 24));
        } else {
            theDays = parseInt(0);
            theRemainingHours = parseInt(theTotalHours);
        }

        theObj = document.getElementById("memDaysId" + _index);
        if (null != theObj) {
            theObj.innerHTML = parseInt(theDays);
        }
        theObj = document.getElementById("memHoursId" + _index);
        if (null != theObj) {
            theObj.innerHTML = parseInt(theRemainingHours);
        }

        // more stuff
        if (arrProjects[_index]['D']['memIsTimeLeftObj'].bActive) {

            // set innerHTML of "memRenewExtend"
            theObj = document.getElementById("memRenewExtendBtn" + _index);
            if (null != theObj) {
                theObj.innerHTML = "EXTEND";
                theObj.disabled = false;
            }
        } else {
            // Just show the section above
            theObj = document.getElementById("memRenewMinId" + _index);
            if (null != theObj) {
                theObj.style.display = 'inline';
            }

            // set innerHTML of "memRenewExtend"
            theObj = document.getElementById("memRenewExtendBtn" + _index);
            if (null != theObj) {
                theObj.innerHTML = "RENEW";
                theObj.disabled = false;
            }
        }

    } else {
        // Active/Inactive status
        let theObj = document.getElementById("memActiveId" + _index);
        if (null != theObj) {
            theObj.innerHTML = 'nonexistent';
        }

        theObj = document.getElementById("memDaysId" + _index);
        if (null != theObj) {
            theObj.innerHTML = parseInt(0);
        }
        theObj = document.getElementById("memHoursId" + _index);
        if (null != theObj) {
            theObj.innerHTML = parseInt(0);
        }

        theObj = document.getElementById("memRenewExtendBtn" + _index);
        if (null != theObj) {
            theObj.innerHTML = "EXTEND";
            theObj.disabled = true;
        }
    }
}



// Parameter:
// { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }
// Returns:
// { "internalType": "bool", "name": "bActive", "type": "bool" }, 
// { "internalType": "uint256", "name": "remainingPrePaidHours", "type": "uint256" }, 
// { "internalType": "uint256", "name": "remainingIntrinsicHours", "type": "uint256" }
//
// Note that if the token Id doesn't exist, the call reverts thus we handle the error.
async function IMemIsTimeLeft(_index) {
    // Note that this call will timeout if we call with bad data, thus check the token
    // number is within bounds.
    if (arrProjects[_index]['D']['memTokenId'] > 0) {
        document.body.style.cursor = 'wait';
        arrProjects[_index]['I']['IMemV1']['Obj'].methods.memIsTimeLeft(arrProjects[_index]['D']['memTokenId']).call()
            .catch(function (err) {
                console.log('failed memIsTimeLeft call');
                // handle error
                document.body.style.cursor = 'default';
            }).then(memIsTimeLeftObj => {
                arrProjects[_index]['D']['memIsTimeLeftObj'] = null;
                if (null != memIsTimeLeftObj) {
                    // What did we get here? memIsTimeLeftObj
                    arrProjects[_index]['D']['memIsTimeLeftObj'] = memIsTimeLeftObj;
                    writeIsTimeLeft(_index);
                    //arrProjects[_index]['W']['istimeLeft'] = true;
                    showPage(_index);
                } else {
                    console.log('recieved null');
                    writeIsTimeLeft(_index);
                    showPage(_index);
                }
                document.body.style.cursor = 'default';
            });

    }
}

function writeMemTreasury(_index) {
    let BalanceWei = arrProjects[_index]['D']['BalanceWei'];

    let theObj = document.getElementById("memTreasuryBalanceId" + _index);
    if (null != theObj) {
        let theWei = BigInt((BigInt(BalanceWei) * BigInt(100)) / BigInt(1000000000000000000));
        //console.log("TreasuryTfuel: " + (Number(theWei) / 100));
        theObj.innerHTML = (Number(theWei) / 100) + ' Tfuel';
    }
}

function writeHolderMemButtons(_index) {
    //console.log('writeHolderMemButtons(): ' + _index);

    let memBalanceObj = arrProjects[_index]['D']['memBalanceObj'];
    let theTokenId = arrProjects[_index]['D']['theTokenId'];

    if (theTokenId > 0) {
        // Now, if we have a positive balance, enable the Withdraw Balance button.
        // memWithdrawBtnId
        if (memBalanceObj['BalanaceWei'] > 0) {
            theObj = document.getElementById("memWithdrawBtnId" + _index);
            if (null != theObj) {
                theObj.disabled = false;
            }
        }
    }
}

function writeEnableMemButtons(_index) {
    //console.log('writeEnableMemButtons(): '+_index);

    let memBalanceObj = arrProjects[_index]['D']['memBalanceObj'];
    let memTokenId = arrProjects[_index]['D']['memTokenId'];

    if (memTokenId > 0) {

        // the Settle button
        if (memBalanceObj['UnsettledWei'] > 0) {
            theObj = document.getElementById("memSettleBtnId" + _index);
            if (null != theObj) {
                theObj.disabled = false;
            }
        }
        // the Grant button too
        theObj = document.getElementById("memGrantBtnId" + _index);
        if (null != theObj) {
            theObj.disabled = false;
        }
    }
}

function writeMemBalance(_index) {
    let memBalanceObj = arrProjects[_index]['D']['memBalanceObj'];

    let theWei = 0;
    let theObj = document.getElementById("memBalanceId" + _index);
    if (null != theObj) {
        theWei = BigInt((BigInt(memBalanceObj['BalanaceWei']) * BigInt(100)) / BigInt(1000000000000000000));
        //console.log("BalWei: " + (Number(theWei) / 100));
        theObj.innerHTML = (Number(theWei) / 100);
    }
    theObj = document.getElementById("memUnsettledId" + _index);
    if (null != theObj) {
        theWei = BigInt((BigInt(memBalanceObj['UnsettledWei']) * BigInt(100)) / BigInt(1000000000000000000));
        //console.log("UnsWei: " + (Number(theWei) / 100));
        theObj.innerHTML = (Number(theWei) / 100);
    }
}

// Parameters:
// { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }
// Returns:
// { "internalType": "uint256", "name": "BalanaceWei", "type": "uint256" }, 
// { "internalType": "uint256", "name": "UnsettledWei", "type": "uint256" }
async function IMemBalance(_index) {
    if (arrProjects[_index]['D']['memTokenId'] > 0) {
        arrProjects[_index]['I']['IMemV1']['Obj'].methods.memBalance(arrProjects[_index]['D']['memTokenId']).call().then(memBalanceObj => {
            arrProjects[_index]['D']['memBalanceObj'] = memBalanceObj;
            writeMemBalance(_index);
            showPage(_index);
        });
    }
}


// --------------------- Button Handlers ------------------------------------


// Handler: This routine toggles showing the information for the member's section
// - toggles the help for memRenewInfo
async function memInfoToggle(_index) {
    if (arrProjects[_index]["showMemInfo"]) {
        arrProjects[_index]["showMemInfo"] = false;
        //console.log("set false");
        let dataObj = document.getElementById("memInfo" + _index);
        if (null != dataObj) {
            dataObj.style.display = "none";
        }
    } else {
        arrProjects[_index]["showMemInfo"] = true;
        //console.log("set true");
        let dataObj = document.getElementById("memInfo" + _index);
        if (null != dataObj) {
            dataObj.style.display = "block";
        }
    }
    showPage(_index);
}

//
// In order to renew, we have to provide payment to the contract in the form
// of wei. 
// Parameters:
// { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }
// Returns:
//
// If the contract is active, all the dollars read from the input control will
// be converted to pennies and then converted to Wei (at the current value). 
// That will then be added to the contract. 
// If the contract is Inactive, the renew
//
async function memRenew(_index) {
    let nRenewPennies = 0;
    let nAdditionalPennies = 0;

    if (arrProjects[_index]['D']['memIsTimeLeftObj']['bActive']) {
        console.log("memRenew: " + _index + ', extend');
        // Extend
    } else {
        console.log("memRenew: " + _index + ', renew');
        // Renew
        nRenewPennies = parseInt(arrProjects[_index]['D']['memInfoObj']['renewPennies']);
    }

    let theObj = document.getElementById("memAdditionalId" + _index);
    if (null != theObj) {

        nAdditionalPennies = parseInt(parseInt(Number(theObj.value) * 10000) / 100);
        console.log("nAdditionalPennies: " + nAdditionalPennies);

        let nPayPennies = nRenewPennies + nAdditionalPennies;
        console.log("nPayPennies: " + nPayPennies);

        if (nPayPennies <= 0) {
            console.log("need positive number");
            theObj.value = 0;
            return;
        }

        // convert to wei
        // BigInt(priOfTfuel * Number(priceWei)
        let renewWeiBI = BigInt(BigInt(nPayPennies) * BigInt(arrProjects[_index]['D']['pennyPriceObj']['pennyTfuelWei']));
        console.log("renewWeiBI: " + renewWeiBI.toString());

        if (await IsCorrectNetwork()) {

            let TokenId = arrProjects[_index]['D']['memTokenId'];
            console.log('TokenId: ' + TokenId);
            let currentGasPrice = await web3.eth.getGasPrice();
            console.log('currentGasPrice: ' + currentGasPrice);

            document.body.style.cursor = 'wait';
            let dataObj = document.getElementById("memTrxnId" + _index);
            try {
                await arrProjects[_index]['I']['IMemV1']['Obj'].methods.memRenew(TokenId).send({
                    from: arrGlobals['visitor'],
                    value: renewWeiBI.toString(),
                    gasPrice: currentGasPrice
                }).on('error', (error) => {
                    //console.log('on handler');
                    console.log(error);
                }).then(tx => {
                    //console.log(tx);
                    var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                    //console.log(transactionRef);
                    dataObj.innerHTML = transactionRef;
                });

            } catch (error) {
                console.log(error.message);
                dataObj.innerHTML = error.message;
            }
            dataObj.style.display = "block";
            document.body.style.cursor = 'default';
        }
    }
}

// When granting hours, the user will have updated the memTokenId through the
// memEvaluate() function. Thus all we need to do is fetch the number of hours
// and call the SC.
// Parameters:
// { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }, 
// { "internalType": "uint256", "name": "_addHours", "type": "uint256" }
// Returns:
//
async function memGrantHours(_index) {

    let theObj = document.getElementById("memGrantHrsId" + _index);
    if (null != theObj) {
        let iHours = parseInt(theObj.value);
        if (iHours > 0) {

            // call the contract with these hours.
            console.log('hours: ' + iHours);

            if (await IsCorrectNetwork()) {

                let TokenId = arrProjects[_index]['D']['memTokenId'];

                let currentGasPrice = await web3.eth.getGasPrice();

                document.body.style.cursor = 'wait';
                let dataObj = document.getElementById("memTrxnId" + _index);
                try {
                    await arrProjects[_index]['I']['IMemV1']['Obj'].methods.memGrantHours(TokenId, iHours).send({
                        from: arrGlobals['visitor'],
                        gasPrice: currentGasPrice
                    }).on('error', (error) => {
                        console.log('on handler');
                        console.log(error);
                    }).then(tx => {
                        //console.log(tx);
                        var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                        console.log(transactionRef);
                        dataObj.innerHTML = transactionRef;
                    });
                } catch (error) {
                    console.log(error.message);
                    dataObj.innerHTML = error.message;
                }
                dataObj.style.display = "block";
                document.body.style.cursor = 'default';
            }
        }
    }
}
// Allow the member to withdraw any balance. The button will only be
// enabled if there is a balance. 
async function memWithdraw(_index) {
    if (await IsCorrectNetwork()) {

        let TokenId = arrProjects[_index]['D']['theTokenId'];
        console.log('Token Id: '+TokenId);
        let currentGasPrice = await web3.eth.getGasPrice();
        console.log('currentGasPrice: ' + currentGasPrice);

        document.body.style.cursor = 'wait';
        let dataObj = document.getElementById("memTrxnId" + _index);
        try {
            await arrProjects[_index]['I']['IMemV1']['Obj'].methods.memWithdraw(TokenId).send({
                from: arrGlobals['visitor'],
                gasPrice: currentGasPrice
            }).on('error', (error) => {
                console.log('on handler');
                console.log(error);
            }).then(tx => {
                //console.log(tx);
                var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                console.log(transactionRef);
                dataObj.innerHTML = transactionRef;
            });

        } catch (error) {
            console.log(error.message);
            dataObj.innerHTML = error.message;
        }
        dataObj.style.display = "block";
        document.body.style.cursor = 'default';
    }
}
// Allow the project owner to settle a membership
async function memSettleTitled(_index) {
    if (await IsCorrectNetwork()) {

        let TokenId = arrProjects[_index]['D']['memTokenId'];
        let currentGasPrice = await web3.eth.getGasPrice();

        document.body.style.cursor = 'wait';
        let dataObj = document.getElementById("memTrxnId" + _index);
        try {
            await arrProjects[_index]['I']['IMemV1']['Obj'].methods.memSettleTitled(TokenId).send({
                from: arrGlobals['visitor'],
                gasPrice: currentGasPrice
            }).on('error', (error) => {
                console.log('on handler');
                console.log(error);
            }).then(tx => {
                //console.log(tx);
                var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                console.log(transactionRef);
                dataObj.innerHTML = transactionRef;
            });

        } catch (error) {
            console.log(error.message);
            dataObj.innerHTML = error.message;
        }
        dataObj.style.display = "block";
        document.body.style.cursor = 'default';
    }
}

// read input control for memKeyTokenId in order to set memTokenId. 
// If the TokenId is greater than zero, show the page.memKeyTokenId
async function memEvaluate(_index) {
    let theObj = document.getElementById("memKeyTokenId" + _index);
    if (null != theObj) {
        if (theObj.value == null || theObj.value == '') {
            arrProjects[_index]['D']['memTokenId'] = 0;
        } else {
            arrProjects[_index]['D']['memTokenId'] = theObj.value;
        }

        if (arrProjects[_index]['D']['memTokenId'] > 0) {
            // now get the info associated with this token id
            IMemIsTimeLeft(_index);
            IMemBalance(_index);
            writeIERC721ExV1M(_index);
        }
    }
}

// Because some membership information is based on the token Id, we have to wait
// until the contract gives us that information. That's in FetchMore().
//
async function IMemV1(_index) {

    // Every IMemV1 contract is single. Let's mark it that way
    arrProjects[_index]['D']['bSingle'] = true;
    writeCollectableState(_index);

    arrProjects[_index]['I']['IMemV1']['Obj'].methods.memInfo().call().then(memInfoObj => {
        arrProjects[_index]['D']['memInfoObj'] = null;
        if (null != memInfoObj) {
            arrProjects[_index]['D']['memInfoObj'] = memInfoObj;
            writeMemInfo(_index)
            showPage(_index);
        }
    });

    arrProjects[_index]['I']['IMemV1']['Obj'].methods.memTreasuryBalance().call().then(BalanceWei => {
        arrProjects[_index]['D']['BalanceWei'] = BalanceWei;
        writeMemTreasury(_index);
        showPage(_index);
    });
}


function writeIERC721ExV1M(_index) {
    let memTokenId = arrProjects[_index]['D']['memTokenId'];

    let theObj;
    // Place this token Id in the memKeyTokenId input control
    if (memTokenId > 0) {
        theObj = document.getElementById("memKeyTokenId" + _index);
        if (null != theObj) {
            theObj.value = memTokenId;
        }
        theObj = document.getElementById("memSettleTokenId" + _index);
        if (null != theObj) {
            theObj.innerHTML = memTokenId;
        }
        theObj = document.getElementById("memGrantTokenId" + _index);
        if (null != theObj) {
            theObj.innerHTML = memTokenId;
        }
    }
}

// look for:
// arrProjects[_index]['D']['memInfoObj'] = memInfoObj;
// arrProjects[_index]['D']['BalanceWei']
async function IERC721ExV1M(_index) {
    arrProjects[_index]['I']['IERC721ExV1M']['Obj'].methods.tokenOf(arrGlobals['visitor']).call().then(memTokenId => {
        //console.log('handling: tokenOf()');
        arrProjects[_index]['D']['memTokenId'] = memTokenId;
        writeIERC721ExV1M(_index);

        // For soulbound burn functionality, we need to set the token id to what the 
        // visitor owns, thus we can use memTokenId because that can change.
        arrProjects[_index]['D']['theTokenId'] = memTokenId;

        showPage(_index);
    });

    arrProjects[_index]['I']['IERC721ExV1M']['Obj'].methods.IsSoulBound().call().then(bSoulBound => {
        arrProjects[_index]['D']['bSoulBound'] = bSoulBound;
        writeTransferState(_index);
        showPage(_index);
    });
}




