/*
 * @project: TERA
 * @version: Development (beta)
 * @license: MIT (not for evil)
 * @copyright: Yuriy Ivanov 2017-2019 [progr76@gmail.com]
 * Web: https://terafoundation.org
 * Twitter: https://twitter.com/terafoundation
 * Telegram: https://web.telegram.org/#/im?p=@terafoundation
*/

var PayList = [];
var AttachItem;
var MapAccounts = {};
var LoadMapAfter = {};
var MapCheckTransaction = {};
var CanSendTransaction = 1;
var CurrentTR = {};
var MaxBlockNum = 0;
var WasAccountsDataStr;

function SetAccountsData(Data,AccountsDataStr)
{
    if(!Data || !Data.result)
        return ;
    if($("idBtRun"))
        $("idBtRun").style.display = (Data.arr.length ? '' : 'none');
    if(AccountsDataStr === WasAccountsDataStr)
        return ;
    WasAccountsDataStr = AccountsDataStr;
    var arr = Data.arr;
    var Select = $("idAccount");
    if(arr.length !== Select.options.length)
    {
        var options = Select.options;
        options.length = arr.length;
    }
    MaxBlockNum = GetCurrentBlockNumByTime();
    SetGridData(arr, "grid_accounts", "idMyTotalSum");
    for(var i = 0; arr && i < arr.length; i++)
    {
        var Item = arr[i];
        Item.MyAccount = true;
        var Num = ParseNum(Item.Num);
        if(!MapAccounts[Num])
            MapAccounts[Num] = {};
        CopyObjKeys(MapAccounts[Num], Item);
        var option = Select.options[i];
        var StrText = GetAccountText(Item, Num, 1);
        if(option.text !== StrText)
            CheckNameAccTo();
        option.value = Num;
        option.text = StrText;
    }
    var CurentValue = LoadMapAfter["idAccount"];
    if(CurentValue)
    {
        Select.value = CurentValue;
        delete LoadMapAfter["idAccount"];
    }
    SetCurCurencyName();
};

function CurTransactionToForm(bForce)
{
    var Item = $("idTransaction");
    if(Item.className === "" || bForce)
        Item.value = GetJSONFromTransaction(CurrentTR);
};

function CheckNameAccTo()
{
    MaxBlockNum = GetCurrentBlockNumByTime();
    var ToID = ParseNum($("idTo").value);
    if(!MapAccounts[ToID] || (MapAccounts[ToID].MustUpdate && MapAccounts[ToID].MustUpdate >= MaxBlockNum))
    {
        GetData("GetAccountList", {StartNum:ToID}, function (Data)
        {
            if(Data && Data.result === 1 && Data.arr.length)
            {
                var Item = Data.arr[0];
                Item.UpdateData = Date.now();
                MapAccounts[Item.Num] = Item;
                SetNameAccTo();
            }
        });
    }
    SetNameAccTo();
};

function SetNameAccTo()
{
    var Str = "";
    var ToID = ParseNum($("idTo").value);
    var element = $("idNameTo");
    var Item = MapAccounts[ToID];
    var StrTo = "To: " + GetAccountText(Item, ToID, 1);
    if(element.innerText !== StrTo)
    {
        element.innerText = StrTo;
        if(Item && Item.MyAccount)
            element.className = "smallbold";
        else
            element.className = "";
    }
};

function GetAccountText(Item,Num,bGetSum)
{
    if(Item)
    {
        var text = Item.Name;
        if(!text || text.length === 0)
            text = Num;
        else
            text = "" + Num + ". " + text;
        if(bGetSum)
        {
            var StrSum = SUM_TO_STRING(Item.Value, Item.Currency);
            text += " (" + StrSum + ")";
        }
        return text;
    }
    else
    {
        return Num;
    }
};

function OnEditIdTo()
{
    CheckNameAccTo();
    OnEditTransactionFields();
};

function OnEditTransactionFields()
{
    if(IsVisibleBlock("edit_transaction"))
        CreateTransaction();
    SetCurCurencyName();
    SaveValues();
};

function SetCurCurencyName()
{
    var Num = ParseNum($("idAccount").value);
    var Item = MapAccounts[Num];
    if(Item)
    {
        $("idCoinName").innerText = CurrencyName(Item.Currency);
    }
};

