/******************************************************************************
 * Copyright © 2014-2016 The SuperNET Developers.                             *
 *                                                                            *
 * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at                  *
 * the top-level directory of this distribution for the individual copyright  *
 * holder information and the developer policies on copyright and licensing.  *
 *                                                                            *
 * Unless otherwise agreed in a custom licensing agreement, no part of the    *
 * SuperNET software, including this file may be copied, modified, propagated *
 * or distributed except according to the terms contained in the LICENSE file *
 *                                                                            *
 * Removal or modification of this copyright notice is prohibited.            *
 *                                                                            *
 ******************************************************************************/

#include "iguana777.h"

struct iguana_waccount *iguana_waccountcreate(struct iguana_info *coin,char *account)
{
    struct iguana_waccount *waddr; int32_t len = (int32_t)strlen(account)+1;
    HASH_FIND(hh,coin->wallet,account,len,waddr);
    if ( waddr != 0 )
        return(waddr);
    waddr = mycalloc('w',1,sizeof(*waddr) + len);
    strcpy(waddr->account,account);
    HASH_ADD(hh,coin->wallet,account,len,waddr);
    return(waddr);
}

struct iguana_waccount *iguana_waccountfind(struct iguana_info *coin,char *account)
{
    struct iguana_waccount *waddr;
    HASH_FIND(hh,coin->wallet,account,strlen(account)+1,waddr);
    return(waddr);
}

struct iguana_waccount *iguana_waccountadd(struct iguana_info *coin,char *walletaccount,struct iguana_waddress *waddr)
{
    struct iguana_waccount *acct;
    if ( (acct= iguana_waccountfind(coin,walletaccount)) == 0 )
        acct = iguana_waccountcreate(coin,walletaccount);
    return(acct);
}

uint8_t *iguana_walletrmds(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *numrmdsp)
{
    int32_t iter,n,m; struct iguana_waccount *acct,*tmp; uint8_t *pubkeys,*addrtypes,*rmdarray = 0; struct iguana_waddress *waddr,*tmp2;
    for (iter=n=m=0; iter<2; iter++)
    {
        HASH_ITER(hh,coin->wallet,acct,tmp)
        {
            HASH_ITER(hh,acct->waddrs,waddr,tmp2)
            {
                if ( iter == 0 )
                    n++;
                else if ( m < n )
                {
                    addrtypes[m] = waddr->type;
                    memcpy(&rmdarray[m * 20],waddr->rmd160,20);
                    memcpy(&pubkeys[m * 33],waddr->pubkey,33);
                    m++;
                }
            }
        }
        if ( iter == 0 )
        {
            rmdarray = calloc(n,20 + 1 + 33);
            addrtypes = &rmdarray[n * 20];
            pubkeys = &rmdarray[n * 21];
        }
    }
    return(rmdarray);
}

int32_t iguana_waccountswitch(struct iguana_info *coin,char *account,struct iguana_waccount *oldwaddr,int32_t oldind,char *coinaddr)
{
    // what if coinaddr is already in an account?
    //printf("change %s walletaccount.(%s) (%s) <- %s\n",coin->symbol,waddr->account,waddr->coinaddr,coinaddr);
    return(0);
}

struct iguana_waccount *iguana_waddressfind(struct iguana_info *coin,int32_t *indp,char *coinaddr)
{
    int32_t n=0; struct iguana_waccount *acct,*tmp; struct iguana_waddress *waddr,*tmp2;
    *indp = -1;
    HASH_ITER(hh,coin->wallet,acct,tmp)
    {
        HASH_ITER(hh,acct->waddrs,waddr,tmp2)
        {
            if ( strcmp(coinaddr,waddr->coinaddr) == 0 )
            {
                *indp = n;
                return(acct);
            }
            n++;
        }
    }
    return(0);
}

int32_t iguana_addressvalidate(struct iguana_info *coin,char *coinaddr)
{
    return(0);
}

char *getnewaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *account)
{
    struct iguana_waddress addr; char str[67]; cJSON *retjson = cJSON_CreateObject();
    if ( iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&addr,rand256(1)) == 0 )
    {
        jaddstr(retjson,"result",addr.coinaddr);
        init_hexbytes_noT(str,addr.pubkey,33);
        jaddstr(retjson,"pubkey",str);
        jaddstr(retjson,"privkey",bits256_str(str,addr.privkey));
        jaddstr(retjson,"wif",addr.wifstr);
        init_hexbytes_noT(str,addr.rmd160,20);
        jaddstr(retjson,"rmd160",str);
        if ( iguana_waccountadd(coin,account,&addr) < 0 )
            jaddstr(retjson,"account","error adding to account");
        else jaddstr(retjson,"account",account);
    } else jaddstr(retjson,"error","cant create address");
    return(jprint(retjson,1));
}

