text:
// Copyright (c) 2009-2012 The Darkcoin developers
// Copyright (c) 2015-2020 The Neutron Developers
//
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "masternode.h"
#include "activemasternode.h"
#include "darksend.h"
#include "main.h"
#include "script/standard.h"
#include "util.h"
#include "addrman.h"

#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <sstream>

CCriticalSection cs_masternodes;

CMasternodeMan mnodeman;
std::vector<CMasternode> vecMasternodes;
CMasternodePayments masternodePayments;
map<uint256, CMasternodePaymentWinner> mapSeenMasternodeVotes;
map<uint256, int> mapSeenMasternodeScanningErrors;
std::map<CNetAddr, int64_t> mAskedUsForMasternodeList;
std::map<COutPoint, int64_t> mWeAskedForMasternodeListEntry;
std::map<int64_t, uint256> mapCacheBlockHashes;

// manage the masternode connections
void ProcessMasternodeConnections()
{
    LOCK(cs_vNodes);

    BOOST_FOREACH(CNode* pnode, vNodes)
    {
        //if it's our masternode, let it be
        if (darkSendPool.submittedToMasternode == pnode->addr)
            continue;

        if (pnode->fDarkSendMaster)
        {
            LogPrintf("%s : closing masternode connection %s\n", __func__, pnode->addr.ToString().c_str());
            pnode->CloseSocketDisconnect();
        }
    }
}

