package zcash

import (
	"encoding/json"
	"errors"
	"fmt"
	"zcash/zcashRpc"
)

type ZcashApi struct {
}

// zcash rpc  error struct
type zcashError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// zcash rpc  common result struct
type zcashResult struct {
	Result string     `json:"result"`
	Error  zcashError `json:"error"`
	Id     string     `json:"id"`
}

//zcash rpc  get t-address result struct
type zcashtaddrlistResult struct {
	Result []string   `json:"result"`
	Error  zcashError `json:"error"`
	Id     string     `json:"id"`
}

//zcash rpc  get t-address  Balance result struct
type zcashBalanceResult struct {
	Result float64    `json:"result"`
	Error  zcashError `json:"error"`
	Id     string     `json:"id"`
}

//zcash rpc  get transactions result struct
type zcashtransactions struct {
	Account       string  `json:"account"`
	Address       string  `json:"address"`
	Category      string  `json:"category"`
	Amount        float64 `json:"amount"`
	Vout          uint64  `json:"vout"`
	Fee           float64 `json:"fee":`
	Confirmations uint64  `json:"confirmations"`
	Blockhash     string  `json:"blockhash"`
	Blockindex    uint64  `json:"blockindex"`
	Txid          string  `json:"txid"`
	Time          uint64  `json:"time"`
	Timereceived  uint64  `json:"timereceived"`
	Comment       string  `json:"comment"`
	Otheraccount  string  `json:"otheraccount"`
	Size          uint64  `json: "size"`
}

type zcashtransactionsResult struct {
	Result []zcashtransactions `json:"result"`
	Error  zcashError          `json:"error"`
	Id     string              `json:"id"`
}

//zcash rpc  get wallet info result struct
type zcashwalletinfo struct {
	Walletversion       uint64  `json:"walletversion"`
	Balance             float64 `json:"balance"`
	Unconfirmed_balance float64 `json:"unconfirmed_balance"`
	Immature_balance    float64 `json:"immature_balance"`
	Txcount             uint64  `json:"txcount"`
	Keypoololdest       uint64  `json:"keypoololdest"`
	Keypoolsize         uint64  `json:"keypoolsize"`
	Unlocked_until      uint64  `json:"unlocked_until"`
	Paytxfee            float64 `json:"paytxfee"`
}

type ZcashwalletinfoResult struct {
	Result zcashwalletinfo `json:"result"`
	Error  zcashError      `json:"error"`
	Id     string          `json:"id"`
}

//zcash rpc  get total balance result struct
type zcashwallettotalbalance struct {
	Transparent string `json:"transparent"`
	Private     string `json:"private"`
	Total       string `json:"total"`
}

type ZcashwallettotalbalanceResult struct {
	Result zcashwallettotalbalance `json:"result"`
	Error  zcashError              `json:"error"`
	Id     string                  `json:"id"`
}

//list received by Z-address
type zcashwalletListByZaddress struct {
	Txid   string  `json:"txid"`
	Amount float64 `json:"amount"`
	Memo   string  `json:"memo"`
}

type ZcashwalletListByZaddressResult struct {
	Result []zcashwalletListByZaddress `json:"result"`
	Error  zcashError                  `json:"error"`
	Id     string                      `json:"id"`
}

// zcash block count result struct
type zcashblockcountResult struct {
	Result uint64     `json:"result"`
	Error  zcashError `json:"error"`
	Id     string     `json:"id"`
}

// zcash set tx fee result struct
type zcashsettxfeeResult struct {
	Result bool       `json:"result"`
	Error  zcashError `json:"error"`
	Id     string     `json:"id"`
}

// zcash the amount to send struct
//"address":The address is a taddr or zaddr
//"amount": The numeric amount in ZEC is the value
//"memo":(optional) If the address is a zaddr, raw data represented in hexadecimal string format

type ZcashAmountsToSend struct {
	address string
	amount  float64
	memo    string
}



