contract XFM is VestedToken {

  string public name = "XferMoney";
  string public symbol = "XFM";
  uint public decimals = 4;
 
  //Special Addresses
  address public multisigAddress=0x749BD34C771456a8DE28Aa0883b00d11273E2Ede; // Address to which all ether fund receive.
  address public XferMoneyTeamAddress=0xc179FCbdEef2DA2A61Ed9b1817942d72B0a46c8a; // Address to which team tokens are reserved.
  address public XferMoneyMarketing=0x9EED63b353Af69cFbDC0e15A1b037429f0780D1c; // Address to which Marketing tokens are reserved.
  address public ownerAddress; // Address of the contract owner. Can halt the crowdsale.

  //Crowdsale Time
  uint public constant publicStartTime=now; // Time in seconds when public Presale starts.
  uint public constant PRESALE_START_WEEK1=1516406401; // Time in seconds when Presale Weel 1 starts.
  uint public constant PRESALE_START_WEEK2=1517011201; // Time in seconds when Presale Week 2 starts.
  uint public constant PRESALE_START_WEEK3=1517616001; // Time in seconds when Presale Week 3 starts.
  uint public constant CROWDSALE_START=1518652801; // Time in seconds when Public Crowdsale starts.
  uint public publicEndTime=1522540799; // Time in seconds XFM crowdsale ends
  
  // Multiplier for the decimals
  uint private constant DECIMALS = 10000;

  //Prices of XFM
  uint public constant PRICE_CROWDSALE    = 8000*DECIMALS; // XFM Price per one ETH during crowdsale; 
  uint public constant PRICE_PRESALE_START   = PRICE_CROWDSALE * 140/100; // Price with 40% Bonus XFM
  uint public constant PRICE_PRESALE_WEEK1   = PRICE_CROWDSALE * 125/100; //  Price with 25% Bonus XFM
  uint public constant PRICE_PRESALE_WEEK2 = PRICE_CROWDSALE * 118/100; //   Price with 18% Bonus XFM
  uint public constant PRICE_PRESALE_WEEK3 = PRICE_CROWDSALE * 110/100; //   Price with 10% Bonus XFM
  
  //Assigned XFM Tokens 
  uint256 public constant _initialSupply=  250000000*DECIMALS; // Total tokens assigned initially 
  uint public constant ALLOC_TEAM =         62500000*DECIMALS; // Token reserved for team
  uint public constant ALLOC_CROWDSALE =    175000000*DECIMALS; // Allocated for Crowdsale(Phase 1 + Phase 2) 
  uint public constant ALLOC_MARKETING =    12500000*DECIMALS; // Allocated for Marketing, Bonties 
  
  //Running totals
  uint public etherRaised; // Total Ether raised.
  uint public XFMSold; // Total XFM sold
  uint public hardcapInEth=25000* 1 ether;
  uint256 public totalSupply = _initialSupply;
  
  //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 && XFMSold >= ALLOC_CROWDSALE) return true; // Crowdsale can also be halted by the owner.
    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.
  function XFM() {
    ownerAddress = msg.sender;
    balances[XferMoneyTeamAddress] += ALLOC_TEAM;
    balances[XferMoneyMarketing] += ALLOC_MARKETING;
    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 XFM price.
  function getPriceRate()
      constant
      returns (uint o_rate)
  {
      uint delta = now;
      if (delta < PRESALE_START_WEEK1) return PRICE_PRESALE_START;
      if (delta < PRESALE_START_WEEK2) return PRICE_PRESALE_WEEK1;
      if (delta < PRESALE_START_WEEK3) return PRICE_PRESALE_WEEK2;
      if (delta < CROWDSALE_START) return PRICE_PRESALE_WEEK3;
      return (PRICE_CROWDSALE);
  }

  // calculates amount of XFM we get, given the wei and the rates defined per 1 eth
  function calcAmount(uint _wei, uint _rate) 
    constant
    returns (uint) 
  {
    return SafeMath.div(SafeMath.mul(_wei, _rate), 1 ether);
  } 
  
  // Returns `amount` in scope as the number of XFM 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);

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

  //Default function called by sending Ether to this address with no arguments.
  //Results in creation of new XFM Tokens if transaction would not exceed hard limit of XFM Token.
  function() payable is_crowdfund_period    is_not_halted
  {
    uint amount = processPurchase(getPriceRate(), SafeMath.sub(ALLOC_CROWDSALE, XFMSold));
    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 _XferMoneyTeamAddress, address _XferMoneyFundAddress)
    is_crowdfund_completed
    only_owner
    is_not_halted
  {
    // Grant tokens pre-allocated for the team
    grantVestedTokens(
      _XferMoneyTeamAddress, ALLOC_TEAM,
      uint64(now), uint64(now) + 91 days , uint64(now) + 365 days, 
      false, false
    );

    // Grant tokens that remain after crowdsale to the XferMoney fund, vested for 2 years
    grantVestedTokens(
      _XferMoneyFundAddress, 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;
  }
}
// vesting: 365 days, 365 days / 4 vesting
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);

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

// Returns `amount` in scope as the number of XFM tokens that it will purchase.