void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
    if (IsInitialBlockDownload())
        return;

    if (strCommand == NetMsgType::DSEE)
    {
        CTxIn vin;
        CService addr;
        CPubKey pubkey;
        CPubKey pubkey2;
        vector<unsigned char> vchSig;
        int64_t sigTime;
        int count;
        int current;
        int64_t lastUpdated;
        int protocolVersion;
        std::string strMessage;

        // 70047 and greater
        vRecv >> vin >> addr >> vchSig >> sigTime >> pubkey >> pubkey2 >> count >> current >>
                 lastUpdated >> protocolVersion;

        if (fDebug)
        {
            LogPrintf("%s : dsee - received: node: %s, vin: %s, addr: %s, sigTime: %lld, pubkey: %s, pubkey2: %s, "
                      "count: %d, current: %d, lastUpdated: %lld, protocol: %d\n", __func__,
                      pfrom->addr.ToString().c_str(),  vin.ToString().c_str(), addr.ToString(), sigTime,
                      pubkey.GetHash().ToString(), pubkey2.GetHash().ToString(), count, current, lastUpdated,
                      protocolVersion);
        }

        // make sure signature isn't in the future (past is OK)
        if (sigTime > GetAdjustedTime() + 60 * 60)
        {
            std::stringstream msg;
            msg << boost::format("%s : dsee - signature rejected, too far into the future %s") %
                __func__ % vin.prevout.hash.ToString();

            LogPrintf("%s\n", msg.str().c_str());
            pfrom->Misbehaving(msg.str(), 1);
            return;
        }

        bool isLocal = addr.IsRFC1918() || addr.IsLocal();
        // if(Params().MineBlocksOnDemand()) isLocal = false;

        std::string vchPubKey(pubkey.vchPubKey.begin(), pubkey.vchPubKey.end());
        std::string vchPubKey2(pubkey2.vchPubKey.begin(), pubkey2.vchPubKey.end());

        strMessage = addr.ToString() + boost::lexical_cast<std::string>(sigTime) + vchPubKey + vchPubKey2 +
                     boost::lexical_cast<std::string>(protocolVersion);

        if (protocolVersion < ActiveProtocol())
        {
            std::stringstream msg;
            msg << boost::format("%s : dsee - ignoring masternode %s using outdated protocol version %d") %
                __func__ % vin.ToString().c_str() % protocolVersion;

            LogPrintf("%s\n", msg.str().c_str());
            pfrom->Misbehaving(msg.str(), 15);
            return;
        }

        CScript pubkeyScript;
        pubkeyScript = GetScriptForDestination(pubkey.GetID());

        if (pubkeyScript.size() != 25)
        {
            std::stringstream msg;
            msg << boost::format("%s : dsee - pubkey wrong size") % __func__;

            LogPrintf("%s\n", msg.str().c_str());
            pfrom->Misbehaving(msg.str(), 100);
            return;
        }

        CScript pubkeyScript2;
        pubkeyScript2 =GetScriptForDestination(pubkey2.GetID());

        if (pubkeyScript2.size() != 25)
        {
            std::stringstream msg;
            msg << boost::format("%s : dsee - pubkey2 the wrong size") % __func__;

            LogPrintf("%s\n", msg.str().c_str());
            pfrom->Misbehaving(msg.str(), 100);
            return;
        }

        std::string errorMessage = "";

        if (!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage))
        {
            std::stringstream msg;
            msg << boost::format("%s : dsee - got bad masternode address signature") % __func__;

            LogPrintf("%s\n", msg.str().c_str());
            pfrom->Misbehaving(msg.str(), 100);
            return;
        }

        // search existing masternode list, this is where we update existing masternodes with new dsee broadcasts
        CMasternode* pmn = mnodeman.Find(vin);
        if (pmn != NULL)
        {
            if (fDebug)
            {
                LogPrintf("%s : dsee - found existing masternode %s - %s - %s\n", __func__,
                          pmn->addr.ToString().c_str(), vin.ToString().c_str(),
                          pmn->UpdatedWithin(MASTERNODE_MIN_DSEE_SECONDS));
            }

            // count == -1 when it's a new entry
            //   e.g. We don't want the entry relayed/time updated when we're syncing the list
            // mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below,
            //   after that they just need to match

            if (count == -1 && pmn->pubkey == pubkey && !pmn->UpdatedWithin(MASTERNODE_MIN_DSEE_SECONDS))
            {
                LogPrintf("%s : dsee - update masternode last seen for %s\n", __func__, addr.ToString().c_str());
                pmn->UpdateLastSeen();

                if (pmn->now < sigTime)
                {
                    LogPrintf("%s : dsee - Got updated entry for %s\n", __func__, addr.ToString().c_str());

                    pmn->pubkey2 = pubkey2;
                    pmn->now = sigTime;
                    pmn->sig = vchSig;
                    pmn->protocolVersion = protocolVersion;
                    pmn->addr = addr;

                    RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion);
                }
            }

            return;
        }

        // make sure the vout that was signed is related to the transaction that spawned the masternode
        //  - this is expensive, so it's only done once per masternode
        if (!darkSendSigner.IsVinAssociatedWithPubkey(vin, pubkey))
        {
            std::stringstream msg;
            msg << boost::format("%s : dsee - got mismatched pubkey and vin") % __func__;

            LogPrintf("%s\n", msg.str().c_str());
            pfrom->Misbehaving(msg.str(), 100);
            return;
        }

        if (fDebug)
            LogPrintf("%s : dsee - got new masternode entry %s\n", __func__, addr.ToString().c_str());

        // make sure it's still unspent
        //  - this is checked later by .check() in many places and by ThreadCheckDarkSend()

        CTransaction tx = CTransaction();
        CTxOut vout = CTxOut(24999*COIN, darkSendPool.collateralPubKey);
        tx.vin.push_back(vin);
        tx.vout.push_back(vout);
        bool pfMissingInputs = false;

        if (AcceptableInputs(mempool, tx, false, &pfMissingInputs))
        {
            if (fDebug)
                LogPrintf("%s : dsee - accepted masternode entry %i %i\n", __func__, count, current);

            if (GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS)
            {
                std::stringstream msg;
                msg << boost::format("%s : dsee - input must have at least %d confirmations") %
                    __func__ % MASTERNODE_MIN_CONFIRMATIONS;

                LogPrintf("%s\n", msg.str().c_str());
                pfrom->Misbehaving(msg.str(), 20);
                return;
            }

            // use this as a peer
            addrman.Add(CAddress(addr), pfrom->addr, 2 * 60 * 60);

            // add our masternode
            CMasternode mn(addr, vin, pubkey, vchSig, sigTime, pubkey2, protocolVersion);
            mn.UpdateLastSeen(lastUpdated);
            vecMasternodes.push_back(mn);

            if (count == -1 && !isLocal)
            {
                RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count,
                                           current, lastUpdated, protocolVersion);
            }

        }
        else
        {
            LogPrintf("%s : dsee - rejected masternode entry %s\n", __func__, addr.ToString().c_str());

            /*int nDoS = 0;
            if (state.IsInvalid(nDoS))
            {
                LogPrintf("dsee - %s from %s %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(),
                    pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str());
                if (nDoS > 0)
                    pfrom->Misbehaving(nDoS);
            }*/
        }
    }
    else if (strCommand == NetMsgType::DSEEP)
    {
        CTxIn vin;
        vector<unsigned char> vchSig;
        int64_t sigTime;
        bool stop;

        vRecv >> vin >> vchSig >> sigTime >> stop;

        if (fDebug)
        {
            LogPrintf("%s : dseep - received: node: %s, vin: %s, sigTime: %lld, stop: %s\n", __func__,
                      pfrom->addr.ToString().c_str(), vin.ToString().c_str(), sigTime, stop ? "true" : "false");
        }

        if (sigTime > GetAdjustedTime() + 60 * 60)
        {
            LogPrintf("%s : dseep - signature rejected, too far into the future %s\n", __func__,
                      vin.ToString().c_str());

            // pfrom->Misbehaving(1);
            return;
        }
        else if (sigTime <= GetAdjustedTime() - 60 * 60)
        {
            LogPrintf("%s : dseep - signature rejected, too far into the past %s - %s - %ld less than %ld\n",
                      __func__, pfrom->addr.ToString().c_str(), vin.ToString().c_str(), sigTime,
                      GetAdjustedTime() - 60 * 60);

            // pfrom->Misbehaving(1);
            return;
        }

        // see if we have this masternode
        CMasternode* pmn = mnodeman.Find(vin);

        if (pmn != NULL)
        {
            if (fDebug)
            {
                LogPrintf("%s : dseep - found corresponding mn for vin=%s addr=%s\n", __func__,
                          vin.ToString().c_str(), pmn->addr.ToString());
            }

            // take this only if it's newer
            if (sigTime - pmn->lastDseep > MASTERNODE_MIN_DSEEP_SECONDS)
            {
                std::string strMessage = pmn->addr.ToString() + boost::lexical_cast<std::string>(sigTime) +
                                         boost::lexical_cast<std::string>(stop);

                if (fDebug)
                {
                    LogPrintf("%s : dseep - got newer sigTime, sigTime=%d lastDseep=%d\n",
                              __func__, sigTime, pmn->lastDseep);
                }

                std::string errorMessage = "";

                if (!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage))
                {
                    std::stringstream msg;
                    msg << boost::format("%s : dseep - got bad masternode address signature %s") %
                        __func__ % vin.ToString().c_str();

                    LogPrintf("%s\n", msg.str().c_str());
                    pfrom->Misbehaving(msg.str(), 100);
                    return;
                }

                pmn->lastDseep = sigTime;
                pmn->Check();

                if (pmn->IsEnabled())
                {
                    if (fDebug)
                        LogPrintf("%s : dseep - masternode is enabled addr=%s\n", __func__, pmn->addr.ToString());

                    if (stop)
                        pmn->Disable();
                    else
                    {
                        if (fDebug)
                            LogPrintf("%s : dseep - updatingLastSeen addr=%s\n", __func__, pmn->addr.ToString());

                        pmn->UpdateLastSeen();
                    }

                    TRY_LOCK(cs_vNodes, lockNodes);

                    if (!lockNodes)
                        return;

                    if  (fDebug)
                    {
                        LogPrintf("%s : dseep - relaying %s - %s\n", __func__, pmn->addr.ToString(),
                                  vin.prevout.hash.ToString());
                    }

                    RelayDarkSendElectionEntryPing(vin, vchSig, sigTime, stop);
                }
            }

            return;
        }

        if (fDebug)
            LogPrintf("%s : dseep - couldn't find masternode entry %s\n", __func__, vin.ToString().c_str());

        mnodeman.AskForMN(pfrom, vin);

    }
    else if (strCommand == NetMsgType::DSEG) // Get masternode list or specific entry
    {
        CTxIn vin;
        vRecv >> vin;

        if (fDebug)
        {
            LogPrintf("%s : dseg - masternode list, vin=%s, prevout=%s\n", __func__, vin.ToString().c_str(),
                      vin.prevout.hash.ToString());
        }

        if (vin == CTxIn()) // Should only ask for this once
        {
            std::map<CNetAddr, int64_t>::iterator i = mAskedUsForMasternodeList.find(pfrom->addr);

            if (i != mAskedUsForMasternodeList.end())
            {
                // int64_t t = (*i).second;
                // if (GetTime() < t)
                // {
                //   LogPrintf("dseg - peer already asked me for the list, peer=%d (%s)\n", pfrom->id, pfrom->addr.ToString().c_str());
                //   pfrom->Misbehaving(34);
                //   return;
                // }
            }

            int64_t askAgain = GetTime() + MASTERNODE_DSEG_SECONDS;
            mAskedUsForMasternodeList[pfrom->addr] = askAgain;
        } // else, asking for a specific node which is ok

        LOCK(cs_masternodes);
        int count = vecMasternodes.size();
        int i = 0;

        BOOST_FOREACH(CMasternode mn, vecMasternodes)
        {
            if (mn.addr.IsRFC1918())
                continue; // local network

            if (vin == CTxIn())
            {
                mn.Check();

                if (mn.IsEnabled())
                {
                    if (fDebug)
                    {
                        LogPrintf("%s : dseg - sending masternode entry - %s\n", __func__,
                                  mn.addr.ToString().c_str());
                    }

                    pfrom->PushMessage(NetMsgType::DSEE, mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2,
                                       count, i, mn.lastTimeSeen, mn.protocolVersion);
                }
            }
            else if (vin == mn.vin)
            {
                if (fDebug)
                {
                    LogPrintf("%s : dseg - sending masternode entry - %s\n", __func__,
                              mn.addr.ToString().c_str());
                }

                pfrom->PushMessage(NetMsgType::DSEE, mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2,
                                   count, i, mn.lastTimeSeen, mn.protocolVersion);

                LogPrintf("%s : dseg - sent single masternode entry to peer %s (%s)\n",
                          __func__, pfrom->GetId(), pfrom->addr.ToString().c_str());
                return;
            }

            i++;
        }

        LogPrintf("%s : dseg - sent %d masternode entries to %s\n", __func__, count,
                  pfrom->addr.ToString().c_str());
    }
    else if (strCommand == NetMsgType::MASTERNODEPAYMENTSYNC) // Masternode Payments Request Sync
    {
        if (pfrom->HasFulfilledRequest(NetMsgType::MASTERNODEPAYMENTSYNC))
        {
            if (fDebug)
            {
                LogPrintf("%s : mnget - peer already asked me for the list, peer=%d (%s)\n",
                          __func__, pfrom->id, pfrom->addr.ToString().c_str());
            }

            return;
        }

        // Ignore such requests until we are fully synced.
        // We could start processing this after masternode list is synced
        // but this is a heavy one so it's better to finish sync first.
        if (!isMasternodeListSynced)
            return;

        pfrom->FulfilledRequest(NetMsgType::MASTERNODEPAYMENTSYNC);
        masternodePayments.Sync(pfrom);

        LogPrintf("%s : mnget - sent masternode winners to peer %s (%s)\n", __func__,
                  pfrom->id, pfrom->addr.ToString().c_str());
    }
    else if (strCommand == NetMsgType::MASTERNODEPAYMENTVOTE) // Masternode payments declare winner
    {
        CMasternodePaymentWinner winner;
        int a = 0;
        vRecv >> winner >> a;

        if (pfrom->nVersion < ActiveProtocol())
        {
            LogPrintf("%s : mnw -- peer=%d (%s) using obsolete version %i\n", __func__,
                      pfrom->id, pfrom->addr.ToString().c_str(), pfrom->nVersion);

            pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
                               strprintf("version must be %d or greater", ActiveProtocol()));
            return;
        }

        if (pindexBest == NULL)
            return;

        CTxDestination address1;
        ExtractDestination(winner.payee, address1);
        CBitcoinAddress address2(address1);

        uint256 nHash = winner.GetHash();

        if (mapSeenMasternodeVotes.count(nHash))
        {
            if (fDebug)
            {
                LogPrintf("%s : mnw - seen vote %s address=%s nBlockHeight=%d nHeight=%d\n", __func__,
                          nHash.ToString(), address2.ToString(), winner.nBlockHeight, pindexBest->nHeight);
            }

            return;
        }

        int nFirstBlock = pindexBest->nHeight - (mnodeman.CountEnabled() * 1.25);

        if (winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > pindexBest->nHeight + 20)
        {
            if (fDebug)
            {
                LogPrintf("%s : mnw - winner out of range - nFirstBlock=%d, nBlockHeight=%d, nHeight=%d\n",
                          __func__, nFirstBlock, winner.nBlockHeight, pindexBest->nHeight);
            }

            return;
        }

        if (winner.vin.nSequence != std::numeric_limits<unsigned int>::max())
        {
            std::stringstream msg;
            msg << boost::format("%s : mnw - invalid nSequence") % __func__;

            LogPrintf("%s\n", msg.str().c_str());
            pfrom->Misbehaving(msg.str(), 100);
            return;
        }

        int nDos = 0; //TODO: What's going on here? What's the point?

        if (!masternodePayments.CheckSignature(winner))
        {
            if (fDebug)
            {
                LogPrintf("%s : mnw - debug - address=%s nBlockHeight=%d nHeight=%d, prevout=%s\n", __func__,
                          address2.ToString(), winner.nBlockHeight, pindexBest->nHeight,
                          winner.vin.prevout.ToStringShort());
            }

            if (nDos)
            {
                std::stringstream msg;
                msg << boost::format("%s : mnw - [ERROR] invalid signature") % __func__;

                LogPrintf("%s\n", msg.str().c_str());
                pfrom->Misbehaving(msg.str(), nDos);
            }
            else
            {
                // only warn about anything non-critical (i.e. nDos == 0) in debug mode
                if (fDebug)
                    LogPrintf("%s : mnw - [WARNING] invalid signature\n", __func__);
            }

            // Either our info or vote info could be outdated.
            // In case our info is outdated, ask for an update,
            mnodeman.AskForMN(pfrom, winner.vin);

            // but there is nothing we can do if vote info itself is outdated
            // (i.e. it was signed by a mn which changed its key),
            // so just quit here.
            return;
        }

        LogPrintf("%s : mnw - new vote - address=%s, nBlockHeight=%d, nHeight=%d, prevout=%s, nHash=%s\n",
                  __func__, address2.ToString(), winner.nBlockHeight, pindexBest->nHeight,
                  winner.vin.prevout.ToStringShort(), nHash.ToString());

        mapSeenMasternodeVotes.insert(make_pair(nHash, winner));

        if (masternodePayments.AddWinningMasternode(winner))
            masternodePayments.Relay(winner);
    }
}

struct CompareValueOnly
{
    bool operator()(const pair<int64_t, CTxIn>& t1,
                    const pair<int64_t, CTxIn>& t2) const
    {
        return t1.first < t2.first;
    }
};

struct CompareValueOnly2
{
    bool operator()(const pair<int64_t, int>& t1,
                    const pair<int64_t, int>& t2) const
    {
        return t1.first < t2.first;
    }
};

int CountMasternodesAboveProtocol(int protocolVersion)
{
    int i = 0;
    LOCK(cs_masternodes);

    BOOST_FOREACH(CMasternode& mn, vecMasternodes)
    {
        if (mn.protocolVersion < protocolVersion)
            continue;

        i++;
    }

    return i;
}

