/* eslint-env mocha */
/* global artifacts */

const HttpProvider = require('ethjs-provider-http');
const EthRPC = require('ethjs-rpc');
const abi = require('ethereumjs-abi');

const ethRPC = new EthRPC(new HttpProvider('http://localhost:8545'));

const Token = artifacts.require('./HumanStandardToken.sol');
const PLCRVoting = artifacts.require('./PLCRVoting.sol');
const Registry = artifacts.require('./Registry.sol');
const Sale = artifacts.require('historical/Sale.sol');

let registry;
let token;

const utils = {
  getVoting: async () => {
    const votingAddr = await registry.voting.call();
    return PLCRVoting.at(votingAddr);
  },
  increaseTime: async seconds =>
    new Promise((resolve, reject) => ethRPC.sendAsync({
      method: 'evm_increaseTime',
      params: [seconds],
    }, (err) => {
      if (err) reject(err);
      resolve();
    }))
      .then(() => new Promise((resolve, reject) => ethRPC.sendAsync({
        method: 'evm_mine',
        params: [],
      }, (err) => {
        if (err) reject(err);
        resolve();
      }))),
  getVoteSaltHash: (vote, salt) => (
    `0x${abi.soliditySHA3(['uint', 'uint'], [vote, salt]).toString('hex')}`
  ),
  getDomainHash: domain => (
    `0x${abi.soliditySHA3(['string'], [domain]).toString('hex')}`
  ),
  buyTokens: async (address, etherAmount) => {
    const sale = await Sale.deployed();
    await sale.purchaseTokens({ from: address, value: etherAmount });
  },
  approvePLCR: async (address, adtAmount) => {
    const plcrAddr = await registry.voting.call();
    await token.approve(plcrAddr, adtAmount, { from: address });
  },
  setupForTests: async (accounts) => {
    async function buyTokensFor(addresses) {
      await utils.buyTokens(addresses[0], '1000000000000000000');
      if (addresses.length === 1) { return true; }
      return buyTokensFor(addresses.slice(1));
    }

    async function approveRegistryFor(addresses) {
      const user = addresses[0];
      const balanceOfUser = await token.balanceOf(user);
      await token.approve(registry.address, balanceOfUser, { from: user });
      if (addresses.length === 1) { return true; }
      return approveRegistryFor(addresses.slice(1));
    }

    async function approvePLCRFor(addresses) {
      const user = addresses[0];
      const balanceOfUser = await token.balanceOf(user);
      await utils.approvePLCR(user, balanceOfUser);
      if (addresses.length === 1) { return true; }
      return approvePLCRFor(addresses.slice(1));
    }
    registry = await Registry.deployed();
    token = Token.at(await registry.token.call());

    const [applicant, challenger, voter] = accounts.slice(1);

    await buyTokensFor(accounts.slice(1));
    await approveRegistryFor(accounts.slice(1));
    await approvePLCRFor(accounts.slice(1));

    return [registry, token, applicant, challenger, voter];
  },
};

module.exports = utils;

@@ -168,16 +168,42 @@
 s-abi');
+%0Aconst fs = require('fs');
 %0A%0Aconst 
@@ -496,16 +496,142 @@
 sol');%0A%0A
+const adchainConfig = JSON.parse(fs.readFileSync('./conf/config.json'));%0Aconst paramConfig = adchainConfig.RegistryDefaults;%0A%0A
 let regi
@@ -2991,16 +2991,1122 @@
 %5D;%0A  %7D,%0A
+  addToWhitelist: async (domain, deposit, actor) =%3E %7B%0A    await utils.as(actor, registry.apply, domain, deposit);%0A    await utils.increaseTime(paramConfig.applyStageLength + 1);%0A    await utils.as(actor, registry.updateStatus, domain);%0A  %7D,%0A  as: (actor, fn, ...args) =%3E %7B%0A    function detectSendObject(potentialSendObj) %7B%0A      function hasOwnProperty(obj, prop) %7B%0A        const proto = obj.constructor.prototype;%0A        return (prop in obj) &&%0A          (!(prop in proto) %7C%7C proto%5Bprop%5D !== obj%5Bprop%5D);%0A      %7D%0A      if (typeof potentialSendObj !== 'object') %7B return undefined; %7D%0A      if (%0A        hasOwnProperty(potentialSendObj, 'from') %7C%7C%0A        hasOwnProperty(potentialSendObj, 'to') %7C%7C%0A        hasOwnProperty(potentialSendObj, 'gas') %7C%7C%0A        hasOwnProperty(potentialSendObj, 'gasPrice') %7C%7C%0A        hasOwnProperty(potentialSendObj, 'value')%0A      ) %7B%0A        throw new Error('It is unsafe to use %22as%22 with custom send objects');%0A      %7D%0A      return undefined;%0A    %7D%0A    detectSendObject(args%5Bargs.length - 1%5D);%0A    const sendObject = %7B from: actor %7D;%0A    return fn(...args, sendObject);%0A  %7D,%0A
 %7D;%0A%0Amodu

add addToWhiteList util func.