/******************************************************************************
 * 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.            *
 *                                                                            *
 ******************************************************************************/

#define _issue_curl(curl_handle,label,url) bitcoind_RPC(curl_handle,label,url,0,0,0)

#define INSTANTDEX_MINVOL 75
#define INSTANTDEX_MINVOLPERC ((double)INSTANTDEX_MINVOL / 100.)
#define INSTANTDEX_PRICESLIPPAGE 0.001
#define FINISH_HEIGHT 7

#define INSTANTDEX_TRIGGERDEADLINE 120
#define JUMPTRADE_SECONDS 100
#define INSTANTDEX_ACCT "4383817337783094122"
#define INSTANTDEX_FEE ((long)(2.5 * SATOSHIDEN))

#include "../iguana777.h"
#include "InstantDEX_quote.h"

#define INSTANTDEX_LOCALAPI "allorderbooks", "orderbook", "lottostats", "LSUM", "makebasket", "disable", "enable", "peggyrates", "tradesequence", "placebid", "placeask", "orderstatus", "openorders", "cancelorder", "tradehistory", "balance", "allexchanges",


typedef char *(*json_handler)(int32_t localaccess,int32_t valid,char *sender,cJSON **objs,int32_t numobjs,char *origargstr);

queue_t InstantDEXQ,TelepathyQ,Pending_offersQ;
cJSON *InstantDEX_lottostats();

//#include "NXT_tx.h"
#include "trades.h"
#include "quotes.h"
#include "subatomic.h"

#include "orderbooks.h"
#include "exchangeparse.h"
#include "exchange_trades.h"
#include "exchanges/poloniex.c"
#include "exchanges/bittrex.c"
#include "exchanges/btce.c"
#include "exchanges/bitfinex.c"
#include "exchanges/btc38.c"
#include "exchanges/huobi.c"
#include "exchanges/lakebtc.c"
#include "exchanges/quadriga.c"
#include "exchanges/okcoin.c"
#include "exchanges/coinbase.c"
#include "exchanges/bitstamp.c"

// {"plugin":"InstantDEX","method":"orderbook","baseid":"8688289798928624137","rel":"USD","exchange":"active","allfields":1}

// {"plugin":"InstantDEX","method":"orderbook","baseid":"17554243582654188572","rel":"12071612744977229797","exchange":"active","allfields":1}
// {"plugin":"InstantDEX","method":"orderbook","baseid":"6918149200730574743","rel":"XMR","exchange":"active","allfields":1}

void idle()
{
    char *jsonstr,*str; cJSON *json; int32_t n = 0; uint32_t nonce;
    /*printf("INSTANTDEX.readyflag.%d\n",INSTANTDEX.readyflag);
    while ( INSTANTDEX.readyflag == 0 )
        sleep(1);
    printf("INSTANTDEX.readyflag.%d\n",INSTANTDEX.readyflag);*/
    while ( 1 )
    {
        if ( n == 0 )
            sleep(1);
        n = 0;
        if ( (jsonstr= queue_dequeue(&InstantDEXQ,1)) != 0 )
        {
            printf("Dequeued InstantDEX.(%s)\n",jsonstr);
            if ( (json= cJSON_Parse(jsonstr)) != 0 )
            {
                //fprintf(stderr,"dequeued\n");
                if ( (str= busdata_sync(&nonce,jsonstr,"allnodes",0)) != 0 )
                {
                    //fprintf(stderr,"busdata.(%s)\n",str);
                    free(str);
                }
                free_json(json);
                n++;
            } else printf("error parsing (%s) from InstantDEXQ\n",jsonstr);
            free_queueitem(jsonstr);
        }
    }
}