int GetMasternodeByVin(CTxIn& vin)
{
    int i = 0;
    LOCK(cs_masternodes);

    BOOST_FOREACH(CMasternode& mn, vecMasternodes)
    {
        if (mn.vin == vin)
            return i;

        i++;
    }

    return -1;
}

int GetCurrentMasterNode(int mod, int64_t nBlockHeight, int minProtocol)
{
    int i = 0;
    unsigned int score = 0;
    int winner = -1;
    LOCK(cs_masternodes);

    // scan for winner
    BOOST_FOREACH(CMasternode mn, vecMasternodes)
    {
        mn.Check();

        if (mn.protocolVersion < minProtocol || !mn.IsEnabled())
        {
            i++;
            continue;
        }

        // calculate the score for each masternode
        uint256 n = mn.CalculateScore(nBlockHeight);
        unsigned int n2 = 0;
        memcpy(&n2, &n, sizeof(n2));

        // determine the winner
        if (n2 > score)
        {
            score = n2;
            winner = i;
        }

        i++;
    }

    return winner;
}

int GetMasternodeByRank(int findRank, int64_t nBlockHeight, int minProtocol)
{
    LOCK(cs_masternodes);
    int i = 0;
    std::vector<pair<unsigned int, int> > vecMasternodeScores;

    BOOST_FOREACH(CMasternode mn, vecMasternodes)
    {
        mn.Check();

        if (mn.protocolVersion < minProtocol)
            continue;

        if (!mn.IsEnabled())
        {
            i++;
            continue;
        }

        uint256 n = mn.CalculateScore(nBlockHeight);
        unsigned int n2 = 0;
        memcpy(&n2, &n, sizeof(n2));

        vecMasternodeScores.push_back(make_pair(n2, i));
        i++;
    }

    sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly2());
    int rank = 0;

    BOOST_FOREACH (PAIRTYPE(unsigned int, int)& s, vecMasternodeScores)
    {
        rank++;

        if (rank == findRank)
            return s.second;
    }

    return -1;
}

int GetMasternodeRank(CTxIn& vin, int64_t nBlockHeight, int minProtocol)
{
    LOCK(cs_masternodes);
    std::vector<pair<unsigned int, CTxIn> > vecMasternodeScores;

    BOOST_FOREACH(CMasternode& mn, vecMasternodes)
    {
        mn.Check();

        if (mn.protocolVersion < minProtocol)
            continue;

        if (!mn.IsEnabled())
            continue;

        uint256 n = mn.CalculateScore(nBlockHeight);
        unsigned int n2 = 0;
        memcpy(&n2, &n, sizeof(n2));

        vecMasternodeScores.push_back(make_pair(n2, mn.vin));
    }

    sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly());
    unsigned int rank = 0;

    BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores)
    {
        rank++;

        if (s.second == vin)
            return rank;
    }

    return -1;
}

//Get the last hash that matches the modulus given. Processed in reverse order
bool GetBlockHash(uint256& hash, int nBlockHeight)
{
    if (pindexBest == NULL || nBlockHeight < 0 || nBlockHeight > nBestHeight)
    {
        LogPrintf("%s : failed to get block %d\n", __func__, nBlockHeight);
        return false;
    }

    if (nBlockHeight == 0)
        nBlockHeight = pindexBest->nHeight;

    hash = FindBlockByHeight(nBlockHeight)->GetBlockHash();
    return true;
}

// Deterministically calculate a given "score" for a masternode depending on how close it's hash is to
// the proof of work for that block. The further away they are the better, the furthest will win the election
// and get paid this block

uint256 CMasternode::CalculateScore(unsigned int nBlockHeight)
{
    if (pindexBest == NULL)
    {
        LogPrintf("%s : pindexbest is null\n", __func__);
        return 0;
    }

    uint256 hash = 0;
    uint256 aux = vin.prevout.hash + vin.prevout.n;

    if(!GetBlockHash(hash, nBlockHeight - MASTERNODE_BLOCK_OFFSET))
    {
        LogPrintf("%s : failed to get blockhash\n", __func__);
        return 0;
    }
    CDataStream ss(SER_GETHASH, 0);
    ss << hash;
    uint256 hash2 = Hash(ss.begin(), ss.end());

    ss << aux;
    uint256 hash3 = Hash(ss.begin(), ss.end());

    uint256 r = (hash3 > hash2 ? hash3 - hash2 : hash2 - hash3);
    return r;
}

void CMasternode::Check()
{
    if (GetTime() - lastTimeChecked < MASTERNODE_CHECK_SECONDS)
        return;

    lastTimeChecked = GetTime();

    // once spent, stop doing the checks
    if (nActiveState==MASTERNODE_VIN_SPENT)
        return;

    // only accept p2p port for mainnet and testnet
   // if (addr.GetPort() != GetDefaultPort())
   // {
   //     nActiveState = MASTERNODE_POS_ERROR;
   //     return;
   // }

    if (!UpdatedWithin(MASTERNODE_REMOVAL_SECONDS))
    {
        nActiveState = MASTERNODE_REMOVE;
        return;
    }

    if (!UpdatedWithin(MASTERNODE_EXPIRATION_SECONDS))
    {
        nActiveState = MASTERNODE_EXPIRED;
        return;
    }

    if (!unitTest)
    {
        CTransaction tx = CTransaction();
        CTxOut vout = CTxOut(24999 * COIN, darkSendPool.collateralPubKey);
        tx.vin.push_back(vin);
        tx.vout.push_back(vout);

        // if(!AcceptableInputs(mempool, state, tx)){
        bool pfMissingInputs = false;

        if (!AcceptableInputs(mempool, tx, false, &pfMissingInputs))
        {
            nActiveState = MASTERNODE_VIN_SPENT;
            return;
        }
    }

    nActiveState = MASTERNODE_ENABLED; // OK
}

std::string CMasternode::StateToString(int nStateIn)
{
    switch(nStateIn)
    {
        case MASTERNODE_ENABLED:   return "ENABLED";
        case MASTERNODE_EXPIRED:   return "EXPIRED";
        case MASTERNODE_VIN_SPENT: return "VIN_SPENT";
        case MASTERNODE_REMOVE:    return "REMOVE";
        case MASTERNODE_POS_ERROR: return "POS_ERROR";
        default:                   return "UNKNOWN";
    }
}

std::string CMasternode::GetStateString() const
{
    return StateToString(nActiveState);
}

std::string CMasternode::GetStatus() const
{
    // TODO: return soemthing a bit more human readable here
    return GetStateString();
}

bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner)
{
    //NOTE: need to investigate why this is failing
    std::string strMessage = winner.vin.ToString().c_str() +
                             boost::lexical_cast<std::string>(winner.nBlockHeight) +
                             winner.payee.ToString();

    std::string strPubKey = !fTestNet ? strMainPubKey: strTestPubKey;
    CPubKey pubkey(ParseHex(strPubKey));

    if (fDebug)
       LogPrintf("%s : strMessage: %s, strPubKey: %s\n", __func__, strMessage, strPubKey);

    std::string errorMessage = "";

    if (!darkSendSigner.VerifyMessage(pubkey, winner.vchSig, strMessage, errorMessage))
    {
        if (fDebug)
        {
            if (!errorMessage.empty())
                LogPrintf("%s : VerifyMessage() failed, error: %s\n", __func__, errorMessage);
            else
                LogPrintf("%s : VerifyMessage() failed\n", __func__);
        }

        return false;
    }

    return true;
}

bool CMasternodePayments::Sign(CMasternodePaymentWinner& winner)
{
    std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast<std::string>(winner.nBlockHeight) + winner.payee.ToString();

    CKey key2;
    CPubKey pubkey2;
    std::string errorMessage = "";

    if (!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
    {
        LogPrintf("%s : [ERROR] invalid masternodeprivkey: '%s'\n", __func__, errorMessage.c_str());
        return false;
    }

    if (!darkSendSigner.SignMessage(strMessage, errorMessage, winner.vchSig, key2))
    {
        LogPrintf("%s : sign message failed\n", __func__);
        return false;
    }

    if (!darkSendSigner.VerifyMessage(pubkey2, winner.vchSig, strMessage, errorMessage))
    {
        LogPrintf("%s : verify message failed\n", __func__);
        return false;
    }

    return true;
}

bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
{
    LOCK(cs_masternodes);
    std::map<int, CMasternodePaymentWinner>::iterator winner = vWinning.find(nBlockHeight);

    if (winner != vWinning.end() && winner->second.nBlockHeight == nBlockHeight)
    {
        payee = winner->second.payee;
        return true;
    }

    return false;
}

bool CMasternodePayments::GetWinningMasternode(int nBlockHeight, CTxIn& vinOut)
{
    LOCK(cs_masternodes);
    std::map<int, CMasternodePaymentWinner>::iterator winner = vWinning.find(nBlockHeight);

    if (winner != vWinning.end() && winner->second.nBlockHeight == nBlockHeight)
    {
        vinOut = winner->second.vin;
        return true;
    }

    return false;
}

bool CMasternodePayments::AddPastWinningMasternode(std::vector<CTransaction>& vtx, int64_t amount, int height)
{
   LOCK(cs_masternodes);

   if (vtx.size() > 1)
   {
      for (const CTxOut out : vtx[1].vout)
      {
         if (amount == out.nValue)
         {
            CMasternodePaymentWinner winner;

            winner.score = -1; /* We can't know this as we dont know the previous state */
            winner.nBlockHeight = height;
            winner.payee = out.scriptPubKey;

            vWinning.erase(height);
            vWinning.insert(make_pair(height, winner));
            return true;
         }
      }
   }

   return false;
}

bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn, bool reorganize)
{
    LOCK(cs_masternodes);
    std::map<int, CMasternodePaymentWinner>::iterator winner = vWinning.find(winnerIn.nBlockHeight);

    if (winner != vWinning.end() && winner->second.nBlockHeight == winnerIn.nBlockHeight)
    {
        if (reorganize || winner->second.score <= winnerIn.score)
        {
            LogPrintf("%s : new masternode winner %s - replacing\n", __func__,
                      reorganize ? "during reorganize" : "has an equal or higher score");

            winner->second.score = winnerIn.score;
            winner->second.vin = winnerIn.vin;
            winner->second.payee = winnerIn.payee;
            winner->second.vchSig = winnerIn.vchSig;

            return true;
        }
        else
            LogPrintf("%s : new masternode winner has a lower score - ignoring\n", __func__);
    }
    else
    {
        LogPrintf("%s : adding block %d\n", __func__, winnerIn.nBlockHeight);
        vWinning.insert(make_pair(winnerIn.nBlockHeight, winnerIn));
        mapSeenMasternodeVotes.insert(make_pair(winnerIn.GetHash(), winnerIn));

        return true;
    }

    return false;
}