// zcash get block info result struct
type zcashblock struct {
	Hash              string
	Confirmations     uint64
	Size              uint64
	Height            uint64
	Version           uint64
	Merkleroot        string
	Tx                []string
	Time              uint64
	Nonce             string
	Bits              string
	Difficulty        float64
	Previousblockhash string
	Nextblockhash     string
}

type ZcashBlockResult struct {
	Result zcashblock `json:"result"`
	Error  zcashError `json:"error"`
	Id     string     `json:"id"`
}

//zcash list  transactions since blockhash result struct
type Zcashlisttransactions struct {
	Account       string  `json:"account"`
	Address       string  `json:"address"`
	Category      string  `json:"category"`
	Amount        float64 `json:"amount"`
	Vout          uint64  `json:"vout"`
	Fee           float64 `json:"fee":`
	Confirmations uint64  `json:"confirmations"`
	Blockhash     string  `json:"blockhash"`
	Blockindex    uint64  `json:"blockindex"`
	Blocktime     uint64  `json:"blocktime"`
	Txid          string  `json:"txid"`
	Time          uint64  `json:"time"`
	Timereceived  uint64  `json:"timereceived"`
	Comment       string  `json:"comment"`
	To            string  `json:"to"`
}

type listtransactions struct {
	Transactions []Zcashlisttransactions `json: "transactions"`
	Lastblock         string                  `json: "lastblock"`
}

type ZcashlisttransactionsResult struct {
	Result listtransactions `json:"result"`
	Error  zcashError         `json:"error"`
	Id     string             `json:"id"`
}