uint32_t _get_NXTheight(uint32_t *firsttimep)
{
    static uint32_t last,lastheight,lastNXTtime;
    cJSON *json; uint32_t height = 0; char cmd[256],*jsonstr;
    if ( time(NULL) > last+10 )
    {
        sprintf(cmd,"requestType=getState");
        if ( (jsonstr= issue_NXTPOST(cmd)) != 0 )
        {
            //printf("(%s) -> (%s)\n",cmd,jsonstr);
            if ( (json= cJSON_Parse(jsonstr)) != 0 )
            {
                if ( firsttimep != 0 )
                    lastNXTtime = *firsttimep = (uint32_t)get_cJSON_int(json,"time");
                height = (int32_t)get_cJSON_int(json,"numberOfBlocks");
                if ( height > 0 )
                    height--;
                lastheight = height;
                free_json(json);
            }
            free(jsonstr);
        }
        last = (uint32_t)time(NULL);
    }
    else
    {
        height = lastheight;
        if ( firsttimep != 0 )
            *firsttimep = lastNXTtime;
    }
    return(height);
}

void idle2()
{
    static double lastmilli;
    uint32_t NXTblock;
    //while ( INSTANTDEX.readyflag == 0 )
    //    sleep(1);
    while ( 1 )
    {
        if ( milliseconds() < (lastmilli + 5000) )
            sleep(1);
        NXTblock = _get_NXTheight(0);
        if ( 1 && NXTblock != prices777_NXTBLOCK )
        {
            prices777_NXTBLOCK = NXTblock;
            InstantDEX_update(IGUANA_NXTADDR,IGUANA_NXTACCTSECRET);//,SUPERNET.);
            //fprintf(stderr,"done idle NXT\n");
        }
        lastmilli = milliseconds();
    }
}