void CMasternodePayments::CleanPaymentList()
{
    LOCK(cs_masternodes);

    if (pindexBest == nullptr)
        return;

    int nLimit = std::max(((int) vecMasternodes.size()) * 2, 1000);

    for (int i = 0; i < (int) vWinning.size() - nLimit; i++)
    {
       int height = pindexBest->nHeight - vWinning.size() + i;

       if (vWinning.erase(height) > 0 && fDebug)
           LogPrintf("%s : Removing old masternode payment block %d\n", __func__, height);
    }
}

bool CMasternodePayments::ProcessBlock(int nBlockHeight, bool reorganize)
{
    CMasternodePaymentWinner winner;

    {
        LOCK(cs_masternodes);

        // scan for winner
        unsigned int score = 0;

        for (CMasternode mn : vecMasternodes)
        {
            mn.Check();

            if (!mn.IsEnabled())
                continue;

            // calculate the score for each masternode
            uint256 nScore_256 = mn.CalculateScore(nBlockHeight);
            unsigned int n2 = static_cast<unsigned int>(nScore_256.Get64());

            // determine the winner
            if (n2 > score)
            {
                score = n2;
                winner.score = n2;
                winner.nBlockHeight = nBlockHeight;
                winner.vin = mn.vin;
                winner.payee = GetScriptForDestination(mn.pubkey.GetID());
            }
        }
    }

    // if we can't find someone to get paid, pick randomly
    if (winner.nBlockHeight == 0 && vecMasternodes.size() > 0)
    {
        LogPrintf("%s : using random mn as winner\n", __func__);
        winner.score = 0;
        winner.nBlockHeight = nBlockHeight;
        unsigned int nHeightOffset = nBlockHeight;

        if (nHeightOffset > vecMasternodes.size() - 1)
            nHeightOffset = (vecMasternodes.size() - 1) % nHeightOffset;

        winner.vin = vecMasternodes[nHeightOffset].vin;
        winner.payee = GetScriptForDestination(vecMasternodes[nHeightOffset].pubkey.GetID());
    }

    CTxDestination address1;
    ExtractDestination(winner.payee, address1);
    CBitcoinAddress address2(address1);

    LogPrintf("%s : winner, payee=%s, nBlockHeight=%d\n", __func__,
              address2.ToString(), nBlockHeight);

    if (AddWinningMasternode(winner, reorganize))
    {
        if (enabled)
        {
            LogPrintf("%s : signing winner\n", __func__);

            if (Sign(winner))
            {
                LogPrintf("%s : relay winner\n", __func__);
                Relay(winner);
            }
        }

        return true;
    }

    return false;
}

bool CMasternodePayments::ProcessManyBlocks(int nBlockHeight)
{
    if (vecMasternodes.empty())
        return false;

    for (int i = nBlockHeight + 1; i < nBlockHeight + 10; i++)
        ProcessBlock(i);

   return true;
}

void CMasternodePayments::Relay(CMasternodePaymentWinner& winner)
{
    CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash());
    vector<CInv> vInv;

    vInv.push_back(inv);
    LOCK(cs_vNodes);

    BOOST_FOREACH(CNode* pnode, vNodes)
        pnode->PushMessage(NetMsgType::INV, vInv);
}

void CMasternodePayments::Sync(CNode* node)
{
    int a = 0;

    for (auto winner : vWinning)
    {
        if (winner.second.nBlockHeight >= pindexBest->nHeight - 10 &&
            winner.second.nBlockHeight <= pindexBest->nHeight + 20)
        {
            node->PushMessage(NetMsgType::MASTERNODEPAYMENTVOTE, winner.second, a);
        }
    }
}

bool CMasternodePayments::SetPrivKey(std::string strPrivKey)
{
    CMasternodePaymentWinner winner;

    // test signing successful, proceed
    strMasterPrivKey = strPrivKey;

    Sign(winner);

    if (CheckSignature(winner))
    {
        LogPrintf("%s : successfully initialized as masternode payments master\n", __func__);
        enabled = true;

        return true;
    }
    else
        return false;
}

void CMasternodeMan::AskForMN(CNode* pnode, CTxIn& vin)
{
    std::map<COutPoint, int64_t>::iterator i = mWeAskedForMasternodeListEntry.find(vin.prevout);

    if (i != mWeAskedForMasternodeListEntry.end())
    {
        int64_t t = (*i).second;

        // we have asked recently?
        if (GetTime() < t)
            return;
    }

    // ask for the mnb info once from the node that sent mnp
    LogPrintf("%s : asking for missing masternode entry, peer: %s vin: %s\n", __func__,
              pnode->addr.ToString(), vin.prevout.ToStringShort());

    pnode->PushMessage(NetMsgType::DSEG, vin);
    int64_t askAgain = GetTime() + MASTERNODE_DSEG_SECONDS;
    mWeAskedForMasternodeListEntry[vin.prevout] = askAgain;
}

void CMasternodeMan::Check()
{
    LOCK(cs_masternodes);

    BOOST_FOREACH (CMasternode& mn, vecMasternodes)
        mn.Check();
}

void CMasternodeMan::CheckAndRemove()
{
    LogPrintf("%s : started\n", __func__);

    {
        LOCK(cs_masternodes);

        Check();
        LogPrintf("%s : remove masternodes\n", __func__);

        // remove inactive and outdated
        vector<CMasternode>::iterator it = vecMasternodes.begin();

        while (it != vecMasternodes.end())
        {
            if ((*it).nActiveState == CMasternode::MASTERNODE_REMOVE ||
                (*it).nActiveState == CMasternode::MASTERNODE_VIN_SPENT)
            {
                LogPrintf("%s : removing inactive masternode %s - %s, reason: %d\n", __func__,
                          (*it).addr.ToString().c_str(), (*it).vin.prevout.hash.ToString(), (*it).nActiveState);

                it = vecMasternodes.erase(it);
            }
            else
                ++it;
        }
    }

    // TODO: NTRN - do more checks here

    {
        // no need for cm_main below
        LOCK(cs);

        LogPrintf("%s : remove asked\n", __func__);

        // check who's asked for the Masternode list
        auto it1 = mAskedUsForMasternodeList.begin();

        while(it1 != mAskedUsForMasternodeList.end())
        {
            if ((*it1).second < GetTime())
                mAskedUsForMasternodeList.erase(it1++);
            else
                ++it1;
        }
    }

    LogPrintf("%s : finished\n", __func__);
}

void CMasternodeMan::Clear()
{
    LOCK(cs_masternodes);
    vecMasternodes.clear();
}

int CMasternodeMan::CountEnabled(int protocolVersion)
{
    int i = 0;
    protocolVersion = protocolVersion == -1 ? ActiveProtocol() : protocolVersion;

    BOOST_FOREACH (CMasternode& mn, vecMasternodes)
    {
        mn.Check();

        if (mn.protocolVersion < protocolVersion || !mn.IsEnabled())
            continue;

        i++;
    }

    return i;
}

CMasternode* CMasternodeMan::Find(const CTxIn& vin)
{
    LOCK(cs_masternodes);

    BOOST_FOREACH (CMasternode& mn, vecMasternodes)
    {
        if (mn.vin.prevout == vin.prevout)
            return &mn;
    }

    return nullptr;
}

max_stars_repo_name: barrystyle/neutron

max_issues_repo_name: barrystyle/neutron

max_forks_repo_name: barrystyle/neutron


text:
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
  boost::gregorian::date d1(2009, 1, 30);
  boost::gregorian::date d2(2009, 10, 31);
  boost::gregorian::date_period dp(d1, d2);
  std::cout << dp.contains(d1) << std::endl;
  std::cout << dp.contains(d2) << std::endl;
}

ext: cpp

max_stars_repo_path: Boost/The Boost C++ Libraries/src/10.2.8/main.cpp


text:
#include "stdafx.h"
#include "CppUnitTest.h"
#include "splines.h"
#include <iostream>
#include <iomanip>
#include <limits>
#include <vector>
 #include <fstream>
