contract BTN is VestedToken {
  //FIELDS
  string public name = "BETNetwork";
  string public symbol = "BTN";
  uint public decimals = 4;

  uint public constant STAGE_PRESALE_ETHRaised = 3500*1 ether; // Stage 1 Ether 10000
  uint public constant STAGE_TWO_ETHRaised = 8500*1 ether; //  Stage 2 Ether 10000
  uint public constant STAGE_THREE_ETHRaised = 14000*1 ether;
  uint public constant STAGE_FOUR_ETHRaised = 20000*1 ether;
  
  // Multiplier for the decimals
  uint private constant DECIMALS = 10000;

  //Prices of BTN
  uint public constant PRICE_STANDARD    = 3128*DECIMALS; // BTN received per one ETH; MAX_SUPPLY / (valuation / ethPrice)
  uint public constant PRICE_STAGE_PRESALE   = PRICE_STANDARD * 140/100; // 1ETH = 40% more BTN
  uint public constant PRICE_STAGE_TWO   = PRICE_STANDARD * 125/100; // 1ETH = 25% more BTN
  uint public constant PRICE_STAGE_THREE = PRICE_STANDARD * 115/100; // 1ETH = 15% more BTN
  uint public constant PRICE_STAGE_FOUR = PRICE_STANDARD * 105/100; // 1ETH = 5% more BTN
  
  //BTN Token Limits
  uint public constant ALLOC_TEAM =         22500000*DECIMALS; // team
  uint public constant ALLOC_RES =         22500000*DECIMALS; // Reserve
  uint public constant ALLOC_CROWDSALE =    105000000*DECIMALS;
  
  //ASSIGNED IN INITIALIZATION
  //Start and end times
  uint public publicStartTime; // Time in seconds public crowd sale starts.
  uint public publicEndTime; // Time in seconds BTN crowdsale ends
  uint public hardcapInEth=30000* 1 ether;

  //Special Addresses
  address public multisigAddress=0x2DD016668BD409B7E1988dFddC08388e448f1E90; // Address to which all ether fund flows.
  address public BETNetworkTeamAddress=0xdCE5999988a40AF0f9E6b73EAF9D5a1DC01a24E9; // Address to which teams funds transferred.
  address public ownerAddress; // Address of the contract owner. Can halt the crowdsale.


  //Running totals
  uint public etherRaised; // Total Ether raised.
  uint public BTNSold; // Total BTN created
  
  //booleans
  bool public halted; // halts the crowd sale if true.

  // MODIFIERS
  //Is currently in the period after the private start time and before the public start time.
  modifier is_pre_crowdfund_period() {
    if (now >= publicStartTime ) throw;
    _;
  }

  //Is currently the crowdfund period
  modifier is_crowdfund_period() {
    if (now < publicStartTime) throw;
    if (isCrowdfundCompleted()) throw;
    _;
  }

  // Is completed
  modifier is_crowdfund_completed() {
    if (!isCrowdfundCompleted()) throw;
    _;
  }
  function isCrowdfundCompleted() internal returns (bool) {
    if (now > publicEndTime || BTNSold >= ALLOC_CROWDSALE || etherRaised >= hardcapInEth) return true;
    return false;
  }

  //May only be called by the owner address
  modifier only_owner() {
    if (msg.sender != ownerAddress) throw;
    _;
  }

  //May only be called if the crowdfund has not been halted
  modifier is_not_halted() {
    if (halted) throw;
    _;
  }

  // EVENTS
  event Buy(address indexed _recipient, uint _amount);

  // Initialization contract assigns address of crowdfund contract and end time.
  function BTN() {
    ownerAddress = msg.sender;
    publicStartTime = now;
    publicEndTime = now + 6 weeks;
    balances[BETNetworkTeamAddress] += ALLOC_TEAM;
    balances[ownerAddress] += ALLOC_RES;
    balances[ownerAddress] += ALLOC_CROWDSALE;
  }

  // Transfer amount of tokens from sender account to recipient.
  // Only callable after the crowd fund is completed
  function transfer(address _to, uint _value)
  {
    if (_to == msg.sender) return; // no-op, allow even during crowdsale, in order to work around using grantVestedTokens() while in crowdsale
    if (!isCrowdfundCompleted()) throw;
    super.transfer(_to, _value);
  }

  // Transfer amount of tokens from a specified address to a recipient.
  // Transfer amount of tokens from sender account to recipient.
  function transferFrom(address _from, address _to, uint _value)
    is_crowdfund_completed
  {
    super.transferFrom(_from, _to, _value);
  }

  //constant function returns the current BTN price.
  function getPriceRate()
      constant
      returns (uint o_rate)
  {
      uint delta = etherRaised;
      if (delta < STAGE_PRESALE_ETHRaised) return PRICE_STAGE_PRESALE;
      if (delta < STAGE_TWO_ETHRaised) return PRICE_STAGE_TWO;
      if (delta < STAGE_THREE_ETHRaised) return PRICE_STAGE_THREE;
       if (delta < STAGE_FOUR_ETHRaised) return PRICE_STAGE_FOUR;
      return (PRICE_STANDARD);
  }

  // calculates wmount of BTN we get, given the wei and the rates we've defined per 1 eth
  function calcAmount(uint _wei, uint _rate) 
    constant
    returns (uint) 
  {
    return SafeMath.div(SafeMath.mul(_wei, _rate), 1 ether);
  } 
  
  // Given the rate of a purchase and the remaining tokens in this tranche, it
  // will throw if the sale would take it past the limit of the tranche.
  // Returns `amount` in scope as the number of BTN tokens that it will purchase.
  function processPurchase(uint _rate, uint _remaining)
    internal
    returns (uint o_amount)
  {
    o_amount = calcAmount(msg.value, _rate);

    if (o_amount > _remaining) throw;
    if (!multisigAddress.send(msg.value)) throw;

    balances[ownerAddress] = balances[ownerAddress].sub(o_amount);
    balances[msg.sender] = balances[msg.sender].add(o_amount);

    BTNSold += o_amount;
    etherRaised += msg.value;
  }

  //Default function called by sending Ether to this address with no arguments.
  //Results in creation of new BTN Tokens if transaction would not exceed hard limit of ADX Token.
  function()
    payable
    is_crowdfund_period
    is_not_halted
  {
    uint amount = processPurchase(getPriceRate(), SafeMath.sub(ALLOC_CROWDSALE, BTNSold));
    Buy(msg.sender, amount);
  }

  // To be called at the end of crowdfund period
  // WARNING: transfer(), which is called by grantVestedTokens(), wants a minimum message length
  function grantVested(address _BETNetworkTeamAddress, address _BETNetworkFundAddress)
    is_crowdfund_completed
    only_owner
    is_not_halted
  {
    // Grant tokens pre-allocated for the team
    grantVestedTokens(
      _BETNetworkTeamAddress, ALLOC_TEAM,
      uint64(now), uint64(now) + 91 days , uint64(now) + 365 days, 
      false, false
    );

    // Grant tokens that remain after crowdsale to the BETNetwork fund, vested for 2 years
    grantVestedTokens(
      _BETNetworkFundAddress, balances[ownerAddress],
      uint64(now), uint64(now) + 182 days , uint64(now) + 730 days, 
      false, false
    );
  }

  //May be used by owner of contract to halt crowdsale and no longer except ether.
  function toggleHalt(bool _halted)
    only_owner
  {
    halted = _halted;
  }

  //failsafe drain
  function drain()
    only_owner
  {
    if (!ownerAddress.send(this.balance)) throw;
  }
}
// - Considering we inherit from VestedToken, how much does that hit at our gas price?
// - Ensure max supply is 150,000,000
// - Ensure that even if not totalSupply is sold, tokens would still be transferrable after.
// vesting: 365 days, 365 days / 4 vesting
function grantVested(address _BETNetworkTeamAddress, address _BETNetworkFundAddress)
  is_crowdfund_completed
  only_owner
  is_not_halted
{
  // Grant tokens pre-allocated for the team
  grantVestedTokens(
    _BETNetworkTeamAddress, ALLOC_TEAM,
    uint64(now), uint64(now) + 91 days , uint64(now) + 365 days, 
    false, false
  );

  // Grant tokens that remain after crowdsale to the BETNetwork fund, vested for 2 years
  grantVestedTokens(
    _BETNetworkFundAddress, balances[ownerAddress],
    uint64(now), uint64(now) + 182 days , uint64(now) + 730 days, 
    false, false
  );
}

// To be called at the end of crowdfund period
// WARNING: transfer(), which is called by grantVestedTokens(), wants a minimum message length