contract CrowdWallet is Ownable {
  using SafeMath for uint;

  struct Deposit {
    uint amount;
    uint block;
  }

  struct Payout {
    uint amount;
    uint block;
  }

  // Genesis Tokens determine the payout for each contributor.
  GenesisToken public token;

  // Track deposits/payouts by address
  mapping (address => Deposit[]) public deposits;
  mapping (address => Payout[]) public payouts;

  // Track the sum of all payouts & deposits ever made to this contract.
  uint public lifetimeDeposits;
  uint public lifetimePayouts;

  // Time between pay periods are defined as a number of blocks.
  uint public blocksPerPayPeriod = 172800; // ~30 days
  uint public previousPayoutBlock;
  uint public nextPayoutBlock;

  // The balance at the end of each period is saved here and allocated to token
  // holders from the previous period.
  uint public payoutPool;

  // For doing division. Numerator should be multiplied by this.
  uint multiplier = 10**18;

  // Set a minimum that a user must have earned in order to withdraw it.
  uint public minWithdrawalThreshold = 100000000000000000; // 0.1 ETH in wei

  // Events
  event onDeposit(address indexed _from, uint _amount);
  event onPayout(address indexed _to, uint _amount);
  event onPayoutFailure(address indexed _to, uint amount);

  /**
   * Constructor - set the GNS token address and the initial number of blocks
   * in-between each pay period.
   */
  function CrowdWallet(address _gns, address _owner, uint _blocksPerPayPeriod) {
    token = GenesisToken(_gns);
    owner = _owner;
    blocksPerPayPeriod = _blocksPerPayPeriod;
    nextPayoutBlock = now.add(blocksPerPayPeriod);
  }

  function setMinimumWithdrawal(uint _weiAmount) onlyOwner {
    minWithdrawalThreshold = _weiAmount;
  }

  function setBlocksPerPayPeriod(uint _blocksPerPayPeriod) onlyOwner {
    blocksPerPayPeriod = _blocksPerPayPeriod;
  }

  /**
   * To prevent cheating, when a withdrawal is made, the tokens for that address
   * become immediately locked until the next period. Otherwise, they could send
   * their tokens to another wallet and withdraw again.
   */
  function withdraw() {
    require(previousPayoutBlock > 0);

    // Ensure the user has not already made a withdrawal this period.
    require(!isAddressLocked(msg.sender));

    uint payoutAmount = calculatePayoutForAddress(msg.sender);

    // Ensure user's payout is above the minimum threshold for withdrawals.
    require(payoutAmount > minWithdrawalThreshold);

    // User qualifies. Save the transaction with the current block number,
    // effectively locking their tokens until the next payout date.
    payouts[msg.sender].push(Payout({ amount: payoutAmount, block: now }));

    require(this.balance >= payoutAmount);

    onPayout(msg.sender, payoutAmount);

    lifetimePayouts += payoutAmount;

    msg.sender.transfer(payoutAmount);
  }

  /**
   * Once a user gets paid out for a period, we lock up the tokens they own
   * until the next period. Otherwise, they can send their tokens to a fresh
   * address and then double dip.
   */
  function isAddressLocked(address contributor) constant returns(bool) {
    var paymentHistory = payouts[contributor];

    if (paymentHistory.length == 0) {
      return false;
    }

    var lastPayment = paymentHistory[paymentHistory.length - 1];

    return (lastPayment.block >= previousPayoutBlock) && (lastPayment.block < nextPayoutBlock);
  }

  /**
   * Check if we are in a new payout cycle.
   */
  function isNewPayoutPeriod() constant returns(bool) {
    return now >= nextPayoutBlock;
  }

  /**
   * Start a new payout cycle
   */
  function startNewPayoutPeriod() {
    require(isNewPayoutPeriod());

    previousPayoutBlock = nextPayoutBlock;
    nextPayoutBlock = nextPayoutBlock.add(blocksPerPayPeriod);
    payoutPool = this.balance;
  }

  /**
   * Determine the amount that should be paid out.
   */
  function calculatePayoutForAddress(address payee) constant returns(uint) {
    uint ownedAmount = token.balanceOf(payee);
    uint totalSupply = token.totalSupply();
    uint percentage = (ownedAmount * multiplier) / totalSupply;
    uint payout = (payoutPool * percentage) / multiplier;

    return payout;
  }

  /**
   * Check the contract's ETH balance.
   */
  function ethBalance() constant returns(uint) {
    return this.balance;
  }

  /**
   * Income should go here.
   */
  function deposit() payable {
    onDeposit(msg.sender, msg.value);
    lifetimeDeposits += msg.value;
    deposits[msg.sender].push(Deposit({ amount: msg.value, block: now }));
  }

  function () payable {
    deposit();
  }
}
/**
 * This contract holds all the revenues generated by the DAO, and pays out to
 * token holders on a periodic basis.
 */
function startNewPayoutPeriod() {
  require(isNewPayoutPeriod());

  previousPayoutBlock = nextPayoutBlock;
  nextPayoutBlock = nextPayoutBlock.add(blocksPerPayPeriod);
  payoutPool = this.balance;
}

/**
 * Start a new payout cycle
 */