#include <array>
#include <Eigen/Dense>
#include <Eigen/StdVector>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest1
{
	TEST_CLASS(UnitTest1)

	{
	public:
		double max_double = std::numeric_limits<double>::max();

		TEST_METHOD(Cubic2dCoefficient)
		{
			std::ifstream in_file("cubic2d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("cubic2dcoeff.points");
			Eigen::Vector2d control_point;
			std::vector<Eigen::Vector2d> control_points;
			while (in_file >> control_point.x() >> control_point.y()) {
				control_points.push_back(control_point);
			}
			std::vector<double> coefficients;
			for (size_t i = 0; i < control_points.size() / 4; ++i) {
				coefficients = bezier::GetCoefficients<double>(control_points, i, 3, bezier::k2d);
				Assert::IsTrue(coefficients.size() == 8);
				out_file << std::fixed << std::setprecision(14);
				for (auto j : coefficients) {
					out_file << j << '\n';
				}
			}
		}

		TEST_METHOD(Cubic3dCoefficient)
		{
			std::ifstream in_file("cubic3d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("cubic3dcoeff.points");
			Eigen::Vector3d control_point;
			std::vector<Eigen::Vector3d> control_points;
			while (in_file >> control_point.x() >> control_point.y() >> control_point.z()) {
				control_points.push_back(control_point);
			}
			std::vector<double> coefficients;
			for (size_t i = 0; i < control_points.size() / 4; ++i) {
				coefficients = bezier::GetCoefficients<double>(control_points, i);
				Assert::IsTrue(coefficients.size() == 12);
				out_file << std::fixed << std::setprecision(14);
				for (auto j : coefficients) {
					out_file << j << '\n';
				}
			}
		}

		TEST_METHOD(Quad2dCoefficient)
		{
			std::ifstream in_file("quad2d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("quad2dcoeff.points");
			Eigen::Vector2d control_point;
			std::vector<Eigen::Vector2d> control_points;
			while (in_file >> control_point.x() >> control_point.y()) {
				control_points.push_back(control_point);
			}
			std::vector<double> coefficients;
			for (size_t i = 0; i < control_points.size() / 3; ++i) {
				coefficients = bezier::GetCoefficients<double>(control_points, i, 2, bezier::k2d);
				Assert::IsTrue(coefficients.size() == 6);
				out_file << std::fixed << std::setprecision(14);
				for (auto j : coefficients) {
					out_file << j << '\n';
				}
			}
		}

		TEST_METHOD(Quad3dCoefficient)
		{
			std::ifstream in_file("quad3d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("quad3dcoeff.points");
			Eigen::Vector3d control_point;
			std::vector<Eigen::Vector3d> control_points;
			while (in_file >> control_point.x() >> control_point.y() >> control_point.z()) {
				control_points.push_back(control_point);
			}
			std::vector<double> coefficients;
			for (size_t i = 0; i < control_points.size() / 3; ++i) {
				coefficients = bezier::GetCoefficients<double>(control_points, i, 2, bezier::k3d);
				Assert::IsTrue(coefficients.size() == 9);
				out_file << std::fixed << std::setprecision(14);
				for (auto j : coefficients) {
					out_file << j << '\n';
				}
			}
		}

		TEST_METHOD(Cubic2dCoordinate)
		{
			std::ifstream in_file("cubic2d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("cubic2dcoord.points");
			Eigen::Vector2d control_point;
			std::vector<Eigen::Vector2d> control_points;
			while (in_file >> control_point.x() >> control_point.y()) {
				control_points.push_back(control_point);
			}

			Eigen::Vector2d coordinate;
			Eigen::Vector2d empty;
			empty << max_double, max_double;
			coordinate = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 4; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .25, i, 3, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .5, i, 3, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .75, i, 3, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
			}

		}

		TEST_METHOD(Cubic3dCoordinate)
		{
			std::ifstream in_file("cubic3d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("cubic3dcoord.points");
			Eigen::Vector3d control_point;
			std::vector<Eigen::Vector3d> control_points;
			while (in_file >> control_point.x() >> control_point.y() >> control_point.z()) {
				control_points.push_back(control_point);
			}

			Eigen::Vector3d coordinate;
			Eigen::Vector3d empty;
			empty << max_double, max_double, max_double;
			coordinate = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 4; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .25, i);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .5, i);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .75, i);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
			}

		}

		TEST_METHOD(Quad2dCoordinate)
		{
			std::ifstream in_file("quad2d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("quad2dcoord.points");
			Eigen::Vector2d control_point;
			std::vector<Eigen::Vector2d> control_points;
			while (in_file >> control_point.x() >> control_point.y()) {
				control_points.push_back(control_point);
			}
			Eigen::Vector2d coordinate;
			Eigen::Vector2d empty;
			empty << max_double, max_double;
			coordinate = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 3; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .25, i, 2, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .5, i, 2, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .75, i, 2, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
			}

		}

		TEST_METHOD(Quad3dCoordinate)
		{
			std::ifstream in_file("quad3d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("quad3dcoord.points");
			Eigen::Vector3d control_point;
			std::vector<Eigen::Vector3d> control_points;
			while (in_file >> control_point.x() >> control_point.y() >> control_point.z()) {
				control_points.push_back(control_point);
			}
			Eigen::Vector3d coordinate;
			Eigen::Vector3d empty;
			empty << max_double, max_double, max_double;
			coordinate = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 3; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .25, i, 2);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .5, i, 2);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
				coordinate = bezier::GetPosition<double>(control_points, .75, i, 2);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				coordinate = empty;
			}

		}

		TEST_METHOD(Cubic2dTangent)
		{
			std::ifstream in_file("cubic2d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("cubic2dtan.points");
			Eigen::Vector2d control_point;
			std::vector<Eigen::Vector2d> control_points;
			while (in_file >> control_point.x() >> control_point.y()) {
				control_points.push_back(control_point);
			}

			Eigen::Vector2d coordinate;
			Eigen::Vector2d tangent;
			Eigen::Vector2d empty;
			empty << max_double, max_double;
			coordinate = empty;
			tangent = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 4; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .5, i, 3, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				tangent = bezier::GetFirstDerivative<double>(control_points, .5, i, 3, bezier::k2d);
				Assert::IsFalse(tangent == empty);
				tangent.normalize();
				tangent += coordinate;
				out_file << tangent.transpose() << '\n';
				coordinate = empty;
				tangent = empty;
			}
		}

		TEST_METHOD(Cubic3dTangent)
		{
			//using Point = Eigen::Vector3d;
			using Point = std::array<double, 3>;
			std::ifstream in_file("cubic.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("cubic.points");
			Point control_point;
			std::vector<Point> control_points;
			//while (in_file >> control_point.x() >> control_point.y() >> control_point.z()) {
			//	control_points.push_back(control_point);
			//}
			while (in_file >> control_point[0] >> control_point[1] >> control_point[2]) {
				control_points.push_back(control_point);
			}

			Point coordinate;
			Point tangent;
			Point normal;
			Point empty;
			//empty << max_double, max_double, max_double;
			for (size_t i = 0; i < 3; ++i) {
				empty[i] = max_double;
			}
			coordinate = empty;
			normal = empty;
			tangent = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 4; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .25, i);
				Assert::IsFalse(coordinate == empty);
				Eigen::Vector3d eigen_coordinate;
				eigen_coordinate << coordinate[0], coordinate[1], coordinate[2];
				out_file << eigen_coordinate.transpose() << '\n';
				//out_file << coordinate[0] << ' ' << coordinate[1] << ' ' << coordinate[2] << '\n';
				tangent = bezier::GetFirstDerivative<double>(control_points, .25, i);
				Assert::IsFalse(tangent == empty);
				Eigen::Vector3d normal_tangent;
				normal_tangent << tangent[0], tangent[1], tangent[2];
				normal_tangent.normalize();
				normal_tangent += eigen_coordinate;
				out_file << normal_tangent.transpose() << '\n';
				//out_file << tangent.transpose() << '\n';
				normal = bezier::GetNormal<double>(control_points, .25, i);
				Assert::IsFalse(normal == empty);
				Eigen::Vector3d eigen_normal;
				eigen_normal << normal[0], normal[1], normal[2];
				eigen_normal.normalize();
				eigen_normal += eigen_coordinate;
				out_file << eigen_normal.transpose() << '\n';
				coordinate = empty;
				tangent = empty;

				coordinate = bezier::GetPosition<double>(control_points, .5, i);
				Assert::IsFalse(coordinate == empty);
				eigen_coordinate << coordinate[0], coordinate[1], coordinate[2];
				out_file << eigen_coordinate.transpose() << '\n';
				//out_file << coordinate[0] << ' ' << coordinate[1] << ' ' << coordinate[2] << '\n';
				tangent = bezier::GetFirstDerivative<double>(control_points, .5, i);
				Assert::IsFalse(tangent == empty);
				normal_tangent << tangent[0], tangent[1], tangent[2];
				normal_tangent.normalize();
				normal_tangent += eigen_coordinate;
				out_file << normal_tangent.transpose() << '\n';
				//out_file << tangent.transpose() << '\n';
				normal = bezier::GetNormal<double>(control_points, .5, i);
				Assert::IsFalse(normal == empty);
				eigen_normal << normal[0], normal[1], normal[2];
				eigen_normal.normalize();
				eigen_normal += eigen_coordinate;
				out_file << eigen_normal.transpose() << '\n';
				coordinate = empty;
				tangent = empty;

				coordinate = bezier::GetPosition<double>(control_points, .75, i);
				Assert::IsFalse(coordinate == empty);
				eigen_coordinate << coordinate[0], coordinate[1], coordinate[2];
				out_file << eigen_coordinate.transpose() << '\n';
				//out_file << coordinate[0] << ' ' << coordinate[1] << ' ' << coordinate[2] << '\n';
				tangent = bezier::GetFirstDerivative<double>(control_points, .75, i);
				Assert::IsFalse(tangent == empty);
				normal_tangent << tangent[0], tangent[1], tangent[2];
				normal_tangent.normalize();
				normal_tangent += eigen_coordinate;
				out_file << normal_tangent.transpose() << '\n';
				//out_file << tangent.transpose() << '\n';
				normal = bezier::GetNormal<double>(control_points, .75, i);
				Assert::IsFalse(normal == empty);
				eigen_normal << normal[0], normal[1], normal[2];
				eigen_normal.normalize();
				eigen_normal += eigen_coordinate;
				out_file << eigen_normal.transpose() << '\n';
				coordinate = empty;
				tangent = empty;
			}
		}

		TEST_METHOD(Quad2dTangent)
		{
			std::ifstream in_file("quad2d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("quad2dtan.points");
			Eigen::Vector2d control_point;
			std::vector<Eigen::Vector2d> control_points;
			while (in_file >> control_point.x() >> control_point.y()) {
				control_points.push_back(control_point);
			}

			Eigen::Vector2d coordinate;
			Eigen::Vector2d tangent;
			Eigen::Vector2d normal;
			Eigen::Vector2d empty;
			empty << max_double, max_double;
			coordinate = empty;
			tangent = empty;
			normal = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 3; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .5, i, 2, bezier::k2d);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				tangent = bezier::GetFirstDerivative<double>(control_points, .5, i, 2, bezier::k2d);
				Assert::IsFalse(tangent == empty);
				tangent.normalize();
				tangent += coordinate;
				out_file << tangent.transpose() << '\n';
				//normal = bezier::GetNormal<double, bezier::k2d, 2>(control_points, i, .5);
				//Assert::IsFalse(normal == empty);
				//normal.normalize();
				//normal += coordinate;
				//out_file << normal.transpose() << '\n';
				coordinate = empty;
				tangent = empty;
			}
		}

		TEST_METHOD(Quad3dTangent)
		{
			using Point = Eigen::Vector3d;
			std::ifstream in_file("quad3d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("quad3dtan.points");
			Point control_point;
			std::vector<Point> control_points;
			while (in_file >> control_point.x() >> control_point.y() >> control_point.z()) {
				control_points.push_back(control_point);
			}

			Point coordinate;
			Point tangent;
			Point normal;
			Point empty;
			empty << max_double, max_double, max_double;
			coordinate = empty;
			tangent = empty;
			normal = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 3; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .75, i, 2);
				Assert::IsFalse(coordinate == empty);
				out_file << coordinate.transpose() << '\n';
				tangent = bezier::GetFirstDerivative<double>(control_points, .75, i, 2);
				Assert::IsFalse(tangent == empty);
				tangent.normalize();
				tangent += coordinate;
				out_file << tangent.transpose() << '\n';
				normal = bezier::GetNormal<double>(control_points, .75, i, 2);
				Assert::IsFalse(normal == empty);
				normal.normalize();
				normal += coordinate;
				out_file << normal.transpose() << '\n';
				coordinate = empty;
				tangent = empty;
			}
		}

		TEST_METHOD(Quartic3dTangent)
		{
			using Point = Eigen::Vector3d;
			//using Point = std::array<double, 3>;
			std::ifstream in_file("quartic3d.dat");
			Assert::IsTrue(in_file.is_open());
			std::ofstream out_file("quartic3dtan.points");
			Point control_point;
			std::vector<Point> control_points;
			//while (in_file >> control_point.x() >> control_point.y() >> control_point.z()) {
			//	control_points.push_back(control_point);
			//}
			while (in_file >> control_point[0] >> control_point[1] >> control_point[2]) {
				control_points.push_back(control_point);
			}

			Point coordinate;
			Point tangent;
			Point normal;
			Point empty;
			//empty << max_double, max_double, max_double;
			for (size_t i = 0; i < 3; ++i) {
				empty[i] = max_double;
			}
			coordinate = empty;
			normal = empty;
			tangent = empty;
			out_file << std::fixed << std::setprecision(14);
			for (size_t i = 0; i < control_points.size() / 5; ++i) {
				coordinate = bezier::GetPosition<double>(control_points, .5, i, 4);
				Assert::IsFalse(coordinate == empty);
				Eigen::Vector3d eigen_coordinate;
				eigen_coordinate << coordinate[0], coordinate[1], coordinate[2];
				out_file << eigen_coordinate.transpose() << '\n';
				//out_file << coordinate[0] << ' ' << coordinate[1] << ' ' << coordinate[2] << '\n';
				tangent = bezier::GetFirstDerivative<double>(control_points, .5, i, 4, bezier::k3d);
				Assert::IsFalse(tangent == empty);
				Eigen::Vector3d normal_tangent;
				normal_tangent << tangent[0], tangent[1], tangent[2];
				normal_tangent.normalize();
				normal_tangent += eigen_coordinate;
				out_file << normal_tangent.transpose() << '\n';
				normal = bezier::GetNormal<double>(control_points, .5, i, 4);
				Assert::IsFalse(normal == empty);
				Eigen::Vector3d eigen_normal;
				eigen_normal << normal[0], normal[1], normal[2];
				eigen_normal.normalize();
				eigen_normal += eigen_coordinate;
				out_file << eigen_normal.transpose() << '\n';
				coordinate = empty;
				tangent = empty;
			}
		}

		TEST_METHOD(PascalRow) {
			std::ofstream out_file("pascalRow.dat");
			out_file << std::fixed << std::setprecision(0);
			Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> pascal_row = bezier::GetBinomialCoefficients<double>(10);
			//out_file << pascal_row.transpose() << '\n';
		}

	};
}