function CreateTransaction(F,CheckErr,Run)
{
    CheckNameAccTo();
    CheckSending();
    var FromID = ParseNum($("idAccount").value);
    if(CheckErr && FromID === 0)
    {
        SetError("Select valid 'From account'");
        return ;
    }
    var StrTo = $("idTo").value.trim();
    var bFindAcc = 0;
    var ToPubKey = "";
    var ToID = ParseNum(StrTo);
    if(StrTo !== "" + ToID)
    {
        if(StrTo.length === 66 && (StrTo.substr(0, 2) === "02" || StrTo.substr(0, 2) === "03") && IsHexStr(StrTo))
        {
            ToID = 0;
            ToPubKey = StrTo;
            if(ToPubKey === PubKeyStr)
                bFindAcc = 1;
        }
        else
        {
            if(CheckErr)
                SetError("Valid 'Pay to' - required!");
            return ;
        }
    }
    if(CheckErr && ToID <= 0 && ToPubKey === "" && !AttachItem)
    {
        SetError("Valid 'Pay to' - required!");
        return ;
    }
    var Description = $("idDescription").value.substr(0, 200);
    var StrSum = $("idSumSend").value;
    var indDot = StrSum.indexOf(".");
    if(indDot >= 0)
    {
        var StrTER = StrSum.substr(0, indDot);
        var StrCENT = StrSum.substr(indDot + 1);
    }
    else
    {
        var StrTER = StrSum;
        var StrCENT = "0";
    }
    StrCENT = StrCENT + "000000000";
    var Coin = {SumCOIN:ParseNum(StrTER), SumCENT:ParseNum(StrCENT.substr(0, 9))};
    var OperationID = 0;
    var Item = MapAccounts[FromID];
    if(Item)
    {
        OperationID = Item.Value.OperationID;
    }
    var AttachBody = [];
    if(AttachItem)
    {
        AttachBody = AttachItem.Data.Body;
        if(!AttachBody)
            AttachBody = [];
    }
    var ToPubKeyArr = [];
    if(ToPubKey)
        ToPubKeyArr = GetArrFromHex(ToPubKey);
    var TR = {Type:111, Version:3, Reserve:0, FromID:FromID, OperationID:OperationID, To:[{PubKey:ToPubKeyArr, ID:ToID, SumCOIN:Coin.SumCOIN,
            SumCENT:Coin.SumCENT}], Description:Description, Body:AttachBody, Sign:CurrentTR.Sign, };
    Object.defineProperties(TR, {bFindAcc:{configurable:true, writable:true, enumerable:false, value:bFindAcc}});
    Object.defineProperties(TR, {Run:{configurable:true, writable:true, enumerable:false, value:Run}});
    if(JSON.stringify(TR) === JSON.stringify(CurrentTR))
    {
        if(F)
            F(CurrentTR);
        return ;
    }
    CurrentTR = TR;
    GetSignTransaction(TR, "", function (TR)
    {
        CurTransactionToForm(true);
        if(F)
            F(TR);
    });
};

function SignJSON(F)
{
    if($("idSignJSON").disabled)
        return ;
    var TR = GetTransactionFromJSON();
    if(!TR)
        return ;
    CurrentTR = TR;
    GetSignTransaction(TR, "", function (TR)
    {
        CurTransactionToForm(true);
        if(F)
            F();
    });
};

function CheckSending(bToStatus)
{
    MaxBlockNum = GetCurrentBlockNumByTime();
    var CanSend = IsPrivateMode();
    var StrButton = "Send";
    var StrButtonSign = "Sign JSON";
    if(!CanSend)
    {
        StrButton = " ";
        StrButtonSign = " ";
    }
    if(CanSend)
    {
        var FromID = ParseNum($("idAccount").value);
        var Item = MapAccounts[FromID];
        if(Item && Item.NextSendTime && Item.NextSendTime > MaxBlockNum)
        {
            if(bToStatus)
                SetStatus("Transaction was sending. Wait... (" + Item.LastTransactionText + ")");
            CanSend = false;
            StrButton = "Wait...";
        }
    }
    $("idSendButton").disabled = (!CanSend);
    $("idSendButton").value = StrButton;
    $("idSignJSON").disabled = (!CanSend);
    $("idSignJSON").value = StrButtonSign;
    return CanSend;
};

function AddWhiteList()
{
    var ToID = ParseNum($("idTo").value);
    if(ToID && $("idWhiteOnSend").checked)
        localStorage["White:" + ToID] = 1;
};

function SendMoneyBefore()
{
    if($("idSendButton").disabled)
        return ;
    var ToID = ParseNum($("idTo").value);
    var Item = MapAccounts[ToID];
    if(localStorage["White:" + ToID] || !$("idSumSend").value || Item && Item.MyAccount)
    {
        SendMoney();
    }
    else
    {
        var StrTo = " to " + GetAccountText(Item, ToID);
        $("idWhiteOnSend").checked = 0;
        $("idOnSendText").innerText = "" + $("idSumSend").value + " " + $("idCoinName").innerText + StrTo;
        SetVisibleBlock("idBlockOnSend", 1);
        SetImg(this, 'idBlockOnSend');
    }
};

function SendMoney2()
{
    AddWhiteList();
    SendMoney();
};

