contract ESCCrowdsale is Ownable {
  using SafeMath for uint256;

  // The token being sold
  MintableToken public token;

  // start and end timestamps where investments are allowed (both inclusive)
  uint256 public startTime;
  uint256 public endTime;

  // address where funds are collected
  address public wallet;

  // how many token units a buyer gets per wei
  uint256 public rate;

  // amount of raised money in wei
  uint256 public weiRaised;
  
  //amount of sold money in wei
  uint256 public tokenSold = 0;
  
  uint256 public cap;

  /**
   * 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 TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);

  /**
   * event for bonuses logging
   * @param purchaser who paid for the tokens
   * @param beneficiary who got the bonus
   * @param amount amount of bonuses
   */
  event TokenBonus(address indexed purchaser, address indexed beneficiary, uint256 amount);

  bool public isFinalized = false;

  event Finalized();

  // minimum amount of funds to be raised in weis
  uint256 public goal;

  // refund vault used to hold funds while crowdsale is running
  RefundVault public vault;

  function ESCCrowdsale() {
    startTime = 1507204800;//1507204800 //5rd October 2017 12:00:00 GMT
    endTime = 1507982400; //14th October 2017 12:00:00 GMT
    rate = 250; //250ESC = 1ETH
    wallet = msg.sender;
    cap = 42550000000000000000000;
    vault = new RefundVault(wallet);
    goal = 2950000000000000000000; // Minimal goal is 2950ETH = 4400ETH - 1450ETH(funding on Waves Platform)

    token = createTokenContract();
  }

  // creates the token to be sold.
  // override this method to have crowdsale of a specific mintable token.
  function createTokenContract() internal returns (MintableToken) {
    return EstateCoin(0xAb519Ef511ee029adC74a469d1ed44955E9d5Cdf);
  }

  // fallback function can be used to buy tokens
  function () payable {
    buyTokens(msg.sender);
  }

  // low level token purchase function
  function buyTokens(address beneficiary) public payable {
    require(beneficiary != 0x0);
    require(validPurchase());

    if (weiRaised.add(msg.value) > cap) {
        throw;
    }

    uint256 weiAmount = msg.value;

    // calculate token amount to be created
    uint256 tokens = weiAmount.mul(rate);
    
    if (token.mint(beneficiary, tokens)) {
        // update state
        weiRaised = weiRaised.add(weiAmount);

        TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
    
        forwardFunds();
    
        tokenSold = tokenSold.add(tokens);
        uint256 bonus = 0;
        if (now < 1507291200) {
            bonus = tokens.div(20); //5%
        } else if (now < 1507377600) {
            bonus = tokens.div(25); //4%
        } else if (now < 1507464000) {
            bonus = tokens.div(33); //3%
        } else if (now < 1507550400) {
            bonus = tokens.div(50); //2%
        } else if (now < 1507636800) {
            bonus = tokens.div(100); //1%
        }
        
        if (bonus > 0) {
            token.mint(beneficiary, bonus);
            TokenBonus(msg.sender, beneficiary, bonus);
        }
    }
  }
    
  //manually transfer tokens
  function transferTokens(address _to, uint256 _amount) onlyOwner public returns (bool) {
    require(!isFinalized);
    require(!hasEnded());
    require(_to != 0x0);
    require(_amount > 0);
    
    token.mint(_to, _amount);
    tokenSold += _amount;
    
    return true;
  }

  // send ether to the fund collection wallet
  // In addition to sending the funds, we want to call
  // the RefundVault deposit function
  function forwardFunds() internal {
    vault.deposit.value(msg.value)(msg.sender);
  }

  // @return true if the transaction can buy tokens
  // @return true if investors can buy at the moment
  function validPurchase() internal constant returns (bool) {
    bool withinPeriod = now >= startTime && now <= endTime;
    bool nonZeroPurchase = msg.value != 0;
    return withinPeriod && nonZeroPurchase;
  }

  // @return true if crowdsale event has ended
  function hasEnded() public constant returns (bool) {
    bool capReached = weiRaised >= cap;
    return (now > endTime) || capReached;
  }
    
  /**
   * @dev Must be called after crowdsale ends, to do some extra finalization
   * work. Calls the contract's finalization function.
   */
  function finalize() onlyOwner public {
    require(!isFinalized);
    require(hasEnded());

    finalization();
    Finalized();

    isFinalized = true;
  }
  
  // if crowdsale is unsuccessful, investors can claim refunds here
  function claimRefund() public {
    require(isFinalized);
    require(!goalReached());

    vault.refund(msg.sender);
  }

  // vault finalization task, called when owner calls finalize()
  function finalization() internal {
    if (goalReached()) {
      token.mint(wallet, tokenSold.div(10)); //10% for owners, bounty, promo...
      vault.close();
    } else {
      vault.enableRefunds();
    }
  }

  function goalReached() public constant returns (bool) {
    return weiRaised >= goal;
  }

}
/**
 * @title ESCCrowdsale
 */
function buyTokens(address beneficiary) public payable {
  require(beneficiary != 0x0);
  require(validPurchase());

  if (weiRaised.add(msg.value) > cap) {
      throw;
  }

  uint256 weiAmount = msg.value;

  // calculate token amount to be created
  uint256 tokens = weiAmount.mul(rate);
    
  if (token.mint(beneficiary, tokens)) {
      // update state
      weiRaised = weiRaised.add(weiAmount);

      TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
    
      forwardFunds();
    
      tokenSold = tokenSold.add(tokens);
      uint256 bonus = 0;
      if (now < 1507291200) {
          bonus = tokens.div(20); //5%
      } else if (now < 1507377600) {
          bonus = tokens.div(25); //4%
      } else if (now < 1507464000) {
          bonus = tokens.div(33); //3%
      } else if (now < 1507550400) {
          bonus = tokens.div(50); //2%
      } else if (now < 1507636800) {
          bonus = tokens.div(100); //1%
      }
        
      if (bonus > 0) {
          token.mint(beneficiary, bonus);
          TokenBonus(msg.sender, beneficiary, bonus);
      }
  }
}

// low level token purchase function