max_stars_repo_name: hpmachining/splines

max_issues_repo_name: hpmachining/splines

max_forks_repo_name: hpmachining/splines


text:
// Copyright 2021 Lawrence Livermore National Security, LLC and other Metall Project Developers.
// See the top-level COPYRIGHT file for details.
//
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#ifndef METALL_CONTAINER_EXPERIMENT_JSON_ARRAY_HPP
#define METALL_CONTAINER_EXPERIMENT_JSON_ARRAY_HPP

#include <iostream>
#include <memory>

#include <boost/container/vector.hpp>
#include <boost/container/scoped_allocator.hpp>

#include <metall/container/experimental/json/json_fwd.hpp>
#include <metall/container/experimental/json/value.hpp>

namespace metall::container::experimental::json {

namespace {
namespace bc = boost::container;
}

/// \brief JSON array.
/// An array is an ordered collection of values.
template <typename _allocator_type = std::allocator<std::byte>>
class array {
 private:
  template <typename alloc, typename T>
  using other_scoped_allocator = bc::scoped_allocator_adaptor<typename std::allocator_traits<alloc>::template rebind_alloc<T>>;

  using value_type = value<_allocator_type>;
  using aray_allocator_type = other_scoped_allocator<_allocator_type, value_type>;
  using array_type = bc::vector<value_type, aray_allocator_type>;

 public:
  using allocator_type = _allocator_type;
  using iterator = typename array_type::iterator;
  using const_iterator = typename array_type::const_iterator;

  explicit array(const allocator_type &alloc = allocator_type())
      : m_array(alloc) {}

  std::size_t size() const noexcept {
    return m_array.size();
  }

  void resize(const std::size_t size) {
    m_array.resize(size, value_type{m_array.get_allocator()});
  }

  value_type &operator[](const std::size_t index) {
    return m_array[index];
  }

  const value_type &operator[](const std::size_t index) const {
    return m_array[index];
  }

  iterator begin() {
    return m_array.begin();
  }

  const_iterator begin() const {
    return m_array.begin();
  }

  iterator end() {
    return m_array.end();
  }

  const_iterator end() const {
    return m_array.end();
  }

 private:
  array_type m_array;
};

template <typename allocator_type>
std::ostream &operator<<(std::ostream &os, const array<allocator_type> &data) {

  os << "[";
  for (std::size_t i = 0; i < data.size(); ++i) {
    if (i > 0) os << ", ";
    os << data[i];
  }
  os << "]";

  return os;
}

} // namespace metall::container::experimental::json

#endif //METALL_CONTAINER_EXPERIMENT_JSON_ARRAY_HPP

ext: hpp

max_stars_repo_name: KIwabuchi/metall

max_issues_repo_name: KIwabuchi/metall

max_forks_repo_name: KIwabuchi/metall