function SendMoney()
{
    if(!CanSendTransaction)
    {
        SetError("Can't Send transaction");
        return ;
    }
    CheckSending(true);
    if($("idSendButton").disabled)
        return ;
    SetVisibleBlock("idBlockOnSend", 0);
    CreateTransaction(SendMoneyTR, true, ClearAttach);
};

function GetJSONFromTransaction(TR)
{
    var TR2 = JSON.parse(JSON.stringify(TR));
    for(var i = 0; i < TR2.To.length; i++)
    {
        var Item = TR2.To[i];
        Item.PubKey = GetHexFromArr(Item.PubKey);
    }
    TR2.Body = GetHexFromArr(TR2.Body);
    TR2.Sign = GetHexFromArr(TR2.Sign);
    var Str = JSON.stringify(TR2, "", 4);
    return Str;
};

function GetTransactionFromJSON()
{
    var Str = $("idTransaction").value;
    try
    {
        var TR = JSON.parse(Str);
    }
    catch(e)
    {
        SetError(e);
        return undefined;
    }
    for(var i = 0; i < TR.To.length; i++)
    {
        var Item = TR.To[i];
        Item.PubKey = GetArrFromHex(Item.PubKey);
        if(Item.SumTER && Item.SumCOIN === undefined)
        {
            Item.SumCOIN = Item.SumTER;
            delete Item.SumTER;
        }
    }
    TR.Body = GetArrFromHex(TR.Body);
    TR.Sign = GetArrFromHex(TR.Sign);
    return TR;
};

function SendMoneyJSON()
{
    if(!CanSendTransaction)
    {
        SetError("Can't Send transaction");
        return ;
    }
    var TR = GetTransactionFromJSON();
    if(!TR)
        return ;
    SendMoneyTR(TR);
};

function SignAndSendFromJSON()
{
    SignJSON(SendMoneyJSON);
};

function GetTransactionText(TR,key)
{
    var Str;
    if(TR)
    {
        if(TR.Type === TYPE_TRANSACTION_CREATE)
        {
            Str = "New account " + TR.Name.substr(0, 20);
        }
        else
            if(TR.Type === 111)
            {
                var MapItem = {};
                var ValueTotal = {SumCOIN:0, SumCENT:0};
                Str = "" + TR.FromID + "/" + TR.OperationID + " to ";
                for(var i = 0; i < TR.To.length; i++)
                {
                    var Item = TR.To[i];
                    if(Item.ID === TR.FromID || MapItem[Item.ID])
                        continue;
                    MapItem[Item.ID] = 1;
                    ADD(ValueTotal, Item);
                    if(i === 0)
                        Str += "[";
                    if(Str.length < 16)
                    {
                        if(i > 0)
                            Str += ",";
                        if(Item.ID || (Item.PubKey && Item.PubKey.length !== 66))
                            Str += Item.ID;
                        else
                            Str += GetHexFromArr(Item.PubKey).substr(0, 8);
                    }
                    else
                        if(Str.substr(Str.length - 1) !== ".")
                            Str += "...";
                }
                Str += "] " + SUM_TO_STRING(ValueTotal);
                Str += " " + (TR.Description.substr(0, 20)).replace(/\n/g, "");
            }
    }
    else
    {
        if(key)
            Str = key;
        else
            Str = "";
    }
    return Str;
};

function SendMoneyTR(TR)
{
    var Body = GetArrFromTR(TR);
    WriteArr(Body, TR.Sign, 64);
    Body.length += 12;
    SendTransaction(Body, TR, undefined, function (Err,TR,Body)
    {
        if(Err)
            return ;
        var Item = MapAccounts[TR.FromID];
        if(Item)
        {
            var key = GetHexFromArr(sha3(Body));
            var BlockNum = GetCurrentBlockNumByTime();
            Item.LastTransactionText = GetTransactionText(TR);
            Item.NextSendTime = BlockNum + 10;
            MapCheckTransaction[key] = Item;
            CheckSending();
        }
    });
};

function ClearTransaction()
{
    PayList = [];
    ClearAttach();
    CheckSendList(1);
    var arr = ["idAccount", "idTo", "idSumSend", "idDescription"];
    for(var i = 0; i < arr.length; i++)
    {
        $(arr[i]).value = "";
    }
    SaveValues();
    CreateTransaction();
};

function StartEditTransactionJSON()
{
    var Item = $("idTransaction");
    Item.className = "smallbold";
};

function EditJSONTransaction()
{
    var name = "edit_transaction";
    var Item = $("idTransaction");
    if(IsVisibleBlock(name))
    {
        SetVisibleBlock(name, false);
        Item.className = "";
    }
    else
    {
        CreateTransaction();
        SetVisibleBlock(name, true);
        Item.className = "";
    }
};
var glNumPayCount = 0;

