contract Crowdsale is Pausable {
    using SafeMath for uint256;

    string public projectName;

    string public tokenName;
    string public tokenSymbol;

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

    // amount of raised money in wei, decimals is 5
    uint256 public ethRaised;
    uint256 public eth_decimal_num = 100000;

    // cap of money in wei
    uint256 public cap;

    // The token being sold
    TokenImpl public token;

    // the target token
    ERC20Basic public targetToken;

    /**
     * event for token purchase logging
     * @param purchaser who paid for the tokens
     * @param beneficiary who got the tokens
     * @param value weis paid for purchase
     */
    event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value);
    event IncreaseCap(uint256 cap);
    event DecreaseCap(uint256 cap);


    function Crowdsale(string _projectName, string _tokenName, string _tokenSymbol, uint256 _cap) public {
        require(_cap > 0);
        projectName = _projectName;
        tokenName = _tokenName;
        tokenSymbol = _tokenSymbol;
        cap = _cap.mul(eth_decimal_num);
        token = createTokenContract();
    }

    function newCrowdSale(string _projectName, string _tokenName,
        string _tokenSymbol, uint256 _cap) onlyOwner public {
        require(_cap > 0);
        projectName = _projectName;
        tokenName = _tokenName;
        tokenSymbol = _tokenSymbol;
        cap = _cap.mul(eth_decimal_num);
        ethRaised = 0;
        token.transferOwnership(owner);
        token = createTokenContract();
        rate = 0;
        targetToken = ERC20Basic(0);
    }


    function createTokenContract() internal returns (TokenImpl) {
        return new TokenImpl(tokenName, tokenSymbol, eth_decimal_num);
    }

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

    // low level token purchase function
    function buyTokens(address beneficiary) whenNotPaused public payable {
        require(beneficiary != address(0));
        require(msg.value >= (0.00001 ether));

        uint256 ethAmount = (msg.value.mul(eth_decimal_num)).div(1 ether);

        // update state
        ethRaised = ethRaised.add(ethAmount);
        require(ethRaised <= cap);

        token.mint(beneficiary, ethAmount);
        TokenPurchase(msg.sender, beneficiary, ethAmount);

        forwardFunds();
    }

    // send ether to the fund collection wallet
    // override to create custom fund forwarding mechanisms
    function forwardFunds() internal {
        owner.transfer(msg.value);
    }

    // increase the amount of eth
    function increaseCap(uint256 _cap_inc) onlyOwner public {
        require(_cap_inc > 0);
        cap = cap.add(_cap_inc.mul(eth_decimal_num));
        IncreaseCap(cap);
    }

    function decreaseCap(uint256 _cap_dec) onlyOwner public {
        require(_cap_dec > 0);
        cap = cap.sub(_cap_dec.mul(eth_decimal_num));
        if (cap <= ethRaised) {
            cap = ethRaised;
        }
        DecreaseCap(cap);
    }

    function saleRatio() public view returns (uint256 ratio) {
        if (cap == 0) {
            return 0;
        } else {
            return ethRaised.mul(10000).div(cap);
        }
    }


    function balanceOf(address _owner) public view returns (uint256 balance) {
        return token.balanceOf(_owner);
    }

    function balanceOfTarget(address _owner) public view returns (uint256 targetBalance) {
        return token.balanceOfTarget(_owner);
    }

    function canExchangeNum() public view returns (uint256) {
        return token.canExchangeNum();
    }

    function updateTargetToken(address _target, uint256 _rate) onlyOwner public {
        rate = _rate;
        targetToken = ERC20Basic(_target);
        token.updateTargetToken(_target, _rate);
    }

    /**
     * @dev called by the owner to transfer the target token to owner from this contact
     */
    function releaseTargetToken(uint256 _value) onlyOwner public returns (bool) {
        if (targetToken != address(0)) {
            return targetToken.transfer(owner, _value);
        } else {
            return false;
        }
    }


    /**
     * @dev called by the owner to pause, triggers stopped state
     */
    function pauseToken() onlyOwner public {
        token.pause();
    }

    /**
     * @dev called by the owner to unpause, returns to normal state
     */
    function unpauseToken() onlyOwner public {
        token.unpause();
    }


    // @return true if crowdsale event has ended
    function hasEnded() public view returns (bool) {
        return ethRaised >= cap;
    }

}
function hasEnded() public view returns (bool) {
    return ethRaised >= cap;
}

// @return true if crowdsale event has ended