text: import { rpc } from '../lib/rpc';
  import { generateTx } from '../lib/transaction';
  import { functionToData, dataToParams, paramsToToken, hexToDecimal } from '../lib/convert';
  import { IcoMachineAddress, CreateTokenFunc, CreateSaleFunc } from '../lib/contract';
  import { ERC223Funcs, TransferTokensFunc, CrowdSaleFuncs } from '../lib/contract';
  import { RegistryAddress, RegisterFunc } from '../lib/contract';
  import { TokensFunc, TokenIndex, BalanceOfFunc } from '../lib/contract';
  
  const initialTx = {
      to: IcoMachineAddress,
      value: 0,
      gasLimit: null,
      gasPrice: null,
      nonce: null,
      data: '0x',
  };
  
  
  export function loadOwnTokens(address) {
      return (dispatch, getState) => {
          const data = functionToData(TokenIndex, { '': address });
          return rpc.call("eth_call", [{ 
              to: IcoMachineAddress,
              data: data,
          }, "latest"]).then((result) => {
              const idx = hexToDecimal(result);
              for (let i=0; i<idx; i++) {
                  dispatch(fetchOwnToken(address, i))
              }
          })
      }
  }
  
  
  export function fetchOwnToken(address, index) {
      return (dispatch) => {
          const data = functionToData(TokensFunc, { 'address': address, 'index': index });
          return rpc.call("eth_call", [{ 
              to: IcoMachineAddress,
              data: data,
          }, "latest"]).then((result) => {
              const params = dataToParams(TokensFunc, result);
              let outputs = paramsToToken(params);
              console.log(outputs);
              if(outputs.tokenAddress==="0x00")
                  return;
              outputs.owner = address;
              dispatch({
                  type: 'TOKEN/LOAD',
                  index,
                  token: outputs,
              })
          })
      }
  }    
  
  export function loadCustomToken(address) {
      return (dispatch) => {
          let data;
          for (const c of ERC223Funcs) {
              data = functionToData(c, {});
              rpc.call("eth_call", [{
                  to: address,
                  data: data,
              }, "latest"]).then((result) => {
                  const params = dataToParams(c, result);
                  const outputs = paramsToToken(params);
                  dispatch({
                      type: 'TOKEN/CUSTOM_TOKEN',
                      name: c.get('name'),
                      value: outputs[""],
                      address,
                  });
              })
          }
      }
  }
  
  export function loadCrowdSale(address) {
      return (dispatch) => {
          let data;
          for (const c of CrowdSaleFuncs) {
              data = functionToData(c, {});
              rpc.call("eth_call", [{
                  to: address,
                  data: data,
              }, "latest"]).then((result) => {
                  const params = dataToParams(c, result);
                  const outputs = paramsToToken(params);
                  dispatch({
                      type: 'TOKEN/ICO_INFO',
                      name: c.get('name'),
                      value: outputs[""],
                  });
              })
          }
      }
  }
  
  export function estimateTokenGas(token, wallet) {
      return (dispatch) => {
          const data = functionToData(CreateTokenFunc, 
              { initialSupply: token.totalSupply || 0, 
              tokenName: token.token || "TokenMint", 
              decimals: token.decimals || 8,
              symbol: token.symbol || "TOKN" });
          return rpc.call("eth_estimateGas", [{
              from: wallet.getAddressString(),
              to: IcoMachineAddress,
              data: data,
          }]).then((result) => {
              console.log(result);
              return result;
          }).catch((error) => {
              console.error(error);
              return null;
          });
      }
  }
  
  export function estimateIcoGas(ico, wallet) {
      const addr =  wallet.getAddressString();
      return (dispatch) => {
          const data = functionToData(CreateSaleFunc, 
              { fundingGoal: ico.fundingGoal,
                  costOfEachToken: ico.price,
                  premine: ico.premine || 0,
                  index: ico.index || 0});
          return rpc.call("eth_estimateGas", [{
              from: addr,
              to: IcoMachineAddress,
              data: data,
          }, "latest"]).then((result) => {
              console.log(result);
              return result;
          }).catch((error) => {
              console.error(error);
              return null;
          });
      }
  }
  
  export function estimateRegisterGas(token, wallet) {
      const addr =  wallet.getAddressString();
      return (dispatch) => {
          const data = functionToData(RegisterFunc, 
              { _tAddr: token.address || "",
               _tSale: token.crowdsale || "",
               _tName: token.name || "",
               _tSymbol: token.symbol || "",
               _tDecimal: token.decimal || 8,
               _tType: token.type || "ERC20",
               _tIcon: token.icon || "",
               _tURL: token.url || "",
               _tBlerb: token.blerb || "" });
          return rpc.call("eth_estimateGas", [{
              from: addr,
              to: RegistryAddress,
              data: data,
          }]).then((result) => {
              console.log(result);
              return result;
          }).catch((error) => {
              console.error(error);
              return null;
          });
      }
  }
  
  export function generateTokenTransaction(token, wallet) {
      const addr = wallet.getAddressString();
      const data = functionToData(CreateTokenFunc, 
              { initialSupply: token.totalSupply || 0, 
              tokenName: token.token || "TokenMint", 
              decimals: token.decimals || 8,
              symbol: token.symbol || "TOKN"});
      const tx = Object.assign(initialTx, { 
          gasLimit: token.gasLimit,
          data: data,
          from: addr });
      return (dispatch, getState) => {
          const transaction = getState().transaction;
          if (!transaction.get('busy')) {
              tx.gasPrice = transaction.get('data').get('gasPrice');
              tx.nonce = transaction.get('data').get('nonce');
          }
          return generateTx(tx, wallet.getPrivateKey()).then((result) => {
              dispatch({
                  type: 'TRANSACTION/GENERATE',
                  raw: result.rawTx,
                  signed: result.signedTx,
              });
              return result;
          });
      }
  }
  
  export function generateIcoTransaction(ico, wallet) {
      const addr = wallet.getAddressString();
      const data = functionToData(CreateSaleFunc, 
              { fundingGoal: ico.fundingGoal,
                  costOfEachToken: ico.price,
                  premine: ico.premine || 0,
                  index: ico.index || 0});                
      const tx = Object.assign(initialTx, { 
          gasLimit: ico.gasLimit,
          data: data,
          from: addr });
      return (dispatch, getState) => {
          const transaction = getState().transaction;
          if (!transaction.get('busy')) {
              tx.gasPrice = transaction.get('data').get('gasPrice');
              tx.nonce = transaction.get('data').get('nonce');
          }
          return generateTx(tx, wallet.getPrivateKey()).then((result) => {
              dispatch({
                  type: 'TRANSACTION/GENERATE',
                  raw: result.rawTx,
                  signed: result.signedTx,
              });
              return result;
          });
      }
  }
  
  export function generateRegisterTransaction(token, wallet) {
      const addr = wallet.getAddressString();
          const data = functionToData(RegisterFunc, 
              { _tAddr: token.address || "",
               _tSale: token.crowdsale || "",
               _tName: token.name || "",
               _tSymbol: token.symbol || "",
               _tDecimal: token.decimal || 8,
               _tType: token.type || "ERC20",
               _tIcon: token.icon || "",
               _tURL: token.url || "",
               _tBlerb: token.blerb || "" });
      const tx = Object.assign(initialTx, { 
          gasLimit: token.gasLimit,
          data: data,
          from: addr });
      return (dispatch, getState) => {
          const transaction = getState().transaction;
          if (!transaction.get('busy')) {
              tx.gasPrice = transaction.get('data').get('gasPrice');
              tx.nonce = transaction.get('data').get('nonce');
          }
          return generateTx(tx, wallet.getPrivateKey()).then((result) => {
              dispatch({
                  type: 'TRANSACTION/GENERATE',
                  raw: result.rawTx,
                  signed: result.signedTx,
              });
              return result;
          });
      }
  }
  
  // Buy tokens is the equivalent of sending money to contract address
  export function generateBuyIco(data, wallet) {
      const addr = wallet.getAddressString();
      const tx = {
          to: data.to, 
          gasLimit: data.gasLimit,
          data: "",
          value: data.value,
          from: addr };
      return (dispatch, getState) => {
          const transaction = getState().transaction;
          if (!transaction.get('busy')) {
              tx.gasPrice = transaction.get('data').get('gasPrice');
              tx.nonce = transaction.get('data').get('nonce');
          }
          return generateTx(tx, wallet.getPrivateKey()).then((result) => {
              dispatch({
                  type: 'TRANSACTION/GENERATE',
                  raw: result.rawTx,
                  signed: result.signedTx,
              });
              return result;
          });
      }
  }
  
  export function generateSendTokenTransaction(tokenAddress, send, wallet) {
      const addr = wallet.getAddressString();
      const data = functionToData(TransferTokensFunc, 
              { _to: send.to, 
              _value: send.value });
      const tx = Object.assign(initialTx, { 
          gasLimit: send.gasLimit,
          data: data,
          from: addr });
      return (dispatch, getState) => {
          const transaction = getState().transaction;
          if (!transaction.get('busy')) {
              tx.gasPrice = transaction.get('data').get('gasPrice');
              tx.nonce = transaction.get('data').get('nonce');
          }
          return generateTx(tx, wallet.getPrivateKey()).then((result) => {
              dispatch({
                  type: 'TRANSACTION/GENERATE',
                  raw: result.rawTx,
                  signed: result.signedTx,
              });
              return result;
          });
      }
  }
  
  export function getBalanceOf(token, address) {
      return (dispatch) => {
          const data = functionToData(BalanceOfFunc, { '_owner': address });
          return rpc.call("eth_call", [{ 
              to: token.address,
              data: data,
          }, "latest"]).then((result) => {
              const params = dataToParams(BalanceOfFunc, result);
              const outputs = paramsToToken(params);
              dispatch({
                  type: 'WALLET/TOKEN_BALANCE',
                  symbol: token.symbol,
                  balance: outputs.balance
              });
          })
      }
  }
  
  export function createToken(token) {
      return (dispatch) => {
          dispatch({
              type: 'TOKEN/LOAD', 
              token,
          });
      }
  }
  
  
  export function createIco(ico) {
      return (dispatch) => {
          dispatch({
              type: 'TOKEN/ICO', 
              ico,
          });
      }
  }
  