package com.samourai.wallet.hd;

import com.samourai.wallet.SamouraiWallet;

import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Base58;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;

import org.bitcoinj.params.MainNetParams;
import org.json.JSONException;
import org.json.JSONObject;

import java.nio.ByteBuffer;

public class HD_Account {

    protected DeterministicKey aKey = null;
    private String strLabel = null;
    protected int mAID;
    private boolean isArchived = false;

    private HD_Chain mReceive = null;
    private HD_Chain mChange = null;

    protected String strXPUB = null;
    protected String strYPUB = null;

    protected NetworkParameters mParams = null;

    protected HD_Account() { ; }

    public HD_Account(NetworkParameters params, DeterministicKey mKey, String label, int child) {

        mParams = params;
        strLabel = label;
        mAID = child;

        // L0PRV & STDVx: private derivation.
        int childnum = child;
        childnum |= ChildNumber.HARDENED_BIT;
        aKey = HDKeyDerivation.deriveChildKey(mKey, childnum);

        strXPUB = aKey.serializePubB58(SamouraiWallet.getInstance().getCurrentNetworkParams());
        strYPUB = aKey.serializePubB58(SamouraiWallet.getInstance().getCurrentNetworkParams(), true);

        mReceive = new HD_Chain(mParams, aKey, true);
        mChange = new HD_Chain(mParams, aKey, false);

    }

    public HD_Account(NetworkParameters params, String xpub, String label, int child) throws AddressFormatException {

        mParams = params;
        strLabel = label;
        mAID = child;

        // assign master key to account key
        aKey = createMasterPubKeyFromXPub(xpub);

        strXPUB = strYPUB = xpub;

        mReceive = new HD_Chain(mParams, aKey, true);
        mChange = new HD_Chain(mParams, aKey, false);

    }

    protected DeterministicKey createMasterPubKeyFromXPub(String xpubstr) throws AddressFormatException {

        byte[] xpubBytes = Base58.decodeChecked(xpubstr);

        ByteBuffer bb = ByteBuffer.wrap(xpubBytes);
        int version = bb.getInt();
        if(version != 0x0488B21E && version != 0x043587CF && version != 0x049D7CB2 && version != 0x044A5262)   {
            throw new AddressFormatException("invalid xpub version");
        }

        byte[] chain = new byte[32];
        byte[] pub = new byte[33];
        // depth:
        bb.get();
        // parent fingerprint:
        bb.getInt();
        // child no.
        bb.getInt();
        bb.get(chain);
        bb.get(pub);

        return HDKeyDerivation.createMasterPubKeyFromBytes(pub, chain);
    }

    public String xpubstr() {

        return strXPUB;

    }

    public String ypubstr() {

        return strYPUB;

    }

    public String getLabel() {
        return strLabel;
    }

    public void setLabel(String label) {
        strLabel = label;
    }

    public int getId() {
        return mAID;
    }

    public HD_Chain getReceive() {
        return mReceive;
    }

    public HD_Chain getChange() {
        return mChange;
    }

    public HD_Chain getChain(int idx) {
        return (idx == 0) ? mReceive : mChange;
    }

    public JSONObject toJSON(boolean isBIP49) {
        try {
            JSONObject obj = new JSONObject();

            if(isBIP49)    {
                obj.put("ypub", ypubstr());
            }
            else    {
                obj.put("xpub", xpubstr());
            }
            obj.put("receiveIdx", getReceive().getAddrIdx());
            obj.put("changeIdx", getChange().getAddrIdx());
            obj.put("id", mAID);

            return obj;
        }
        catch(JSONException ex) {
            throw new RuntimeException(ex);
        }
    }
}

@@ -3399,24 +3399,64 @@
 NObject();%0A%0A
+            obj.put(%22xpub%22, xpubstr());%0A
             
@@ -3468,24 +3468,24 @@
 BIP49)    %7B%0A
-
             
@@ -3534,87 +3534,8 @@
   %7D%0A
-            else    %7B%0A                obj.put(%22xpub%22, xpubstr());%0A            %7D
 %0A   

include both YPUB & XPUB in backup for BIP49 accounts