contract Crowdsale is Ownable {
    
    using SafeMath for uint;
    uint256 public startTimeRound1;
    uint256 public endTimeRound1;

    uint256 public startTimeRound2;
    uint256 public endTimeRound2;

    // one token per one rate
    uint256 public rateRound1 = 1200;
    uint256 public rateRound2 = 900;

    uint256 constant dec = 10 ** 8;
    uint256 public supply = 50000000 * 10 ** 8;
    uint256 public percentTokensToSale = 60;
    uint256 public tokensToSale = supply.mul(percentTokensToSale).div(100);
    // address where funds are collected
    address public wallet;

    AlttexToken public token;
    // Amount of raised money in wei
    uint256 public weiRaised = 21678 * 10 ** 16; // 216.78 ETH
    uint256 public minTokensToSale = 45 * dec;
    // Company addresses
    address public TeamAndAdvisors;
    address public Investors;

    uint256 timeBonus1 = 20;
    uint256 timeBonus2 = 10;

    // Round bonuses
    uint256 bonus1 = 10;
    uint256 bonus2 = 15;
    uint256 bonus3 = 20;
    uint256 bonus4 = 30;

    // Amount bonuses
    uint256 amount1 = 500 * dec;
    uint256 amount2 = 1000 * dec;
    uint256 amount3 = 5000 * dec;
    uint256 amount4 = 10000 * dec;

    bool initalMinted = false;
    bool initialWeiRaised = false;
    bool checkBonus = false;

    function Crowdsale(
        address _token,
        uint256 _startTimeRound1, // 1520121600 - 03/04/2018 @ 12:00am (UTC)
        uint256 _startTimeRound2, // 1521417600 - 03/19/2018 @ 12:00am (UTC)
        uint256 _endTimeRound1, // 1521417600 - 03/19/2018 @ 12:00am (UTC)
        uint256 _endTimeRound2, // 1525305600 - 05/03/2018 @ 12:00am (UTC)
        address _wallet,
        address _TeamAndAdvisors,
        address _Investors) public {
        require(_token != address(0));
        require(_endTimeRound1 > _startTimeRound1);
        require(_endTimeRound2 > _startTimeRound2);
        require(_wallet != address(0));
        require(_TeamAndAdvisors != address(0));
        require(_Investors != address(0));
        token = AlttexToken(_token);
        startTimeRound1 = _startTimeRound1;
        startTimeRound2 = _startTimeRound2;
        endTimeRound1 = _endTimeRound1;
        endTimeRound2 = _endTimeRound2;
        wallet = _wallet;
        TeamAndAdvisors = _TeamAndAdvisors;
        Investors = _Investors;
    }

    function initialMint() onlyOwner public {
        require(!initalMinted);
        uint256 _initialRaised = 17472 * 10 ** 16;
        uint256 _tokens = _initialRaised.mul(1500).div(10 ** 10);
        token.mint(Investors, _tokens.add(_tokens.mul(40).div(100)));
        initalMinted = true;
    }

    function initialWeiRais(uint256 _newInitialWeiRais) onlyOwner public {
        require(!initialWeiRaised);
        weiRaised = _newInitialWeiRais;
        initialWeiRaised = true;
    }

    modifier saleIsOn() {
        uint tokenSupply = token.totalSupply();
        require(now > startTimeRound1 && now < endTimeRound2);
        require(tokenSupply <= supply);
        _;
    }

    function setPercentTokensToSale(
        uint256 _newPercentTokensToSale) onlyOwner public {
        percentTokensToSale = _newPercentTokensToSale;
    }

    function setMinTokensToSale(
        uint256 _newMinTokensToSale) onlyOwner public {
        minTokensToSale = _newMinTokensToSale;
    }

    function setCheckBonus(
        bool _newCheckBonus) onlyOwner public {
        checkBonus = _newCheckBonus;
    }

    function setAmount(
        uint256 _newAmount1,
        uint256 _newAmount2,
        uint256 _newAmount3,
        uint256 _newAmount4) onlyOwner public {
        amount1 = _newAmount1;
        amount2 = _newAmount2;
        amount3 = _newAmount3;
        amount4 = _newAmount4;
    }

    function setBonuses(
        uint256 _newBonus1,
        uint256 _newBonus2,
        uint256 _newBonus3,
        uint256 _newBonus4) onlyOwner public {
        bonus1 = _newBonus1;
        bonus2 = _newBonus2;
        bonus3 = _newBonus3;
        bonus4 = _newBonus4;
    }

    function setRoundTime(
      uint256 _newStartTimeRound2,
      uint256 _newEndTimeRound2) onlyOwner public {
      require(_newEndTimeRound2 > _newStartTimeRound2);
        startTimeRound2 = _newStartTimeRound2;
        endTimeRound2 = _newEndTimeRound2;
    }

    function setRate(uint256 _newRateRound2) public onlyOwner {
        rateRound2 = _newRateRound2;
    }

    function setTimeBonus(uint256 _newTimeBonus) public onlyOwner {
        timeBonus2 = _newTimeBonus;
    }
 
    function setTeamAddress(
        address _newTeamAndAdvisors,
        address _newInvestors,
        address _newWallet) onlyOwner public {
        require(_newTeamAndAdvisors != address(0));
        require(_newInvestors != address(0));
        require(_newWallet != address(0));
        TeamAndAdvisors = _newTeamAndAdvisors;
        Investors = _newInvestors;
        wallet = _newWallet;
    }


    function getAmount(uint256 _value) internal view returns (uint256) {
        uint256 amount = 0;
        uint256 all = 100;
        uint256 tokenSupply = token.totalSupply();
        if(now >= startTimeRound1 && now < endTimeRound1) { // Round 1
            amount = _value.mul(rateRound1);
            amount = amount.add(amount.mul(timeBonus1).div(all));
        } else if(now >= startTimeRound2 && now < endTimeRound2) { // Round 2
            amount = _value.mul(rateRound2);
            amount = amount.add(amount.mul(timeBonus2).div(all));
        } 
        require(amount >= minTokensToSale);
        require(amount != 0 && amount.add(tokenSupply) < tokensToSale);
        return amount;
    }

    function getBonus(uint256 _value) internal view returns (uint256) {
        if(_value >= amount1 && _value < amount2) { 
            return bonus1;
        } else if(_value >= amount2 && _value < amount3) {
            return bonus2;
        } else if(_value >= amount3 && _value < amount4) {
            return bonus3;
        } else if(_value >= amount4) {
            return bonus4;
        }
    }

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

    function buyTokens(address beneficiary) saleIsOn public payable {
        require(beneficiary != address(0));
        uint256 weiAmount = (msg.value).div(10 ** 10);

        // calculate token amount to be created
        uint256 tokens = getAmount(weiAmount);

        if(checkBonus) {
          uint256 bonusNow = getBonus(tokens);
          tokens = tokens.add(tokens.mul(bonusNow).div(100));
        }
        
        weiRaised = weiRaised.add(msg.value);
        uint256 taaTokens = tokens.mul(20).div(100);

        require(tokens.add(taaTokens).add(token.totalSupply()) <= tokensToSale);

        token.mint(beneficiary, tokens);
        TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
        token.mint(TeamAndAdvisors, taaTokens);
        TokenPartners(msg.sender, TeamAndAdvisors, taaTokens);
        wallet.transfer(msg.value);
        
    }

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

    // @return true if tokensale event has ended
    function hasEnded() public view returns (bool) {
        return now > endTimeRound2;
    }

    function kill() onlyOwner public { selfdestruct(owner); }
    
}
function hasEnded() public view returns (bool) {
    return now > endTimeRound2;
}

// @return true if tokensale event has ended