//get a new taddr
func (m *ZcashApi) WalletNewAddr() (string, error) {

	var zcashaddr zcashResult

	result, err := zcashRpc.RunCall("getnewaddress")

	if err != nil {
		fmt.Println("Call getinfo fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &zcashaddr); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(zcashaddr.Error.Message) == 0 {
		return zcashaddr.Result, nil
	}

	err = errors.New(zcashaddr.Error.Message)
	return "", err
}

//get PrivKey by taddr
func (m *ZcashApi) WalletDumpPrivKey(taddr string) (string, error) {

	var zcashkey zcashResult

	if len(taddr) == 0 {
		fmt.Println("input address err:")
		err := errors.New("input address error:")

		return "", err
	}

	//
	result, err := zcashRpc.RunCall("dumpprivkey", taddr)

	if err != nil {
		fmt.Println("Call dumpprivkey fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &zcashkey); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(zcashkey.Error.Message) == 0 {
		return zcashkey.Result, nil
	}
	err = errors.New(zcashkey.Error.Message)
	return "", err
}

//the list of addresses for the given account
func (m *ZcashApi) WalletAddrList(Account string) ([]string, error) {

	// current only support default account“”
	if len(Account) != 0 {
		fmt.Println("input Account err:")
		err := errors.New("input Account err")
		return nil, err
	}
	var zcashtaddrlist zcashtaddrlistResult

	//
	result, err := zcashRpc.RunCall("getaddressesbyaccount", "")

	if err != nil {
		fmt.Println("Call getaddressesbyaccount fail:", err.Error())
		return nil, err
	}

	if err := json.Unmarshal([]byte(result), &zcashtaddrlist); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return nil, err
	}

	// success
	if len(zcashtaddrlist.Error.Message) == 0 {
		return zcashtaddrlist.Result, nil
	}
	err = errors.New(zcashtaddrlist.Error.Message)
	return nil, err
}

//get the current Zcash address for receiving payments to this account
func (m *ZcashApi) WalletGetAccountAddress(Account string) (string, error) {

	var zcashaddr zcashResult

	// current only support default account“”
	if len(Account) != 0 {
		fmt.Println("input Account err:")
		err := errors.New("input Account error:")
		return "", err
	}

	//
	result, err := zcashRpc.RunCall("getaccountaddress", "")

	if err != nil {
		fmt.Println("Call getaccountaddress fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &zcashaddr); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(zcashaddr.Error.Message) == 0 {
		return zcashaddr.Result, nil
	}
	err = errors.New(zcashaddr.Error.Message)
	return "", err
}

//Result:
//  	"walletversion": xxxxx,     钱包的额版本
//  	"balance": xxxxxxx,        钱包中已经确认的zcash余额
//  	"unconfirmed_balance": xxx, 钱包中未经确认的zcash余额
//  	"immature_balance": xxxxxx, 钱包中不成熟的余额
//  	"txcount": xxxxxxx,         钱包中交易的总数
//  	"keypoololdest": xxxxxx,    密钥池中最早的预生成密钥的时间戳
// 	    "keypoolsize": xxxx,        预先生成了多少个新密匙
// 	    "unlocked_until": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT)
//                                   that the wallet is unlocked for transfers, or 0 if the wallet is locked
//  	"paytxfee": x.xxxx,         交易费用的配置 set in ZEC/KB
func (m ZcashApi) WallectInfo() ([]byte, error) {

	var zcashwalletinfoResult ZcashwalletinfoResult

	//
	result, err := zcashRpc.RunCall("getwalletinfo")

	if err != nil {
		fmt.Println("Call getwalletinfo fail:", err.Error())
		return nil, err
	}

	if err := json.Unmarshal([]byte(result), &zcashwalletinfoResult); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return nil, err
	}

	// success
	if len(zcashwalletinfoResult.Error.Message) == 0 {
		var jbuf []byte
		if jbuf, err = json.Marshal(zcashwalletinfoResult.Result); err != nil {
			return nil, err
		}
		return jbuf, nil
	}

	err = errors.New(zcashwalletinfoResult.Error.Message)
	return nil, err
}

//export all taddr and zaddr of the wallet to filename
func (m ZcashApi) WalleExportWalletAddress(filename string) (string, error) {

	var zcashaddr zcashResult
	if len(filename) == 0 {
		fmt.Println("input filename err:")
		err := errors.New("input filename err")
		return "", err
	}

	//
	result, err := zcashRpc.RunCall("z_exportwallet", filename)

	if err != nil {
		fmt.Println("Call z_exportwallet fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &zcashaddr); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(zcashaddr.Error.Message) == 0 {
		return zcashaddr.Result, nil
	}
	err = errors.New(zcashaddr.Error.Message)
	return "", err
}

//get the server's total available balance
func (m ZcashApi) WalleGetBalance(account string) (float64, error) {

	var zcashBalance zcashBalanceResult

	// current only support default account“”
	if len(account) != 0 {
		fmt.Println("input account err:")
		err := errors.New("input account err")
		return 0, err
	}

	// getbalance all
	result, err := zcashRpc.RunCall("getbalance", "*")

	if err != nil {
		fmt.Println("Call getbalance fail:", err.Error())
		return 0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashBalance); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return 0, err
	}

	// success
	if len(zcashBalance.Error.Message) == 0 {
		return float64(zcashBalance.Result), nil
	}
	err = errors.New(zcashBalance.Error.Message)
	return 0, err
}

//get the server's total unconfirmed balance
func (m ZcashApi) WalleGetUnconfirmedBalance(account string) (float64, error) {

	var zcashBalance zcashBalanceResult

	// current only support default account“”
	if len(account) != 0 {
		fmt.Println("input account err:")
		err := errors.New("input account err")
		return 0, err
	}
	//
	result, err := zcashRpc.RunCall("getunconfirmedbalance")

	if err != nil {
		fmt.Println("Call getunconfirmedbalance fail:", err.Error())
		return 0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashBalance); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return 0, err
	}

	// success
	if len(zcashBalance.Error.Message) == 0 {
		return float64(zcashBalance.Result), nil
	}
	err = errors.New(zcashBalance.Error.Message)
	return 0, err
}