text:
/*
Copyright 2019 Association for the promotion of open - source insurance software and for the establishment of open interface standards in the insurance industry

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http ://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <chrono>
#include <iostream>
#include <memory>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/test/unit_test.hpp>
#include <calculusprime/cache/DefaultCacheFactory.h>
#include <calculusprime/IRatingEngine.h>
#include <calculusprime/RatingEngineException.h>
#include <calculusprime/RatingEngineFactory.h>
#include <calculusprime/Value.h>
#include "testfunctions.h"

using boost::unit_test_framework::test_suite;
using namespace CalculusPrime;

typedef IRatingEngine::Value_t Value_t;
typedef IRatingEngine::InstanceVariable_t InstanceVariable_t;

static const std::string g_dummyVtarKey("ee3812d0-8cf1-11e9-b475-0800200c9a66");

template <class ValueType>
class OStreamVisitor
    : public boost::static_visitor<>
{
public:
    OStreamVisitor(std::ostream& os_)
        : m_os(os_)
    {
    }

    void operator()(const IRatingEngine::Variant_t& variant_) const
    {
        m_os << variant_;
    }
    void operator()(const IRatingEngine::InstanceVariable_t& instanceVariable_) const
    {
        bool first = true;
        for (const IRatingEngine::InstanceVariable_t::value_type& iv : instanceVariable_) {
            if (!first) {
                m_os << ',';
            }
            else {
                first = false;
            }
            m_os << iv.first << '=' << iv.second;
        }
    }
private:
    std::ostream& m_os;
};

namespace boost {
std::ostream& operator<< (std::ostream& os_, const IRatingEngine::Value_t& value_)
{
    boost::apply_visitor(OStreamVisitor<IRatingEngine::Value_t>(os_), value_);
    return os_;
}
}

namespace {
IRatingEngine::Map_t makeInput()
{
    IRatingEngine::Map_t input{
        { "Wohnungswert", 300000.0 },
        { "Gut_checked", "N" },
        { "Besser_checked", "N" },
        { "Beste_checked", "J" },
        { "Er_WohnWert", "B" },
        { "Aqua_1000l_checked", "N" },
        { "Aqua_2000l_checked", "J" },
        { "HP_Hund_checked", "J" },
        { "Anz_Hunde", 2.0 },
        { "HP_Pferd_checked", "J" },
        { "Anz_Pferde", 4.0 },
        { "VS_Geldschrank", 0.0 },
        { "VS_Schmuck", 0.0 },
        { "VS_Schmuck_unversperrt", 0.0 },
        { "VS_Bargeld", 0.0 },
        { "VS_HP_Privat_Sport", 0.0 },
        { "Anzahl_VP", 0.0 }
    };
    return std::move(input);
}

IRatingEngine::Map_t makeInstanceInput()
{
    IRatingEngine::Map_t input{
        { "Wohnungswert", IRatingEngine::InstanceVariable_t { {"1", 300000.0}, {"2", 200000.0} } },
        { "Gut_checked", IRatingEngine::InstanceVariable_t{ { "1", "N" }, { "2", "N" } } },
        { "Besser_checked", IRatingEngine::InstanceVariable_t{ { "1", "N"}, { "2", "J"} } },
        { "Beste_checked", IRatingEngine::InstanceVariable_t{ { "1", "J"}, { "2", "N"} } },
        { "Er_WohnWert", IRatingEngine::InstanceVariable_t{ { "1", "B"}, { "2", "A"} } },
        { "Aqua_1000l_checked", IRatingEngine::InstanceVariable_t{ { "1", "N"}, { "2", "J"} } },
        { "Aqua_2000l_checked", IRatingEngine::InstanceVariable_t{ { "1", "J"}, { "2", "N"} } },
        { "HP_Hund_checked", IRatingEngine::InstanceVariable_t{ { "1", "J"}, { "2", "N"} } },
        { "Anz_Hunde", IRatingEngine::InstanceVariable_t{ { "1", 2.0}, { "2", 0.0} } },
        { "HP_Pferd_checked", IRatingEngine::InstanceVariable_t{ { "1", "J"}, { "2", "N"} } },
        { "Anz_Pferde", IRatingEngine::InstanceVariable_t{ { "1", 4.0}, { "2", 0.0} } },
        { "VS_Geldschrank", IRatingEngine::InstanceVariable_t{ { "1", 0.0 }, { "2", 11000.0} } },
        { "VS_Schmuck", IRatingEngine::InstanceVariable_t{ { "1", 0.0 }, { "2", 20000.0} } },
        { "VS_Schmuck_unversperrt", IRatingEngine::InstanceVariable_t{ { "1", 0.0 }, { "2", 10000.0} } },
        { "VS_Bargeld", IRatingEngine::InstanceVariable_t{ { "1", 0.0 }, { "2", 5000.0} } },
        { "VS_HP_Privat_Sport", IRatingEngine::InstanceVariable_t{ { "", 0.0 } } },
        { "Anzahl_VP", IRatingEngine::InstanceVariable_t{ { "", 0.0 } } }
    };
    return std::move(input);
}

IRatingEngine::RatingFormulaMap_t makeRatingFormulas()
{
    IRatingEngine::RatingFormulaMap_t variables {
        {
            "Praemie_Gut",
            "if (Gut_checked = 'J') then return max(Wohnungswert, GetSachtarif('MINVSGU')) * GetSachtarif('VARGUT1') else    return 0.0 end"
        },
        {
            "Praemie_Besser",
            "if (Besser_checked = 'J') then return max(Wohnungswert, GetSachtarif('MINVSBE')) * GetSachtarif('VARBESSER1') else return 0.0 end"
        },
        {
            "Praemie_Beste",
            "if (Beste_checked = 'J') then return max(Wohnungswert, GetSachtarif('MINVSSB')) * GetSachtarif('VARBESTE1') else return 0.0 end"
        },
        {
            "Summenermittlungsrabatt",
            "if (Er_WohnWert <> 'B') then     return GetSachtarif('HHSUERM') else     return 1 end"
        },
        {
            "Aqua_1000",
            "if (Aqua_1000l_checked = 'J') then    return 1.05 else    return 1 end"
        },
        {
            "Aqua_2000",
            "if (Aqua_2000l_checked = 'J') then    return 1.1 else    return 1 end"
        },
        {
            "Nachlass_Hunde",
            "if (Beste_checked = 'J') then   return GetSachtarif('HHNLHU1') else   return 1 end"
        },
        {
            "Variante",
            "if (Gut_checked = 'J') then   return 'Gut' else      if (Besser_checked = 'J') then          return 'BESSER'     else         return 'SBeste' end"
        },
        {
            "Praemie_pro_VP",
            "if (Anzahl_VP > 0) then     return GetTarifpraemie('VS_HP_Privat_Sport', 0, 'Variante') * Anzahl_VP else     return 0.0 end"
        },
        {
            "Variante_Person",
            "if (Gut_checked = 'J') then   return 'ERGut' else      if (Besser_checked = 'J') then          return 'ERBESSER'     else         return 'ERBeste' end"
        },
        {
            "Test",
            "return (Test1+Test2+Test3+Test4+Test5+Test5+Test6+Test7+Test8+Test9+Test10)"
        },
        {
            "Test1",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSGU')) * GetSachtarif('VARGUT1')"
        },
        {
            "Test2",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSGU')) * GetSachtarif('VARGUT1')"
        },
        {
            "Test3",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSGU')) * GetSachtarif('VARGUT1')"
        },
        {
            "Test4",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSGU')) * GetSachtarif('VARGUT1')"
        },
        {
            "Test5",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSGU')) * GetSachtarif('VARGUT1')"
        },
        {
            "Test6",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSSB')) * GetSachtarif('VARBESTE1')"
        },
        {
            "Test7",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSSB')) * GetSachtarif('VARBESTE1')"
        },
        {
            "Test8",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSSB')) * GetSachtarif('VARBESTE1')"
        },
        {
            "Test9",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSSB')) * GetSachtarif('VARBESTE1')"
        },
        {
            "Test10",
            "return 0*max(Wohnungswert,  GetSachtarif('MINVSSB')) * GetSachtarif('VARBESTE1')"
        }
    };
    return std::move(variables);
}

std::vector<RatingOutput> makeRatingOutput()
{
    std::vector<RatingOutput> output{
        {
            "Wohnungspraemie",
            0,
            "return (Praemie_Gut + Praemie_Besser + Praemie_Beste)*Aqua_1000*Aqua_2000*Summenermittlungsrabatt+Test",
            ""
        },
        {
            "Elektronikpauschalpraemie",
            0,
            "if (Beste_checked = 'J') then      return max(Wohnungswert, GetSachtarif('MINVSEL')) * GetSachtarif('HHPAUVS1') else      return 0.0 end",
            ""
        },
        {
            "HP_Hunde_Praemie",
            0,
            "if (HP_Hund_checked = 'J') then     return GetSachtarif('HHZDHU1')*Anz_Hunde * Nachlass_Hunde else     return 0 end",
            ""
        },
        {
            "HP_Pferde_Praemie",
            0,
            "if (HP_Pferd_checked = 'J') then      return GetSachtarif('HHZDPF1')*Anz_Pferde else     return 0 end",
            ""
        },
        {
            "Geldschrank_Praemie",
            0,
            "if (VS_Geldschrank > 0)  then    return GetSachtarif('GESCHR1') * (VS_Geldschrank - GetProdschabl('HH50123','MINDSUM')) else    return 0.0 end",
            ""
        },
        {
            "Schmuck_Praemie",
            0,
            "if (VS_Schmuck > 0)  then    return GetSachtarif('SCHMVER1') * (VS_Schmuck - GetProdschabl('HH50122','MINDSUM')) else    return 0.0 end",
            ""
        },
        {
            "Schmuck_unversperrrt_Praemie",
            0,
            "if (VS_Schmuck_unversperrt > 0)  then    return GetSachtarif('SCHMUNV1') * (VS_Schmuck_unversperrt - GetProdschabl('HH50121','MINDSUM')) else    return 0.0 end",
            ""
        },
        {
            "Bargeld_Praemie",
            0,
            "if (VS_Bargeld> 0)  then    return GetSachtarif('BARGELD') * (VS_Bargeld - GetProdschabl('HH50120','MINDSUM')) else    return 0.0 end",
            ""
        },
        {
            "HP_Privat_Sport_Praemie",
            0,
            "if (VS_HP_Privat_Sport > 0) then   return GetTarifpraemie('HH1245', VS_HP_Privat_Sport, 0, Variante) + Praemie_pro_VP else    return 0.0 end",
            ""
        }
    };
    return std::move(output);
}

std::vector<RatingOutput> makeInstanceRatingOutput()
{
    std::vector<RatingOutput> output{
        {
            "Wohnungspraemie",
            0,
            "return (Praemie_Gut + Praemie_Besser + Praemie_Beste)*Aqua_1000*Aqua_2000*Summenermittlungsrabatt+Test",
            "1"
        },
        {
            "Elektronikpauschalpraemie",
            0,
            "if (Beste_checked = 'J') then      return max(Wohnungswert, GetSachtarif('MINVSEL')) * GetSachtarif('HHPAUVS1') else      return 0.0 end",
            "1"
        },
        {
            "HP_Hunde_Praemie",
            0,
            "if (HP_Hund_checked = 'J') then     return GetSachtarif('HHZDHU1')*Anz_Hunde * Nachlass_Hunde else     return 0 end",
            "1"
        },
        {
            "HP_Pferde_Praemie",
            0,
            "if (HP_Pferd_checked = 'J') then      return GetSachtarif('HHZDPF1')*Anz_Pferde else     return 0 end",
            "1"
        },
        {
            "Geldschrank_Praemie",
            0,
            "if (VS_Geldschrank > 0)  then    return GetSachtarif('GESCHR1') * (VS_Geldschrank - GetProdschabl('HH50123','MINDSUM')) else    return 0.0 end",
            "1"
        },
        {
            "Schmuck_Praemie",
            0,
            "if (VS_Schmuck > 0)  then    return GetSachtarif('SCHMVER1') * (VS_Schmuck - GetProdschabl('HH50122','MINDSUM')) else    return 0.0 end",
            "1"
        },
        {
            "Schmuck_unversperrrt_Praemie",
            0,
            "if (VS_Schmuck_unversperrt > 0)  then    return GetSachtarif('SCHMUNV1') * (VS_Schmuck_unversperrt - GetProdschabl('HH50121','MINDSUM')) else    return 0.0 end",
            "1"
        },
        {
            "Bargeld_Praemie",
            0,
            "if (VS_Bargeld> 0)  then    return GetSachtarif('BARGELD') * (VS_Bargeld - GetProdschabl('HH50120','MINDSUM')) else    return 0.0 end",
            "1"
        },
        {
            "HP_Privat_Sport_Praemie",
            0,
            "if (VS_HP_Privat_Sport > 0) then   return GetTarifpraemie('HH1245', VS_HP_Privat_Sport, 0, Variante) + Praemie_pro_VP else    return 0.0 end",
            "1"
        },

        {
            "Wohnungspraemie",
            0,
            "return (Praemie_Gut + Praemie_Besser + Praemie_Beste)*Aqua_1000*Aqua_2000*Summenermittlungsrabatt+Test",
            "2"
        },
        {
            "Elektronikpauschalpraemie",
            0,
            "if (Beste_checked = 'J') then      return max(Wohnungswert, GetSachtarif('MINVSEL')) * GetSachtarif('HHPAUVS1') else      return 0.0 end",
            "2"
        },
        {
            "HP_Hunde_Praemie",
            0,
            "if (HP_Hund_checked = 'J') then     return GetSachtarif('HHZDHU1')*Anz_Hunde * Nachlass_Hunde else     return 0 end",
            "2"
        },
        {
            "HP_Pferde_Praemie",
            0,
            "if (HP_Pferd_checked = 'J') then      return GetSachtarif('HHZDPF1')*Anz_Pferde else     return 0 end",
            "2"
        },
        {
            "Geldschrank_Praemie",
            0,
            "if (VS_Geldschrank > 0)  then    return GetSachtarif('GESCHR1') * (VS_Geldschrank - GetProdschabl('HH50123','MINDSUM')) else    return 0.0 end",
            "2"
        },
        {
            "Schmuck_Praemie",
            0,
            "if (VS_Schmuck > 0)  then    return GetSachtarif('SCHMVER1') * (VS_Schmuck - GetProdschabl('HH50122','MINDSUM')) else    return 0.0 end",
            "2"
        },
        {
            "Schmuck_unversperrrt_Praemie",
            0,
            "if (VS_Schmuck_unversperrt > 0)  then    return GetSachtarif('SCHMUNV1') * (VS_Schmuck_unversperrt - GetProdschabl('HH50121','MINDSUM')) else    return 0.0 end",
            "2"
        },
        {
            "Bargeld_Praemie",
            0,
            "if (VS_Bargeld> 0)  then    return GetSachtarif('BARGELD') * (VS_Bargeld - GetProdschabl('HH50120','MINDSUM')) else    return 0.0 end",
            "2"
        },
        {
            "HP_Privat_Sport_Praemie",
            0,
            "if (VS_HP_Privat_Sport > 0) then   return GetTarifpraemie('HH1245', VS_HP_Privat_Sport, 0, Variante) + Praemie_pro_VP else    return 0.0 end",
            "2"
        }

    };
    return std::move(output);
}

void dumpResults(const IRatingEngine::Map_t& results_)
{
    // comment this in if needed
    //for (const IRatingEngine::Map_t::value_type& result : results_) {
    //    std::cout << result.first << ' ';
    //    boost::apply_visitor(OStreamVisitor<IRatingEngine::IRatingEngine::Value_t>(std::cout), result.second);
    //    std::cout << '\n';
    //}
}

void validateResults(IRatingEngine::Map_t& results_)
{
    BOOST_CHECK_EQUAL(results_["Wohnungspraemie"], Value_t(1320));
    BOOST_CHECK_EQUAL(results_["Elektronikpauschalpraemie"], Value_t(600));
    BOOST_CHECK_EQUAL(results_["Bargeld_Praemie"], Value_t(0));
    BOOST_CHECK_EQUAL(results_["HP_Hunde_Praemie"], Value_t(210));
    BOOST_CHECK_EQUAL(results_["HP_Pferde_Praemie"], Value_t(600));
    BOOST_CHECK_EQUAL(results_["HP_Privat_Sport_Praemie"], Value_t(0));
    BOOST_CHECK_EQUAL(results_["Geldschrank_Praemie"], Value_t(0));
    BOOST_CHECK_EQUAL(results_["Schmuck_Praemie"], Value_t(0));
    BOOST_CHECK_EQUAL(results_["Schmuck_unversperrrt_Praemie"], Value_t(0));
}

void validateInstanceResults(IRatingEngine::Map_t& results_)
{
    BOOST_CHECK_EQUAL(results_["Wohnungspraemie"], Value_t(InstanceVariable_t{ { "1", 1320 }, { "2", 623.7 } }));
    BOOST_CHECK_EQUAL(results_["Elektronikpauschalpraemie"], Value_t(InstanceVariable_t{ { "1", 600 }, { "2", 0 } }));
    BOOST_CHECK_EQUAL(results_["Bargeld_Praemie"], Value_t(InstanceVariable_t{ { "1", 0 }, { "2", 450 } }));
    BOOST_CHECK_EQUAL(results_["HP_Hunde_Praemie"], Value_t(InstanceVariable_t{ { "1", 210 }, { "2", 0 } }));
    BOOST_CHECK_EQUAL(results_["HP_Pferde_Praemie"], Value_t(InstanceVariable_t{ { "1", 600 }, { "2", 0 } }));
    BOOST_CHECK_EQUAL(results_["HP_Privat_Sport_Praemie"], Value_t(InstanceVariable_t{ { "1", 0 }, { "2", 0 } }));
    BOOST_CHECK_EQUAL(results_["Geldschrank_Praemie"], Value_t(InstanceVariable_t{ { "1", 0 }, { "2", 5 } }));
    BOOST_CHECK_EQUAL(results_["Schmuck_Praemie"], Value_t(InstanceVariable_t{ { "1", 0 }, { "2", 150 } }));
    BOOST_CHECK_EQUAL(results_["Schmuck_unversperrrt_Praemie"], Value_t(InstanceVariable_t{ { "1", 0 }, { "2", 900 } }));
}
}

void testCalculation()
{
    std::shared_ptr<IFunctionResultCache> functionResultCache(DefaultCacheFactory::getFunctionResultCache(g_dummyVtarKey));
    std::shared_ptr<IParseTreeCache> parseTreeCache(DefaultCacheFactory::getParseTreeCache(g_dummyVtarKey));
    std::vector<std::shared_ptr<IFunction>> functions{ std::make_shared<GetProdschablFunction>(), std::make_shared<GetSachtarifFunction>(), std::make_shared<GetTarifpraemieFunction>() };

    std::unique_ptr<IRatingEngine> ratingEngine(RatingEngineFactory::createRatingEngine(functions, functionResultCache, parseTreeCache));

    IRatingEngine::Map_t input(makeInput());
    IRatingEngine::RatingFormulaMap_t ratingFormulas(makeRatingFormulas());
    std::vector<RatingOutput> ratingOutput(makeRatingOutput());

    IRatingEngine::Map_t results = ratingEngine->calculate(g_dummyVtarKey, input, ratingFormulas, ratingOutput);
    dumpResults(results);
    validateResults(results);
}

void testInstanceCalculation()
{
    std::shared_ptr<IFunctionResultCache> functionResultCache(DefaultCacheFactory::getFunctionResultCache(g_dummyVtarKey));
    std::shared_ptr<IParseTreeCache> parseTreeCache(DefaultCacheFactory::getParseTreeCache(g_dummyVtarKey));
    std::vector<std::shared_ptr<IFunction>> functions{ std::make_shared<GetProdschablFunction>(), std::make_shared<GetSachtarifFunction>(), std::make_shared<GetTarifpraemieFunction>() };

    std::unique_ptr<IRatingEngine> ratingEngine(RatingEngineFactory::createRatingEngine(functions, functionResultCache, parseTreeCache));

    IRatingEngine::Map_t input(makeInstanceInput());
    IRatingEngine::RatingFormulaMap_t ratingFormulas(makeRatingFormulas());
    std::vector<RatingOutput> ratingOutput(makeInstanceRatingOutput());

    IRatingEngine::Map_t results = ratingEngine->calculate(g_dummyVtarKey, input, ratingFormulas, ratingOutput);
    dumpResults(results);
    validateInstanceResults(results);
}

void testCalculationPerformance()
{
    DefaultCacheFactory::clear();
    std::shared_ptr<IFunctionResultCache> functionResultCache(DefaultCacheFactory::getFunctionResultCache(g_dummyVtarKey));
    std::shared_ptr<IParseTreeCache> parseTreeCache(DefaultCacheFactory::getParseTreeCache(g_dummyVtarKey));
    std::vector<std::shared_ptr<IFunction>> functions{ std::make_shared<GetProdschablFunction>(), std::make_shared<GetSachtarifFunction>(), std::make_shared<GetTarifpraemieFunction>() };

    std::unique_ptr<IRatingEngine> ratingEngine(RatingEngineFactory::createRatingEngine(functions, functionResultCache, parseTreeCache));

    IRatingEngine::Map_t input(makeInput());
    IRatingEngine::RatingFormulaMap_t ratingFormulas(makeRatingFormulas());
    std::vector<RatingOutput> ratingOutput(makeRatingOutput());

    typedef std::chrono::high_resolution_clock Clock_t;
    std::chrono::time_point<Clock_t> startTime, endTime;

    startTime = Clock_t::now();
    IRatingEngine::Map_t results = ratingEngine->calculate(g_dummyVtarKey, input, ratingFormulas, ratingOutput);
    endTime = Clock_t::now();
    std::cout << "duration first calculation: " << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count() << " microseconds\n";
    validateResults(results);

    startTime = Clock_t::now();
    results = ratingEngine->calculate(g_dummyVtarKey, input, ratingFormulas, ratingOutput);
    endTime = Clock_t::now();
    std::cout << "duration second calculation: " << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count() << " microseconds\n";
    validateResults(results);

    startTime = Clock_t::now();
    results = ratingEngine->calculate(g_dummyVtarKey, input, ratingFormulas, ratingOutput);
    endTime = Clock_t::now();
    std::cout << "duration third calculation: " << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count() << " microseconds\n";

    validateResults(results);
}

max_stars_repo_name: allianz/CalculusPrime-PnC

max_issues_repo_name: allianz/CalculusPrime-PnC

max_forks_repo_name: allianz/CalculusPrime-PnC