cJSON *InstantDEX_lottostats()
{
    char cmdstr[1024],NXTaddr[64],buf[1024],*jsonstr; struct destbuf receiverstr;
    cJSON *json,*array,*txobj; int32_t i,n,totaltickets = 0; uint64_t amount,senderbits; uint32_t timestamp = 0;
    if ( timestamp == 0 )
        timestamp = 38785003;
    sprintf(cmdstr,"requestType=getBlockchainTransactions&account=%s&timestamp=%u&type=0&subtype=0",INSTANTDEX_ACCT,timestamp);
    //printf("cmd.(%s)\n",cmdstr);
    if ( (jsonstr= issue_NXTPOST(cmdstr)) != 0 )
    {
        // printf("jsonstr.(%s)\n",jsonstr);
        // mm string.({"requestProcessingTime":33,"transactions":[{"fullHash":"2a2aab3b84dadf092cf4cedcd58a8b5a436968e836338e361c45651bce0ef97e","confirmations":203,"signatureHash":"52a4a43d9055fe4861b3d13fbd03a42fecb8c9ad4ac06a54da7806a8acd9c5d1","transaction":"711527527619439146","amountNQT":"1100000000","transactionIndex":2,"ecBlockHeight":360943,"block":"6797727125503999830","recipientRS":"NXT-74VC-NKPE-RYCA-5LMPT","type":0,"feeNQT":"100000000","recipient":"4383817337783094122","version":1,"sender":"423766016895692955","timestamp":38929220,"ecBlockId":"10121077683890606382","height":360949,"subtype":0,"senderPublicKey":"4e5bbad625df3d536fa90b1e6a28c3f5a56e1fcbe34132391c8d3fd7f671cb19","deadline":1440,"blockTimestamp":38929430,"senderRS":"NXT-8E6V-YBWH-5VMR-26ESD","signature":"4318f36d9cf68ef0a8f58303beb0ed836b670914065a868053da5fe8b096bc0c268e682c0274e1614fc26f81be4564ca517d922deccf169eafa249a88de58036"}]})
        if ( (json= cJSON_Parse(jsonstr)) != 0 )
        {
            if ( (array= cJSON_GetObjectItem(json,"transactions")) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
            {
                for (i=0; i<n; i++)
                {
                    txobj = cJSON_GetArrayItem(array,i);
                    copy_cJSON(&receiverstr,cJSON_GetObjectItem(txobj,"recipient"));
                    if ( strcmp(receiverstr.buf,INSTANTDEX_ACCT) == 0 )
                    {
                        if ( (senderbits = get_API_nxt64bits(cJSON_GetObjectItem(txobj,"sender"))) != 0 )
                        {
                            expand_nxt64bits(NXTaddr,senderbits);
                            amount = get_API_nxt64bits(cJSON_GetObjectItem(txobj,"amountNQT"));
                            if ( amount == INSTANTDEX_FEE )
                                totaltickets++;
                            else if ( amount >= 2*INSTANTDEX_FEE )
                                totaltickets += 2;
                        }
                    }
                }
            }
            free_json(json);
        }
        free(jsonstr);
    }
    sprintf(buf,"{\"result\":\"lottostats\",\"totaltickets\":\"%d\"}",totaltickets);
    return(cJSON_Parse(buf));
}

void set_best_amounts(int64_t *baseamountp,int64_t *relamountp,double price,double volume)
{
    double checkprice,checkvol,distA,distB,metric,bestmetric = (1. / SMALLVAL);
    uint64_t baseamount,relamount,bestbaseamount = 0,bestrelamount = 0;
    int32_t i,j;
    baseamount = volume * SATOSHIDEN;
    relamount = ((price * volume) * SATOSHIDEN);
    //*baseamountp = baseamount, *relamountp = relamount;
    //return;
    for (i=-1; i<=1; i++)
        for (j=-1; j<=1; j++)
        {
            checkprice = prices777_price_volume(&checkvol,baseamount+i,relamount+j);
            distA = (checkprice - price);
            distA *= distA;
            distB = (checkvol - volume);
            distB *= distB;
            metric = sqrt(distA + distB);
            if ( metric < bestmetric )
            {
                bestmetric = metric;
                bestbaseamount = baseamount + i;
                bestrelamount = relamount + j;
                //printf("i.%d j.%d metric. %f\n",i,j,metric);
            }
        }
    *baseamountp = bestbaseamount;
    *relamountp = bestrelamount;
}

int32_t bidask_parse(int32_t localaccess,struct destbuf *exchangestr,struct destbuf *name,struct destbuf *base,struct destbuf *rel,struct destbuf *gui,struct InstantDEX_quote *iQ,cJSON *json)
{
    uint64_t basemult,relmult,baseamount,relamount; double price,volume; int32_t exchangeid,keysize,flag; char key[1024],buf[64],*methodstr;
    memset(iQ,0,sizeof(*iQ));
    iQ->s.baseid = j64bits(json,"baseid"); iQ->s.relid = j64bits(json,"relid");
    iQ->s.baseamount = j64bits(json,"baseamount"), iQ->s.relamount = j64bits(json,"relamount");
    iQ->s.vol = jdouble(json,"volume"); iQ->s.price = jdouble(json,"price");
    copy_cJSON(exchangestr,jobj(json,"exchange"));
    if ( exchangestr->buf[0] == 0 || find_exchange(&exchangeid,exchangestr->buf) == 0 )
        exchangeid = -1;
    iQ->exchangeid = exchangeid;
    copy_cJSON(base,jobj(json,"base"));
    copy_cJSON(rel,jobj(json,"rel"));
    copy_cJSON(name,jobj(json,"name"));
    methodstr = jstr(json,"method");
    if ( methodstr != 0 && (strcmp(methodstr,"placeask") == 0 || strcmp(methodstr,"ask") == 0) )
        iQ->s.isask = 1;
    if ( iQ->s.vol < 0. )
    {
        iQ->s.vol = -iQ->s.vol;
        iQ->s.isask ^= 1;
    }
    if ( methodstr != 0 && strcmp(exchangestr->buf,"wallet") == 0 && (iQ->s.baseid == NXT_ASSETID || strcmp(base->buf,"NXT") == 0) )
    {
        flag = 1;
        if ( strcmp(methodstr,"placeask") == 0 )
            methodstr = "placebid";
        else if ( strcmp(methodstr,"placebid") == 0 )
            methodstr = "placeask";
        else if ( strcmp(methodstr,"ask") == 0 )
            methodstr = "bid";
        else if ( strcmp(methodstr,"bid") == 0 )
            methodstr = "ask";
        else flag = 0;
        if ( flag != 0 )
        {
            iQ->s.baseid = iQ->s.relid, iQ->s.relid = NXT_ASSETID;
            strcpy(base->buf,rel->buf), strcpy(rel->buf,"NXT");
            baseamount = iQ->s.baseamount;
            iQ->s.baseamount = iQ->s.relamount, iQ->s.relamount = baseamount;
            name->buf[0] = 0;
            if ( iQ->s.vol > SMALLVAL && iQ->s.price > SMALLVAL )
            {
                iQ->s.vol *= iQ->s.price;
                iQ->s.price = 1. / iQ->s.price;
            }
            iQ->s.isask ^= 1;
            printf("INVERT\n");
        }
    }
    if ( (iQ->s.timestamp= juint(json,"timestamp")) == 0 )
        iQ->s.timestamp = (uint32_t)time(NULL);
    copy_cJSON(gui,jobj(json,"gui")), strncpy(iQ->gui,gui->buf,sizeof(iQ->gui)-1);
    iQ->s.automatch = juint(json,"automatch");
    iQ->s.minperc = juint(json,"minperc");
    if ( (iQ->s.duration= juint(json,"duration")) == 0 || iQ->s.duration > ORDERBOOK_EXPIRATION )
        iQ->s.duration = ORDERBOOK_EXPIRATION;
    InstantDEX_name(key,&keysize,exchangestr->buf,name->buf,base->buf,&iQ->s.baseid,rel->buf,&iQ->s.relid);
    //printf(">>>>>>>>>>>> BASE.(%s) REL.(%s)\n",base->buf,rel->buf);
    iQ->s.basebits = stringbits(base->buf);
    iQ->s.relbits = stringbits(rel->buf);
    safecopy(iQ->base,base->buf,sizeof(iQ->base));
    safecopy(iQ->rel,rel->buf,sizeof(iQ->rel));
    iQ->s.offerNXT = j64bits(json,"offerNXT");
    iQ->s.quoteid = j64bits(json,"quoteid");
    if ( strcmp(exchangestr->buf,"jumblr") == 0 || strcmp(exchangestr->buf,"pangea") == 0 )
    {
        if ( strcmp(exchangestr->buf,"pangea") == 0 )
        {
            if ( juint(json,"rakemillis") != 0 )
                iQ->s.minperc = juint(json,"rakemillis");
            if ( j64bits(json,"bigblind") != 0 )
            {
                iQ->s.baseamount = j64bits(json,"bigblind");
                iQ->s.vol = ((double)iQ->s.baseamount / SATOSHIDEN);
            }
            if ( j64bits(json,"ante") != 0 )
                iQ->s.relamount = j64bits(json,"ante");
            iQ->s.minbuyin = juint(json,"minbuyin");
            iQ->s.maxbuyin = juint(json,"maxbuyin");
            /*if ( (iQ->s.maxrake= j64bits(json,"maxrake")) != 0 )
            {
                if ( strcmp(base->buf,"BTC") == 0 && iQ->s.maxrake < SATOSHIDEN/10 )
                    iQ->s.maxrake = SATOSHIDEN/10;
                else if ( iQ->s.maxrake < 10*SATOSHIDEN )
                    iQ->s.maxrake = 10*SATOSHIDEN;
            }*/
        }
        if ( iQ->s.price == 0. )
            iQ->s.price = 1.;
        if ( iQ->s.vol == 0. )
            iQ->s.vol = 1.;
        if ( iQ->s.baseamount == 0 )
            iQ->s.baseamount = iQ->s.vol * SATOSHIDEN;
        if ( localaccess != 0 && strcmp(exchangestr->buf,"jumblr") == 0 )
        {
#ifdef later
            struct coin777 *coin; int32_t maxamount;
            if ( (coin= coin777_find(base->buf,0)) != 0 )
            {
                if ( coin->jvin == 0 && coin->jvinaddr[0] == 0 )
                {
                    coin->jvin = -1;
                    printf("initial state for jumblr.%s detected\n",coin->name);
                    sleep(5);
                }
                if ( coin->jvin < 0 )
                {
                    printf("no %s unspents available for jumblr/pangea jvin.%d %.8f\n",coin->name,coin->jvin,dstr(coin->junspent));
                    return(-1);
                }
                maxamount = coin->junspent - coin->mgw.txfee*2 - (coin->junspent>>10);
                if ( iQ->s.baseamount > maxamount )
                    iQ->s.baseamount = maxamount;
                else if ( iQ->s.baseamount < coin->mgw.txfee )
                {
                    printf("jumblr/pangea amount %.8f less than txfee %.8f\n",dstr(iQ->s.baseamount),dstr(coin->mgw.txfee));
                    return(-1);
                }
            }
            else
            {
                printf("%s not initialized for jumblr\n",base->buf);
                return(-1);
            }
#endif
        }
    }
    else
    {
        if ( iQ->s.baseamount == 0 || iQ->s.relamount == 0 )
        {
            if ( iQ->s.price <= SMALLVAL || iQ->s.vol <= SMALLVAL )
                return(-1);
            set_best_amounts(&iQ->s.baseamount,&iQ->s.relamount,iQ->s.price,iQ->s.vol);
        }
    }
    if ( iQ->s.quoteid == 0 )
        iQ->s.quoteid = calc_quoteid(iQ);
    else if ( iQ->s.quoteid != calc_quoteid(iQ) )
    {
        printf("bidask_parse quoteid.%llu != calc.%llu\n",(long long)iQ->s.quoteid,(long long)calc_quoteid(iQ));
        return(-1);
    }
    if ( iQ->s.price > SMALLVAL && iQ->s.vol > SMALLVAL && iQ->s.baseid != 0 && iQ->s.relid != 0 )
    {
        buf[0] = 0, _set_assetname(&basemult,buf,0,iQ->s.baseid);
        printf("baseid.%llu -> %s mult.%llu\n",(long long)iQ->s.baseid,buf,(long long)basemult);
        buf[0] = 0, _set_assetname(&relmult,buf,0,iQ->s.relid);
        printf("relid.%llu -> %s mult.%llu\n",(long long)iQ->s.relid,buf,(long long)relmult);
        //basemult = get_assetmult(iQ->baseid), relmult = get_assetmult(iQ->relid);
        baseamount = (iQ->s.baseamount + basemult/2) / basemult, baseamount *= basemult;
        relamount = (iQ->s.relamount + relmult/2) / relmult, relamount *= relmult;
        if ( iQ->s.price != 0. && iQ->s.vol != 0 )
        {
            price = prices777_price_volume(&volume,baseamount,relamount);
            if ( fabs(iQ->s.price - price)/price > 0.001 )
            {
                printf("cant create accurate price ref.(%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume);
                return(-1);
            }
        }
    }
    return(0);
}

char *InstantDEX(char *jsonstr,char *remoteaddr,int32_t localaccess)
{
    char *prices777_allorderbooks();
    char *InstantDEX_tradehistory(cJSON *json,int32_t firsti,int32_t endi);
    char *InstantDEX_cancelorder(cJSON *json,char *activenxt,char *secret,uint64_t sequenceid,uint64_t quoteid);
    struct destbuf exchangestr,method,gui,name,base,rel; double balance;
    char *retstr = 0,key[512],retbuf[1024],*activenxt,*secret,*coinstr; struct InstantDEX_quote iQ; struct exchange_info *exchange;
    cJSON *json; uint64_t assetbits,sequenceid; uint32_t maxdepth; int32_t invert=0,keysize,allfields; struct prices777 *prices = 0;
    //printf("INSTANTDEX.(%s)\n",jsonstr);
    //if ( INSTANTDEX.readyflag == 0 )
    //    return(0);
    if ( jsonstr != 0 && (json= cJSON_Parse(jsonstr)) != 0 )
    {
        // test: asset/asset, asset/external, external/external, autofill and automatch
        // peggy integration
        if ( bidask_parse(localaccess,&exchangestr,&name,&base,&rel,&gui,&iQ,json) < 0 && (strcmp(exchangestr.buf,"jumblr") == 0 || strcmp(exchangestr.buf,"pangea") == 0) )
        {
            //return(clonestr("{\"error\":\"invalid parameters\"}"));
        }
        if ( iQ.s.offerNXT == 0 )
            iQ.s.offerNXT = IGUANA_MY64BITS;
printf("isask.%d base.(%s) rel.(%s)\n",iQ.s.isask,base.buf,rel.buf);
        copy_cJSON(&method,jobj(json,"method"));
        if ( (sequenceid= j64bits(json,"orderid")) == 0 )
            sequenceid = j64bits(json,"sequenceid");
        allfields = juint(json,"allfields");
        if ( (maxdepth= juint(json,"maxdepth")) <= 0 )
            maxdepth = MAX_DEPTH;
        if ( exchangestr.buf[0] == 0 )
        {
            if ( iQ.s.baseid != 0 && iQ.s.relid != 0 )
                strcpy(exchangestr.buf,"nxtae");
            else strcpy(exchangestr.buf,"basket");
        }
        assetbits = InstantDEX_name(key,&keysize,exchangestr.buf,name.buf,base.buf,&iQ.s.baseid,rel.buf,&iQ.s.relid);
        //printf("2nd isask.%d base.(%s) rel.(%s)\n",iQ.s.isask,base.buf,rel.buf);
        exchange = exchange_find(exchangestr.buf);
        secret = jstr(json,"secret"), activenxt = jstr(json,"activenxt");
        if ( secret == 0 )
        {
            secret = IGUANA_NXTACCTSECRET;
            activenxt = IGUANA_NXTADDR;
        }
        if ( strcmp(method.buf,"exit") == 0 )
        {
            printf("getchar and then exit\n");
            getchar();
            exit(0);
        }
        if ( strcmp(method.buf,"orderstatus") == 0 )
            retstr = InstantDEX_orderstatus(json,sequenceid,iQ.s.quoteid);
        else if ( strcmp(method.buf,"cancelorder") == 0 )
            retstr = InstantDEX_cancelorder(json,jstr(json,"activenxt"),jstr(json,"secret"),sequenceid,iQ.s.quoteid);
        else if ( strcmp(method.buf,"openorders") == 0 )
            retstr = InstantDEX_openorders(json,IGUANA_NXTADDR,juint(json,"allorders"));
        else if ( strcmp(method.buf,"tradehistory") == 0 )
            retstr = InstantDEX_tradehistory(json,juint(json,"firsti"),juint(json,"endi"));
        else if ( strcmp(method.buf,"withdraw") == 0 )
            retstr = InstantDEX_withdraw(json);
        else if ( strcmp(method.buf,"balance") == 0 )
        {
            if ( exchange != 0 && exchange->issue.trade != 0 )
            {
                if ( exchange->issue.balances != 0 )
                {
                    if ( exchange->balancejson != 0 )
                        free_json(exchange->balancejson), exchange->balancejson = 0;
                    exchange->lastbalancetime = (uint32_t)time(NULL);
                    if ( (exchange->balancejson= (*exchange->issue.balances)(&exchange->cHandle,exchange)) != 0 )
                    {
                        if ( (coinstr= jstr(json,"base")) != 0 )
                            retstr = (*exchange->issue.parsebalance)(exchange,&balance,coinstr);
                        else retstr = jprint(exchange->balancejson,0);
                    } else retstr = clonestr("{\"error\":\"balances null return\"}");
                } else retstr = clonestr("{\"error\":\"no balances function\"}");
            } else retstr = clonestr("{\"error\":\"cant find exchange trade or balances function\"}");
            printf("%s ptr.%p trade.%p\n",exchangestr.buf,exchange,exchange!=0?exchange->issue.trade:0);
        }
        else if ( strcmp(method.buf,"allorderbooks") == 0 )
            retstr = prices777_allorderbooks();
        else if ( strcmp(method.buf,"allexchanges") == 0 )
            retstr = jprint(exchanges_json(),1);
        else if ( strcmp(method.buf,"lottostats") == 0 )
            retstr = jprint(InstantDEX_lottostats(),1);
       /* else if ( strcmp(method.buf,"tradesequence") == 0 )
        {
            //printf("call tradesequence.(%s)\n",jsonstr);
            int32_t dotrade,numtrades; struct prices777_order trades[256]; struct pending_trade *pend;
            dotrade = juint(json,"dotrade");
            retstr = InstantDEX_tradesequence(0,0,0,&numtrades,trades,(int32_t)(sizeof(trades)/sizeof(*trades)),dotrade,activenxt,secret,json);
            if ( dotrade != 0 )
            {
                pend = calloc(1,sizeof(*pend));
                pend->dir = iQ.s.isask == 0 ? 1 : -1, pend->price = iQ.s.price, pend->volume = iQ.s.vol, pend->orderid = iQ.s.quoteid;
                pend->tradesjson = json;
                pend->type = 'S';
                pend->timestamp = (uint32_t)time(NULL);
                //InstantDEX_history(0,pend,0);
                queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0);
            }
        }*/
        else if ( strcmp(method.buf,"makebasket") == 0 )
        {
            if ( (prices= prices777_makebasket(0,json,1,"basket",0,0)) != 0 )
                retstr = clonestr("{\"result\":\"basket made\"}");
            else retstr = clonestr("{\"error\":\"couldnt make basket\"}");
        }
        else if ( strcmp(method.buf,"peggyrates") == 0 )
        {
            //if ( SUPERNET.peggy != 0 )
            //    retstr = peggyrates(juint(json,"timestamp"),jstr(json,"name"));
            //else retstr = clonestr("{\"error\":\"peggy disabled\"}");
        }
        else if ( strcmp(method.buf,"LSUM") == 0 )
        {
            sprintf(retbuf,"{\"result\":\"%s\",\"amount\":%d}",(rand() & 1) ? "BUY" : "SELL",(rand() % 100) * 100000);
            retstr = clonestr(retbuf);
        }
        else if ( strcmp(method.buf,"placebid") == 0 || strcmp(method.buf,"placeask") == 0 )
            return(InstantDEX_placebidask(0,sequenceid,exchangestr.buf,name.buf,base.buf,rel.buf,&iQ,jstr(json,"extra"),secret,activenxt,json));
        else if ( strcmp(exchangestr.buf,"active") == 0 && strcmp(method.buf,"orderbook") == 0 )
            retstr = prices777_activebooks(name.buf,base.buf,rel.buf,iQ.s.baseid,iQ.s.relid,maxdepth,allfields,strcmp(exchangestr.buf,"active") == 0 || juint(json,"tradeable"));
        else if ( (prices= prices777_find(&invert,iQ.s.baseid,iQ.s.relid,exchangestr.buf)) == 0 )
        {
            if ( (prices= prices777_poll(exchangestr.buf,name.buf,base.buf,iQ.s.baseid,rel.buf,iQ.s.relid)) != 0 )
            {
                if ( prices777_equiv(prices->baseid) == prices777_equiv(iQ.s.baseid) && prices777_equiv(prices->relid) == prices777_equiv(iQ.s.relid) )
                    invert = 0;
                else if ( prices777_equiv(prices->baseid) == prices777_equiv(iQ.s.relid) && prices777_equiv(prices->relid) == prices777_equiv(iQ.s.baseid) )
                    invert = 1;
                else invert = 0, printf("baserel not matching (%s %s) %llu %llu vs (%s %s) %llu %llu\n",prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,base.buf,rel.buf,(long long)iQ.s.baseid,(long long)iQ.s.relid);
            }
        }
        if ( retstr == 0 && prices != 0 )
        {
            if ( strcmp(method.buf,"disablequotes") == 0 )
            {
                if ( prices != 0 )
                {
                    if ( strcmp(prices->exchange,"unconf") == 0 )
                        return(clonestr("{\"error\":\"cannot disable unconf\"}"));
                    prices->disabled = 1;
                    return(clonestr("{\"result\":\"success\"}"));
                }
                else return(clonestr("{\"error\":\"no prices to disable\"}"));
            }
            else if ( strcmp(method.buf,"enablequotes") == 0 )
            {
                if ( prices != 0 )
                {
                    prices->disabled = 0;
                    return(clonestr("{\"result\":\"success\"}"));
                }
                else return(clonestr("{\"error\":\"no prices to enable\"}"));
            }
            else if ( strcmp(method.buf,"orderbook") == 0 )
            {
                if ( maxdepth < MAX_DEPTH )
                    return(prices777_orderbook_jsonstr(invert,IGUANA_MY64BITS,prices,&prices->O,maxdepth,allfields));
                else if ( (retstr= prices->orderbook_jsonstrs[invert][allfields]) == 0 )
                {
                    retstr = prices777_orderbook_jsonstr(invert,IGUANA_MY64BITS,prices,&prices->O,MAX_DEPTH,allfields);
                    portable_mutex_lock(&prices->mutex);
                    if ( prices->orderbook_jsonstrs[invert][allfields] != 0 )
                        free(prices->orderbook_jsonstrs[invert][allfields]);
                    prices->orderbook_jsonstrs[invert][allfields] = retstr;
                    portable_mutex_unlock(&prices->mutex);
                    if ( retstr == 0 )
                        retstr = clonestr("{}");
                }
                if ( retstr != 0 )
                    retstr = clonestr(retstr);
            }
            //else if ( strcmp(method.buf,"tradebot") == 0 )
            //    retstr = InstantDEX_tradebot(prices,json,&iQ,invert);
        }
        //if ( Debuglevel > 2 )
            printf("(%s) %p exchange.(%s) base.(%s) %llu rel.(%s) %llu | name.(%s) %llu\n",retstr!=0?retstr:"",prices,exchangestr.buf,base.buf,(long long)iQ.s.baseid,rel.buf,(long long)iQ.s.relid,name.buf,(long long)assetbits);
    }
    return(retstr);
}

char *bidask_func(int32_t localaccess,int32_t valid,char *sender,cJSON *json,char *origargstr)
{
    struct destbuf gui,exchangestr,name,base,rel,offerNXT; struct InstantDEX_quote iQ;
    copy_cJSON(&offerNXT,jobj(json,"offerNXT"));
//printf("got (%s)\n",origargstr);
    if ( strcmp(IGUANA_NXTADDR,offerNXT.buf) != 0 )
    {
        if ( bidask_parse(localaccess,&exchangestr,&name,&base,&rel,&gui,&iQ,json) == 0 )
            return(InstantDEX_placebidask(sender,j64bits(json,"orderid"),exchangestr.buf,name.buf,base.buf,rel.buf,&iQ,jstr(json,"extra"),jstr(json,"secret"),jstr(json,"activenxt"),json));
        else printf("error with incoming bidask\n");
    } else fprintf(stderr,"got my bidask from network (%s)\n",origargstr);
    return(clonestr("{\"result\":\"got loopback bidask\"}"));
}