//Sent an amount from an account to a zcash address.
//The amount is a real and is rounded to the nearest 0.00000001.
//Result:"transactionid" (string) The transaction id.
func (m *ZcashApi) WalleSendFrom(fromaccount string, tozcashaddress string, amount float64, minconf int, comment string, commentto string) (string, error) {

	var zcashaddr zcashResult

	if len(tozcashaddress) == 0 {
		fmt.Println("input tozcashaddress err:")
		err := errors.New("input tozcashaddress err")
		return "", err
	}

	// current only support default account“”
	if len(fromaccount) != 0 {
		fmt.Println("input fromaccount err:")
		err := errors.New("input fromaccount err")
		return "", err
	}

	//
	result, err := zcashRpc.RunCall("sendfrom", "", tozcashaddress, amount, minconf, "", "")

	if err != nil {
		fmt.Println("Call sendfrom fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &zcashaddr); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(zcashaddr.Error.Message) == 0 {
		return zcashaddr.Result, nil
	}
	err = errors.New(zcashaddr.Error.Message)
	return "", err
}

//Get detailed information about in-wallet transaction <txid>
//func (m *ZcashApi) WalleGetTransaction (txid string)([]byte ,error) {
//	var zcashaddr zcashResult
//	if len(txid) == 0{
//		fmt.Println("input txid err:")
//		err := errors.New("input txid err")
//		return nil, err
//	}
//
//	//
//	result, err := zcashRpc.RunCall("gettransaction",txid)
//
//	if err != nil {
//		fmt.Println("zcashCoin.Call getinfo fail:", err.Error())
//		return nil, err
//	}
//
//	if err := json.Unmarshal([]byte(result), &zcashaddr); err != nil {
//		fmt.Println("Unmarshal err :", err.Error())
//		return nil, err
//	}
//
//	// success
//	if len(zcashaddr.Error.Message) == 0 {
//		return zcashaddr.Result,nil
//	}
//	err = errors.New(zcashaddr.Error.Message)
//	return nil,err
//
//}

//result:
//    "account":"accountname",    (string) The account name associated with the transaction.It will be "" for the default account.
//    "address":"zcashaddress",    (string) The zcash address of the transaction. Not present formove transactions (category = move).
//    "category":"send|receive|move", (string)
//    "amount": x.xxx,          (numeric) The amount in btc.
//    "vout" : n,               (numeric) the vout value
//    "fee": x.xxx,             (numeric) The amount of the fee in btc.
//    "confirmations": n,       (numeric) The number of confirmations for the transaction.
//    "blockhash": "hashvalue", (string) The block hash containing the transaction.
//    "blockindex": n,          (numeric) The block index containing the transaction.
//    "txid": "transactionid", (string) The transaction id.
//    "time": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).
//    "timereceived": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT).
//    "comment": "...",       (string) If a comment is associated with the transaction.
//    "otheraccount": "accountname",  (string) For the 'move' category of transactions,
//    "size": n,                (numeric) Transaction size in bytes
//Returns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.
func (m *ZcashApi) WalleListTransactions(account string, count uint64, from uint64) ([]byte, error) {

	var zcashtransactions zcashtransactionsResult
	if len(account) == 0 {
		fmt.Println("input account err:")
		err := errors.New("input account err")
		return nil, err
	}

	//
	result, err := zcashRpc.RunCall("listtransactions", "*", count, from)

	if err != nil {
		fmt.Println("Call listtransactions fail:", err.Error())
		return nil, err
	}

	if err := json.Unmarshal([]byte(result), &zcashtransactions); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return nil, err
	}

	// success
	if len(zcashtransactions.Error.Message) == 0 {
		var jbuf []byte

		if jbuf, err = json.Marshal(zcashtransactions.Result); err != nil {
			return nil, err
		}
		return jbuf, nil
	}
	err = errors.New(zcashtransactions.Error.Message)
	return nil, err
}