function GetInvoiceHTML(item,onclick,classstr)
{
    if(!item.num)
    {
        glNumPayCount++;
        item.num = glNumPayCount;
    }
    var idname = "idSendInvoice" + item.num;
    var value = "";
    if(item.Data.Amount)
        value += "<B>" + item.Data.Amount + "</B> Tera";
    else
        value += "<B style='color:green'>No pay</B>";
    value += "&#x00A;" + item.num + ". " + item.Data.name;
    return "<button id='" + idname + "' onclick='" + onclick + "' class='" + classstr + "'>" + value + "</button>";
};

function AddSendList(item)
{
    PayList.push({Data:item});
};

function CheckSendList(bRedraw)
{
    TitleWarning = PayList.length;
    if(AttachItem)
        TitleWarning++;
    var Str = localStorage["InvoiceList"];
    if(!Str && !bRedraw)
        return ;
    if(!bRedraw)
    {
        SelectTab("TabSend");
    }
    if(Str)
    {
        var arr = JSON.parse(Str);
        for(var i = 0; i < arr.length; i++)
        {
            AddSendList(arr[i]);
        }
        localStorage["InvoiceList"] = "";
    }
    var idList = $("idSendList");
    if(PayList.length)
    {
        idList.innerHTML = "<DIV id='PaiListInfo'>Select the item you want to sign (pay) and send to blockchain:</DIV>";
        for(var i = 0; i < PayList.length; i++)
        {
            var item = PayList[i];
            idList.innerHTML += GetInvoiceHTML(item, "UseInvoice(" + i + ")", "btinvoice");
        }
        if(AttachItem === undefined)
            UseInvoice(0);
    }
    else
    {
        idList.innerHTML = "";
    }
};
setInterval(CheckSendList, 200);

function UseInvoice(Num)
{
    var item = PayList[Num];
    if(item.Data.From)
        $("idAccount").value = item.Data.From;
    $("idTo").value = item.Data.To;
    $("idSumSend").value = item.Data.Amount;
    $("idDescription").value = item.Data.Description;
    PayList.splice(Num, 1);
    AttachItem = item;
    $("idAttach").innerHTML = GetInvoiceHTML(AttachItem, "OpenAttach()", "btinvoice btinvoice_use");
    CheckSendList(1);
};

function ClearAttach()
{
    AttachItem = undefined;
    $("idAttach").innerHTML = "";
};

function OpenAttach()
{
    if(AttachItem)
    {
        var Data2 = JSON.parse(JSON.stringify(AttachItem.Data));
        if(Data2.Body)
            Data2.Body = GetHexFromArr(Data2.Body);
        delete Data2.TransferSecret;
        alert("DATA:\n" + JSON.stringify(Data2, "", 4));
    }
};

function SendTrCreateAcc(Currency,PubKey,Description,Adviser,Smart,bFindAcc,bAddToPay)
{
    var TR = GetTrCreateAcc(Currency, PubKey, Description, Adviser, Smart);
    var Body = GetBodyCreateAcc(TR);
    TR.bFindAcc = 1;
    if(bAddToPay)
    {
        var Item = {name:Description, To:0, Amount:CONFIG_DATA.PRICE_DAO.NewAccount, Description:"Create acc: " + Description, Body:Body,
        };
        AddToInvoiceList(Item);
    }
    else
    {
        SendTransaction(Body, TR);
    }
    $("idAccountName").value = "";
    CancelCreateAccount();
};

function ChangeSmart(NumAccount,WasSmart)
{
    if(!IsPrivateMode())
    {
        SetError("Pls, open wallet");
        return 0;
    }
    var Result = prompt("Enter smart number:", WasSmart);
    if(Result !== null && Result != WasSmart)
    {
        var Smart = parseInt(Result);
        var OperationID = 0;
        var Item = MapAccounts[NumAccount];
        if(Item)
        {
            OperationID = Item.Value.OperationID;
        }
        var TR = {Type:140, Account:NumAccount, Smart:Smart, FromNum:NumAccount, Reserve:[], OperationID:OperationID, Sign:"", };
        var Body = [];
        WriteByte(Body, TR.Type);
        WriteUint(Body, TR.Account);
        WriteUint32(Body, TR.Smart);
        WriteArr(Body, TR.Reserve, 10);
        WriteUint(Body, TR.FromNum);
        WriteUint(Body, TR.OperationID);
        SendTrArrayWithSign(Body, TR.Account, TR);
    }
};

function CheckLengthAccDesription(name,Length)
{
    var Str = $(name).value.substr(0, Length + 1);
    var arr = toUTF8Array(Str);
    var Len = Length - arr.length;
    if(Len < 0)
        SetError("Bad length");
    else
        SetStatus("Lost: " + Len + " bytes");
};
