contract SontakuToken is StandardToken, DetailedERC20, SplitPayment {
  using SafeMath for uint256;

  /**
   * Event for token purchase logging
   * @param purchaser who paid for the tokens
   * @param beneficiary who got the tokens
   * @param value weis paid for purchase
   * @param amount amount of tokens purchased
   */
  event Purchase(
    address indexed purchaser,
    address indexed beneficiary,
    uint256 value,
    uint256 amount
  );

  string constant TOKEN_NAME = "Sontaku";
  string constant TOKEN_SYMBOL = "SONTAKU";
  uint8 constant TOKEN_DECIMALS = 18;
  uint256 constant EXCHANGE_RATE = 46490;
  uint256 constant HARD_CAP = 46494649 * (uint256(10)**TOKEN_DECIMALS);
  uint256 constant MIN_PURCHASE = 4649 * (uint256(10)**(TOKEN_DECIMALS - 2));

  uint256 public exchangeRate;          // Token units per wei on purchase
  uint256 public hardCap;               // Maximum mintable tokens
  uint256 public minPurchase;           // Minimum purchase tokens
  uint256 public crowdsaleOpeningTime;  // Starting time for crowdsale
  uint256 public crowdsaleClosingTime;  // Finishing time for crowdsale
  uint256 public fundRaised;            // Amount of wei raised

  constructor(
    address[] _founders,
    uint256[] _founderShares,
    uint256 _crowdsaleOpeningTime, 
    uint256 _crowdsaleClosingTime
  )
    DetailedERC20(TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS)
    SplitPayment(_founders, _founderShares)
    public 
  {
    require(_crowdsaleOpeningTime <= _crowdsaleClosingTime);

    exchangeRate = EXCHANGE_RATE;
    hardCap = HARD_CAP;
    minPurchase = MIN_PURCHASE;
    crowdsaleOpeningTime = _crowdsaleOpeningTime;
    crowdsaleClosingTime = _crowdsaleClosingTime;

    for (uint i = 0; i < _founders.length; i++) {
      _mint(_founders[i], _founderShares[i]);
    }
  }

  // -----------------------------------------
  // Crowdsale external interface
  // -----------------------------------------

  function () public payable {
    buyTokens(msg.sender);
  }

  /**
   * @param _beneficiary Address performing the token purchase
   */
  function buyTokens(address _beneficiary) public payable {

    uint256 weiAmount = msg.value;
    uint256 tokenAmount = _getTokenAmount(weiAmount);

    _validatePurchase(_beneficiary, weiAmount, tokenAmount);
    _processPurchase(_beneficiary, weiAmount, tokenAmount);

    emit Purchase(
      msg.sender,
      _beneficiary,
      weiAmount,
      tokenAmount
    );
  }

  // -----------------------------------------
  // Internal interface (extensible)
  // -----------------------------------------

  /**
   * @param _beneficiary Address performing the token purchase
   * @param _weiAmount Value in wei involved in the purchase
   * @param _tokenAmount Number of tokens to be purchased
   */
  function _validatePurchase(
    address _beneficiary,
    uint256 _weiAmount,
    uint256 _tokenAmount
  )
    internal view
  {
    require(_beneficiary != address(0));
    require(_weiAmount != 0);
    require(_tokenAmount >= minPurchase);
    require(totalSupply_ + _tokenAmount <= hardCap);
    require(block.timestamp >= crowdsaleOpeningTime);
    require(block.timestamp <= crowdsaleClosingTime);
  }

  /**
   * @param _beneficiary Address receiving the tokens
   * @param _weiAmount Value in wei involved in the purchase
   * @param _tokenAmount Number of tokens to be purchased
   */
  function _processPurchase(
    address _beneficiary,
    uint256 _weiAmount,
    uint256 _tokenAmount
  )
    internal
  {
    _mint(_beneficiary, _tokenAmount);
    fundRaised = fundRaised.add(_weiAmount);
  }

  /**
   * @param _beneficiary Address receiving the tokens
   * @param _tokenAmount Number of tokens to be minted
   */
  function _mint(
    address _beneficiary, 
    uint256 _tokenAmount
  )
    internal
  {
    totalSupply_ = totalSupply_.add(_tokenAmount);
    balances[_beneficiary] = balances[_beneficiary].add(_tokenAmount);

    emit Transfer(address(0), _beneficiary, _tokenAmount);
  }

  /**
   * @param _weiAmount Value in wei to be converted into tokens
   * @return Number of tokens that can be purchased with the specified _weiAmount
   */
  function _getTokenAmount(uint256 _weiAmount)
    internal view returns (uint256)
  {
    return _weiAmount.mul(exchangeRate);
  }
}
/**
 * @title Sontaku token contract
 * @dev ERC20-compatible token which is mintable, capped and timed crowdsalable
 */
function buyTokens(address _beneficiary) public payable {

  uint256 weiAmount = msg.value;
  uint256 tokenAmount = _getTokenAmount(weiAmount);

  _validatePurchase(_beneficiary, weiAmount, tokenAmount);
  _processPurchase(_beneficiary, weiAmount, tokenAmount);

  emit Purchase(
    msg.sender,
    _beneficiary,
    weiAmount,
    tokenAmount
  );
}

/**
 * @param _beneficiary Address performing the token purchase
 */