//get new z-addr
func (m ZcashApi) WallectGetNewZaddress() (string, error) {

	var zaddres zcashResult

	//
	result, err := zcashRpc.RunCall("z_getnewaddress")

	if err != nil {
		fmt.Println("Call z_getnewaddress fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &zaddres); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(zaddres.Error.Message) == 0 {
		return zaddres.Result, nil
	}

	err = errors.New(zaddres.Error.Message)
	return "", err
}

//get key of z-addr
func (m ZcashApi) WallectExportZkey(zaddr string) (string, error) {

	var zaddreskey zcashResult
	if len(zaddr) == 0 {
		fmt.Println("input zaddr err:")
		err := errors.New("input zaddr err")
		return "", err
	}
	//
	result, err := zcashRpc.RunCall("z_exportkey", zaddr)

	if err != nil {
		fmt.Println("Call z_exportkey fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &zaddreskey); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(zaddreskey.Error.Message) == 0 {
		return zaddreskey.Result, nil
	}

	err = errors.New(zaddreskey.Error.Message)
	return "", err
}

//list all z-addr in wallet
func (m ZcashApi) WallectListZaddresses() ([]string, error) {

	var zaddreslist zcashtaddrlistResult

	//
	result, err := zcashRpc.RunCall("z_listaddresses")

	if err != nil {
		fmt.Println("Call z_listaddresses fail:", err.Error())
		return nil, err
	}

	if err := json.Unmarshal([]byte(result), &zaddreslist); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return nil, err
	}

	// success
	if len(zaddreslist.Error.Message) == 0 {
		return zaddreslist.Result, nil
	}

	err = errors.New(zaddreslist.Error.Message)
	return nil, err
}

//Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.
func (m ZcashApi) WalleGetReceivedByAccount(account string, minconf uint64) (float64, error) {

	var zcashBalance zcashBalanceResult

	// current only support default account“”
	if len(account) != 0 {
		fmt.Println("input account err:")
		err := errors.New("input account err")
		return 0, err
	}

	//
	result, err := zcashRpc.RunCall("getreceivedbyaccount", "", minconf)

	if err != nil {
		fmt.Println("Call getreceivedbyaccount fail:", err.Error())
		return 0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashBalance); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return 0, err
	}

	// success
	if len(zcashBalance.Error.Message) == 0 {
		return float64(zcashBalance.Result), nil
	}
	err = errors.New(zcashBalance.Error.Message)
	return 0, err
}

//get the total amount received by the given zcashaddress in transactions with at least minconf confirmations.
func (m ZcashApi) WalleGetReceivedByAddress(addr string, minconf uint64) (float64, error) {

	var zcashBalance zcashBalanceResult

	if len(addr) == 0 {
		fmt.Println("input addres err:")
		err := errors.New("input addres err")
		return 0, err
	}

	//
	result, err := zcashRpc.RunCall("getreceivedbyaddress", addr, minconf)

	if err != nil {
		fmt.Println("Call getreceivedbyaddress fail:", err.Error())
		return 0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashBalance); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return 0, err
	}

	// success
	if len(zcashBalance.Error.Message) == 0 {
		return float64(zcashBalance.Result), nil
	}
	err = errors.New(zcashBalance.Error.Message)
	return 0, err
}

//get the balance of a taddr or zaddr belonging to the node’s wallet.
func (m ZcashApi) WalleGetbalanceByaddress(addr string, minconf uint64) (float64, error) {

	var zcashBalance zcashBalanceResult

	if len(addr) == 0 {
		fmt.Println("input addres err:")
		err := errors.New("input addres err")
		return 0, err
	}

	//
	result, err := zcashRpc.RunCall("z_getbalance", addr, minconf)

	if err != nil {
		fmt.Println("Call z_getbalance fail:", err.Error())
		return 0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashBalance); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return 0, err
	}

	// success
	if len(zcashBalance.Error.Message) == 0 {
		return float64(zcashBalance.Result), nil
	}
	err = errors.New(zcashBalance.Error.Message)
	return 0, err
}

