contract TezaCrowdsale is CappedCrowdsale, RefundableCrowdsale, AllowanceCrowdsale {

    //mapping (address => uint256) internal referrers
    mapping (address => uint256) public referrers;
    
    uint internal constant REFERRER_PERCENT = 10;
    
    modifier whenNotPaused() {
        require((block.timestamp >= openingTime && block.timestamp <= openingTime + (40 days)) || (block.timestamp >= openingTime + (80 days) && block.timestamp < closingTime));
        _;
    }

    constructor(
        uint256 _openingTime,
        uint256 _closingTime,
        uint256 _rate,
        address _wallet,
        uint256 _cap,
        StandardBurnableToken _token,
        uint256 _goal
    )
    public
    Crowdsale(_rate, _wallet, _token)
    CappedCrowdsale(_cap)
    TimedCrowdsale(_openingTime, _closingTime)
    RefundableCrowdsale(_goal)
    AllowanceCrowdsale(_wallet)
    {
        //As goal needs to be met for a successful crowdsale
        //the value needs to less or equal than a cap which is limit for accepted funds
        require(_goal <= _cap);
        require(_rate > 0);
    }
    
    function bytesToAddres(bytes source) internal pure returns(address) {
        uint result;
        uint mul = 1;
        for(uint i = 20; i > 0; i--) {
            result += uint8(source[i-1])*mul;
            mul = mul*256;
        }
        return address(result);
    }
    
    /**
     * @dev Extend parent behavior requiring beneficiary to be in whitelist.
     * @param _beneficiary Token beneficiary
     * @param _weiAmount Amount of wei contributed
     */
    function _preValidatePurchase(
        address _beneficiary,
        uint256 _weiAmount
    )
    internal
    whenNotPaused
    {
        super._preValidatePurchase(_beneficiary, _weiAmount);
        
        if(block.timestamp <= openingTime + (18 days)) {
            rate = 2000;
        }else if(block.timestamp > openingTime + (18 days) && block.timestamp <= openingTime + (37 days)) {
            rate = weiRaised <= 4000000000000000000000000 ? 1428 : 1250;
        }else if(block.timestamp >= openingTime + (77 days) && block.timestamp <= openingTime + (108 days)) {
            rate = weiRaised >= 50000000000000000000000000 ? 1000 : 1111;
        }else{
            rate = 2000;
        }
    }

    function referrerBonus(address _referrer) public view returns (uint256) {
        require(goalReached());
        return referrers[_referrer];
    }

    function _forwardFunds() internal
    {
        // referer bonus
        if(msg.data.length == 20) {
            address referrerAddress = bytesToAddres(bytes(msg.data));
            require(referrerAddress != address(token) && referrerAddress != msg.sender);
            uint256 referrerAmount = msg.value.mul(REFERRER_PERCENT).div(100);
            referrers[referrerAddress] = referrers[referrerAddress].add(referrerAmount);
        }
    }
}
// XXX There doesn't seem to be a way to split this line that keeps solium
// happy. See:
// https://github.com/duaraghav8/Solium/issues/205
// --elopio - 2018-05-10
// solium-disable-next-line max-len
function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
)
internal
whenNotPaused
{
    super._preValidatePurchase(_beneficiary, _weiAmount);
        
    if(block.timestamp <= openingTime + (18 days)) {
        rate = 2000;
    }else if(block.timestamp > openingTime + (18 days) && block.timestamp <= openingTime + (37 days)) {
        rate = weiRaised <= 4000000000000000000000000 ? 1428 : 1250;
    }else if(block.timestamp >= openingTime + (77 days) && block.timestamp <= openingTime + (108 days)) {
        rate = weiRaised >= 50000000000000000000000000 ? 1000 : 1111;
    }else{
        rate = 2000;
    }
}

/**
 * @dev Extend parent behavior requiring beneficiary to be in whitelist.
 * @param _beneficiary Token beneficiary
 * @param _weiAmount Amount of wei contributed
 */