contract Crowdsale is Token {

    address public backend;

    uint public stage;
    bool public started;
    uint public startTokenPriceWei;
    uint public tokensForSale;
    uint public startTime;
    uint public lastTokenPriceWei;
    uint public milliPercent; // "25" means 0.25%
    uint public paymentsCount; // restart on each stage
    bool public sealed;
    modifier notSealed {
        require(sealed == false);
        _;
    }

    event Mint(address indexed _who, uint _tokens, uint _coinType, bytes32 _txHash);
    event Stage(uint _stage, bool startNotFinish);

    function Crowdsale() public Token() {
        totalSupply = 100000000*100000000;
        holders[this].balance = totalSupply;
    }

    function startStage(uint _startTokenPriceWei, uint _tokensForSale, uint _milliPercent) public onlyOwner notSealed {
        require(!started);
        require(_startTokenPriceWei >= lastTokenPriceWei);
        startTokenPriceWei = _startTokenPriceWei;
        tokensForSale = _tokensForSale * 100000000;
        if(tokensForSale > holders[this].balance) {
            tokensForSale = holders[this].balance;
        }
        milliPercent = _milliPercent;
        startTime = now;
        started = true;
        paymentsCount = 0;
        emit Stage(stage, started);
    }
    
    function currentTokenPrice() public constant returns(uint) {
        uint price;
        if(!sealed && started) {
            uint d = (now - startTime) / 1 days;
            price = startTokenPriceWei;
            price += startTokenPriceWei * d * milliPercent / 100;
        }
        return price;
    }
    
    function stopStage() public onlyOwner notSealed {
        require(started);
        started = false;
        lastTokenPriceWei = currentTokenPrice();
        emit Stage(stage, started);
        ++stage;
    }
    
    function () payable public notSealed {
        require(started);
        uint price = currentTokenPrice();
        if(paymentsCount < 100) {
            price = price * 90 / 100;
        }
        ++paymentsCount;
        uint tokens = 100000000 * msg.value / price;
        if(tokens > tokensForSale) {
            tokens = tokensForSale;
            uint sumWei = tokens * lastTokenPriceWei / 100000000;
            require(msg.sender.call.gas(3000000).value(msg.value - sumWei)());
        }
        require(tokens > 0);
        require(holders[msg.sender].balance + tokens > holders[msg.sender].balance); // overflow
        tokensForSale -= tokens;
        beforeBalanceChanges(msg.sender);
        beforeBalanceChanges(this);
        holders[msg.sender].balance += tokens;
        holders[this].balance -= tokens;
        emit Transfer(this, msg.sender, tokens);
    }

    function mintTokens1(address _who, uint _tokens, uint _coinType, bytes32 _txHash) public notSealed {
        require(msg.sender == owner || msg.sender == backend);
        require(started);
        _tokens *= 100000000;
        if(_tokens > tokensForSale) {
            _tokens = tokensForSale;
        }
        require(_tokens > 0);
        require(holders[_who].balance + _tokens > holders[_who].balance); // overflow
        tokensForSale -= _tokens;
        beforeBalanceChanges(_who);
        beforeBalanceChanges(this);
        holders[_who].balance += _tokens;
        holders[this].balance -= _tokens;
        emit Mint(_who, _tokens, _coinType, _txHash);
        emit Transfer(this, _who, _tokens);
    }
    
    // must be called by owners only out of stage
    function mintTokens2(address _who, uint _tokens, uint _vesting) public notSealed {
        require(msg.sender == owner || msg.sender == backend);
        require(!started);
        require(_tokens > 0);
        _tokens *= 100000000;
        require(_tokens <= holders[this].balance);
        require(holders[_who].balance + _tokens > holders[_who].balance); // overflow
        if(_vesting != 0) {
            vesting[_who] = _vesting;
        }
        beforeBalanceChanges(_who);
        beforeBalanceChanges(this);
        holders[_who].balance += _tokens;
        holders[this].balance -= _tokens;
        emit Mint(_who, _tokens, 0, 0);
        emit Transfer(this, _who, _tokens);
    }

    // need to seal Crowdsale when it is finished completely
    function seal() public onlyOwner {
        sealed = true;
    }
}
function seal() public onlyOwner {
    sealed = true;
}

// need to seal Crowdsale when it is finished completely