//Result:
//  "transparent": xxxxx,     (numeric) the total balance of transparent funds
//  "private": xxxxx,         (numeric) the total balance of private funds
//  "total": xxxxx,           (numeric) the total balance of both transparent and private funds

//Return the total value of funds stored in the node’s wallet
func (m ZcashApi) WalleGetTotalBalance(minconf uint64) ([]byte, error) {

	var zcashtotalBalance ZcashwallettotalbalanceResult

	// gettotalbalance by Address
	result, err := zcashRpc.RunCall("z_gettotalbalance", minconf)

	if err != nil {
		fmt.Println("Call z_gettotalbalance fail:", err.Error())
		return nil, err
	}

	if err := json.Unmarshal([]byte(result), &zcashtotalBalance); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return nil, err
	}

	// success
	if len(zcashtotalBalance.Error.Message) == 0 {
		var jbuf []byte
		if jbuf, err = json.Marshal(zcashtotalBalance.Result); err != nil {
			return nil, err
		}
		return jbuf, nil
	}
	err = errors.New(zcashtotalBalance.Error.Message)
	return nil, err
}

//Return a list of amounts received by a zaddr belonging to the node’s wallet
func (m ZcashApi) WallezListReceivedByZaddress(address string, minconf uint64) ([]byte, error) {

	var listByZaddress ZcashwalletListByZaddressResult
	if len(address) == 0 {
		fmt.Println("input addres err:")
		err := errors.New("input addres err")
		return nil, err
	}
	// a list of amounts received by a zaddr
	result, err := zcashRpc.RunCall("z_listreceivedbyaddress", address, minconf)

	if err != nil {
		fmt.Println("Call z_listreceivedbyaddress fail:", err.Error())
		return nil, err
	}

	if err := json.Unmarshal([]byte(result), &listByZaddress); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return nil, err
	}

	// success
	if len(listByZaddress.Error.Message) == 0 {
		var jbuf []byte
		if jbuf, err = json.Marshal(listByZaddress.Result); err != nil {
			return nil, err
		}
		return jbuf, nil
	}
	err = errors.New(listByZaddress.Error.Message)
	return nil, err
}

//get the number of blocks in the longest block chain
func (m ZcashApi) WalleGetBlockCount() (uint64, error) {

	var zcashblockcount zcashblockcountResult

	//
	result, err := zcashRpc.RunCall("getblockcount")

	if err != nil {
		fmt.Println("Call getblockcount fail:", err.Error())
		return 0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashblockcount); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return 0, err
	}

	// success
	if len(zcashblockcount.Error.Message) == 0 {
		return uint64(zcashblockcount.Result), nil
	}
	err = errors.New(zcashblockcount.Error.Message)
	return 0, err
}
//Set the transaction fee per kB.
//amount:The transaction fee in BTC/kB rounded to the nearest 0.00000001

func (m ZcashApi) WalletSetTxFee(amount float64) (bool, error) {

	var zcashsettxfee  zcashsettxfeeResult
	//
	result, err := zcashRpc.RunCall("settxfee", amount)
	if err != nil {
		fmt.Println("Call settxfee fail:", err.Error())
		return false, err
	}

	if err := json.Unmarshal([]byte(result), &zcashsettxfee); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return false, err
	}

	// success
	if len(zcashsettxfee.Error.Message) == 0 {
		return zcashsettxfee.Result, nil
	}
	err = errors.New(zcashsettxfee.Error.Message)
	return false, err
}