char *getaccountaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *account)
{
    struct iguana_waccount *wacct; struct iguana_waddress *waddr=0,addr; char str[67];cJSON *retjson;
    if ( account != 0 && account[0] != 0 )
    {
        if ( (wacct= iguana_waccountfind(coin,account)) == 0 )
        {
            if ( (waddr= iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&addr,rand256(1))) == 0 )
                return(clonestr("{\"error\":\"cant generate address\"}"));
            iguana_waccountswitch(coin,account,0,-1,addr.coinaddr);
        }
        retjson = cJSON_CreateObject();
        jaddstr(retjson,"result",waddr->coinaddr);
        init_hexbytes_noT(str,addr.pubkey,33);
        jaddstr(retjson,"pubkey",str);
        jaddstr(retjson,"privkey",bits256_str(str,waddr->privkey));
        jaddstr(retjson,"wif",waddr->wifstr);
        init_hexbytes_noT(str,waddr->rmd160,20);
        jaddstr(retjson,"rmd160",str);
        jaddstr(retjson,"account",account);
        return(jprint(retjson,1));
    }
    return(clonestr("{\"error\":\"no account specified\"}"));
}

char *setaccount(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr)
{
    struct iguana_waccount *wacct; struct iguana_waddress *waddr=0,addr; int32_t ind=-1;
    if ( coinaddr != 0 && coinaddr[0] != 0 && account != 0 && account[0] != 0 )
    {
        if ( iguana_addressvalidate(coin,coinaddr) < 0 )
            return(clonestr("{\"error\":\"invalid coin address\"}"));
        if ( (wacct= iguana_waddressfind(coin,&ind,coinaddr)) == 0 )
        {
            if ( (waddr= iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&addr,rand256(1))) == 0 )
                return(clonestr("{\"error\":\"cant generate address\"}"));
        }
        iguana_waccountswitch(coin,account,wacct,ind,coinaddr);
        return(clonestr("{\"result\":\"account set\"}"));
    }
    return(clonestr("{\"error\":\"need address and account\"}"));
}

char *getaccount(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr)
{
    struct iguana_waccount *wacct; cJSON *retjson; int32_t ind;
    if ( iguana_addressvalidate(coin,coinaddr) < 0 )
        return(clonestr("{\"error\":\"invalid coin address\"}"));
    if ( (wacct= iguana_waddressfind(coin,&ind,coinaddr)) == 0 )
        return(clonestr("{\"result\":\"no account for address\"}"));
    retjson = cJSON_CreateObject();
    jaddstr(retjson,"result",wacct->account);
    return(jprint(retjson,1));
}

char *getaddressesbyaccount(struct supernet_info *myinfo,struct iguana_info *coin,char *account)
{
    struct iguana_waccount *subset; struct iguana_waddress *waddr,*tmp; cJSON *retjson,*array;
    retjson = cJSON_CreateObject();
    array = cJSON_CreateArray();
    if ( (subset= iguana_waccountfind(coin,account)) != 0 )
    {
        HASH_ITER(hh,subset->waddrs,waddr,tmp)
        {
            jaddistr(array,waddr->coinaddr);
        }
    } else jaddstr(retjson,"result","cant find account");
    jadd(retjson,"addresses",array);
    return(jprint(retjson,1));
}

char *sendtoaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,double amount,char *comment,char *comment2)
{
    //char *coinaddr;
    //sendtoaddress	<bitcoinaddress> <amount> [comment] [comment-to]	<amount> is a real and is rounded to 8 decimal places. Returns the transaction ID <txid> if successful.	Y
    if ( coinaddr != 0 && coinaddr[0] != 0 && amount > 0. )
    {
        if ( iguana_addressvalidate(coin,coinaddr) < 0 )
            return(clonestr("{\"error\":\"invalid coin address\"}"));
        //amount = jdouble(params[1],0);
        //comment = jstr(params[2],0);
        //comment2 = jstr(params[3],0);
        printf("need to generate send %.8f to %s [%s] [%s]\n",dstr(amount),coinaddr,comment!=0?comment:"",comment2!=0?comment2:"");
    }
    return(clonestr("{\"error\":\"need address and amount\"}"));
}