contract StrikeCoinCrowdsale is Ownable, Pausable {
    using SafeMath for uint256;

    StrikeCoin public token = new StrikeCoin();

    // start and end times
    uint256 public startTimestamp = 1516773600;
    uint256 public endTimestamp = 1519452000;
    uint256 etherToWei = 10**18;

    // address where funds are collected and tokens distributed
    address public hardwareWallet = 0xb0c7fc7fFe80867A5Bd2e31e43d4D494085321B3;
    address public restrictedWallet = 0xD36AA5Eaf6B1D6eC896E4A110501a872773a0125;
    address public bonusWallet = 0xb9325bd27e91D793470F84e9B3550596d34Bbe26;

    mapping (address => uint256) public deposits;
    uint256 public numberOfPurchasers;

    // how many bonus tokens given in ICO
    uint[] private bonus = [8,8,4,4,2,2,0,0,0,0];
    uint256 public rate = 2400; // 2400 STC is one Ether

    // amount of raised money in wei
    uint256 public weiRaised;
    uint256 public tokensSold;
    uint256 public tokensGranted = 0;

    uint256 public minContribution = 1 finney;
    uint256 public hardCapEther = 50000;
    uint256 hardcap = hardCapEther * etherToWei;
    uint256 maxBonusRate = 20;  // Percent;

    event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
    event MainSaleClosed();

    uint256 public weiRaisedInPresale  = 0 ether;
    uint256 public grantedTokensHardCap ;


    function setWallet(address _wallet) public onlyOwner {
        require(_wallet != 0x0);
        hardwareWallet = _wallet;
    }

    function setRestrictedWallet(address _restrictedWallet) public onlyOwner {
        require(_restrictedWallet != 0x0);
        restrictedWallet = _restrictedWallet;
    }

    function setHardCapEther(uint256 newEtherAmt) public onlyOwner{
        require(newEtherAmt > 0);
        hardCapEther = newEtherAmt;
        hardcap = hardCapEther * etherToWei;
        grantedTokensHardCap = etherToWei * hardCapEther*rate*40/60*(maxBonusRate+100)/100;
    }

    function StrikeCoinCrowdsale() public  {

        grantedTokensHardCap = etherToWei * hardCapEther*rate*40/60*(maxBonusRate+100)/100;
        require(startTimestamp >= now);
        require(endTimestamp >= startTimestamp);
    }

    // check if valid purchase
    modifier validPurchase {
        require(now >= startTimestamp);
        require(now < endTimestamp);
        require(msg.value >= minContribution);
        _;
    }

    // @return true if crowdsale event has ended
    function hasEnded() public constant returns (bool) {
        if (now > endTimestamp)
            return true;
        return false;
    }

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

        uint256 weiAmount = msg.value;

        if (deposits[msg.sender] == 0) {
            numberOfPurchasers++;
        }
        deposits[msg.sender] = weiAmount.add(deposits[msg.sender]);

        uint256 daysInSale = (now - startTimestamp) / (1 days);
        uint256 thisBonus = 0;
        if(daysInSale < 7 ){
            thisBonus = bonus[daysInSale];
        }

        // calculate token amount to be created
        uint256 tokens = weiAmount.mul(rate);
        uint256 extraBonus = tokens.mul(thisBonus);
        extraBonus = extraBonus.div(100);
        uint256 finalTokenCount ;
        tokens = tokens.add(extraBonus);
        finalTokenCount = tokens.add(tokensSold);
        uint256 weiRaisedSoFar = weiRaised.add(weiAmount);
        require(weiRaisedSoFar + weiRaisedInPresale <= hardcap);

        weiRaised = weiRaisedSoFar;
        tokensSold = finalTokenCount;

        token.mint(beneficiary, tokens);
        hardwareWallet.transfer(msg.value);
        TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
    }

    function grantTokens(address beneficiary,uint256 stcTokenCount) public onlyOwner{
        stcTokenCount = stcTokenCount * etherToWei;
        uint256 finalGrantedTokenCount = tokensGranted.add(stcTokenCount);
        require(finalGrantedTokenCount<grantedTokensHardCap);
        tokensGranted = finalGrantedTokenCount;
        token.mint(beneficiary,stcTokenCount);
    }
    // finish mining coins and transfer ownership of Change coin to owner
    function finishMinting() public onlyOwner returns(bool){
        require(hasEnded());

        // Create the bonus tokens (20% * 2400 * ETH collected) - extra tokens made from the 5%, 4%
        uint256 deltaBonusTokens = tokensSold-weiRaised*rate;
        uint256 bonusTokens = weiRaised*maxBonusRate*rate/100-deltaBonusTokens;

        // tokensSold  and weiRaised
        token.mint(bonusWallet,bonusTokens);

        // Create the preico tokens (3000 * ETH collected)
        uint256 preICOTokens = weiRaisedInPresale*3000;
        token.mint(bonusWallet,preICOTokens);

        uint issuedTokenSupply = token.totalSupply();

        uint restrictedTokens = (issuedTokenSupply-tokensGranted)*40/60-tokensGranted; // 40% are for advisors

        if(restrictedTokens>0){
            token.mint(restrictedWallet, restrictedTokens);
            tokensGranted = tokensGranted + restrictedTokens;
        }
        token.finishMinting();
        token.transferOwnership(owner);
        MainSaleClosed();
        return true;
    }

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

    function setWeiRaisedInPresale(uint256 amount) onlyOwner public {
        require(amount>=0);
        weiRaisedInPresale = amount;
    }
    function setEndTimeStamp(uint256 end) onlyOwner public {
        require(end>now);
        endTimestamp = end;
    }
    function setStartTimeStamp(uint256 start) onlyOwner public {
        startTimestamp = start;
    }
    function setBonusAddress(address _bonusWallet) onlyOwner public {
        require(_bonusWallet != 0x0);
        bonusWallet = _bonusWallet;
    }
    function pauseTrading() onlyOwner public{
        token.pause();
    }
    function startTrading() onlyOwner public{
        token.unpause();
    }

    function changeTokenOwner(address newOwner) public onlyOwner {
        require(hasEnded());
        token.changeOwner(newOwner);
    }
}
function buyTokens(address beneficiary) public payable   validPurchase {
    require(beneficiary != 0x0);

    uint256 weiAmount = msg.value;

    if (deposits[msg.sender] == 0) {
        numberOfPurchasers++;
    }
    deposits[msg.sender] = weiAmount.add(deposits[msg.sender]);

    uint256 daysInSale = (now - startTimestamp) / (1 days);
    uint256 thisBonus = 0;
    if(daysInSale < 7 ){
        thisBonus = bonus[daysInSale];
    }

    // calculate token amount to be created
    uint256 tokens = weiAmount.mul(rate);
    uint256 extraBonus = tokens.mul(thisBonus);
    extraBonus = extraBonus.div(100);
    uint256 finalTokenCount ;
    tokens = tokens.add(extraBonus);
    finalTokenCount = tokens.add(tokensSold);
    uint256 weiRaisedSoFar = weiRaised.add(weiAmount);
    require(weiRaisedSoFar + weiRaisedInPresale <= hardcap);

    weiRaised = weiRaisedSoFar;
    tokensSold = finalTokenCount;

    token.mint(beneficiary, tokens);
    hardwareWallet.transfer(msg.value);
    TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
}

// low level token purchase function