//result:
//"operationid"  (string) An operationid to pass to z_getoperationstatus to get the result of the operation.
func (m *ZcashApi) WalletZ_Send(fromaddress string, toaddress string,amount float64 ,minconf uint64, fee float64) (string, error) {

	var operationidresult zcashResult
	//amountToSendArry := []ZcashAmountsToSend{{"zc8m5tV9gjZVQa3mBiVmSenYmrS2ft9Fb6PmSmapKkU73R38DJd4ynVh28B67KcYArcGhDUWCgvydx8mhWhWvM79Y3ANa2V", 0.0000001,""}}
	if len(fromaddress) == 0 {
		fmt.Println("input fromaddress err:")
		err := errors.New("input fromaddress err")
		return "", err
	}

	if len(toaddress) == 0 {
                fmt.Println("input toaddress err:")
                err := errors.New("input toaddress err")
                return "", err
        }
	amountparamsArr := make([]map[string]interface{}, 0)


	amountarry := make(map[string]interface{})
	amountarry["address"] = toaddress
	amountarry["amount"] = amount

	amountparamsArr = append(amountparamsArr, amountarry)

	//
	result, err := zcashRpc.RunCall("z_sendmany", fromaddress, amountparamsArr, minconf, fee)

	if err != nil {
		fmt.Println("Call z_sendmany fail:", err.Error())
		return "", err
	}

	if err := json.Unmarshal([]byte(result), &operationidresult); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", err
	}

	// success
	if len(operationidresult.Error.Message) == 0 {
		return operationidresult.Result, nil
	}
	err = errors.New(operationidresult.Error.Message)
	return "", err
}



//get block info:hash,blocktime
func (m ZcashApi) WalletGetBlockinfo(height string) (string, uint64, error) {

	var zcashBlockinfo ZcashBlockResult
	if len(height) == 0 {
		fmt.Println("input para err:")
		err := errors.New("input para err")
		return "", 0, err
	}
	//get block info by height
	result, err := zcashRpc.RunCall("getblock", height)
	if err != nil {
		fmt.Println("Call getblock fail:", err.Error())
		return "", 0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashBlockinfo); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return "", 0, err
	}

	// success
	if len(zcashBlockinfo.Error.Message) == 0 {
		return zcashBlockinfo.Result.Hash, zcashBlockinfo.Result.Time, nil
	}
	err = errors.New(zcashBlockinfo.Error.Message)
	return "", 0, err
}
//get block info:hash,blocktime
func (m ZcashApi) WalletGetBlockHeight(blockhash string) (uint64, error) {

	var zcashBlockinfo ZcashBlockResult
	if len(blockhash) == 0 {
		fmt.Println("input para err:")
		err := errors.New("input para err")
		return  0, err
	}
	//get block info by blockhash
	result, err := zcashRpc.RunCall("getblock", blockhash)
	if err != nil {
		fmt.Println("Call getblock fail:", err.Error())
		return  0, err
	}

	if err := json.Unmarshal([]byte(result), &zcashBlockinfo); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return  0, err
	}

	// success
	if len(zcashBlockinfo.Error.Message) == 0 {
		return zcashBlockinfo.Result.Height, nil
	}
	err = errors.New(zcashBlockinfo.Error.Message)
	return 0, err
}



func (m *ZcashApi) WalleListSinceBlock(blockhash string) ([]byte, error) {

	var zcashlisttransactions ZcashlisttransactionsResult
	if len(blockhash) == 0 {
		fmt.Println("input blockhash err:")
		err := errors.New("input blockhash err")
		return nil, err
	}

	//
	result, err := zcashRpc.RunCall("listsinceblock", blockhash)

	if err != nil {
		fmt.Println("Call listsinceblock fail:", err.Error())
		return nil, err
	}

	if err := json.Unmarshal([]byte(result), &zcashlisttransactions); err != nil {
		fmt.Println("Unmarshal err :", err.Error())
		return nil, err
	}

	// success
	if len(zcashlisttransactions.Error.Message) == 0 {
		var jbuf []byte

		if jbuf, err = json.Marshal(zcashlisttransactions.Result.Transactions); err != nil {
			return nil, err
		}
		return jbuf, nil
	}
	err = errors.New(zcashlisttransactions.Error.Message)
	return nil, err
}



func (m ZcashApi) InitRpcConf(rpcuser string, rpcpassword string, rpchost string, rpcport int) bool {

	zcashRpc.InitRpcConfig(rpcuser, rpcpassword, rpchost, rpcport)
	return true
}
