contract Crowdsale is Ownable {
  using SafeMath for uint256;
  // soft cap
  uint256 public softcap;
  // balances for softcap
  mapping(address => uint) public balancesSoftCap;
  struct BuyInfo {
    uint summEth;
    uint summToken;
    uint dateEndRefund;
  }
  mapping(address => mapping(uint => BuyInfo)) public payments;
  mapping(address => uint) public paymentCounter;
  // The token being offered
  Wolf public token;
  // start and end timestamps where investments are allowed (both inclusive)
  // start
  uint256 public startICO;
  // end
  uint256 public endICO;
  uint256 public period;
  uint256 public endICO14; 
  // token distribution
  uint256 public hardCap;
  uint256 public totalICO;
  // how many token units a Contributor gets per wei
  uint256 public rate;   
  // address where funds are collected
  address public wallet;
  // minimum/maximum quantity values
  uint256 public minNumbPerSubscr; 
  uint256 public maxNumbPerSubscr; 

/**
* event for token Procurement logging
* @param contributor who Pledged for the tokens
* @param beneficiary who got the tokens
* @param value weis Contributed for Procurement
* @param amount amount of tokens Procured
*/
  event TokenProcurement(address indexed contributor, address indexed beneficiary, uint256 value, uint256 amount);
  function Crowdsale() public {
    token = createTokenContract();
    // soft cap
    softcap = 100 * 1 ether;   
    // minimum quantity values
    minNumbPerSubscr = 10000000000000000; //0.01 eth
    maxNumbPerSubscr = 100 * 1 ether;
    // start and end timestamps where investments are allowed
    // start
    startICO = 1521878400;// 03/24/2018 @ 8:00am (UTC)
    period = 30;
    // end
    endICO = startICO + period * 1 days;
    endICO14 = endICO + 14 * 1 days;
    // restrictions on amounts during the crowdfunding event stages
    hardCap = 65000000000 * 1 ether;
    // rate;
    rate = 1000000;
    // address where funds are collected
    wallet = 0x7472106A07EbAB5a202e195c0dC22776778b44E6;
  }

  function setStartICO(uint _startICO) public onlyOwner{
    startICO = _startICO;
    endICO = startICO + period * 1 days;
    endICO14 = endICO + 14 * 1 days;    
  }

  function setPeriod(uint _period) public onlyOwner{
    period = _period;
    endICO = startICO + period * 1 days;
    endICO14 = endICO + 14 * 1 days;    
  }
  
  function setRate(uint _rate) public  onlyOwner{
    rate = _rate;
  }
  
  function createTokenContract() internal returns (Wolf) {
    return new Wolf();
  }

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

  // low level token Pledge function
  function procureTokens(address beneficiary) public payable {
    uint256 tokens;
    uint256 weiAmount = msg.value;
    uint256 backAmount;
    require(beneficiary != address(0));
    //minimum/maximum amount in ETH
    require(weiAmount >= minNumbPerSubscr && weiAmount <= maxNumbPerSubscr);
    if (now >= startICO && now <= endICO && totalICO < hardCap){
      tokens = weiAmount.mul(rate);
      if (hardCap.sub(totalICO) < tokens){
        tokens = hardCap.sub(totalICO); 
        weiAmount = tokens.div(rate);
        backAmount = msg.value.sub(weiAmount);
      }
      totalICO = totalICO.add(tokens);
    }

    require(tokens > 0);
    token.mint(beneficiary, tokens);
    balancesSoftCap[beneficiary] = balancesSoftCap[beneficiary].add(weiAmount);

    uint256 dateEndRefund = now + 14 * 1 days;
    paymentCounter[beneficiary] = paymentCounter[beneficiary] + 1;
    payments[beneficiary][paymentCounter[beneficiary]] = BuyInfo(weiAmount, tokens, dateEndRefund); 
    
    if (backAmount > 0){
      msg.sender.transfer(backAmount);  
    }
    emit TokenProcurement(msg.sender, beneficiary, weiAmount, tokens);
  }

 
  function refund() public{
    require(address(this).balance < softcap && now > endICO);
    require(balancesSoftCap[msg.sender] > 0);
    uint value = balancesSoftCap[msg.sender];
    balancesSoftCap[msg.sender] = 0;
    msg.sender.transfer(value);
  }
  
  function revoke(uint _id) public{
    require(now <= payments[msg.sender][_id].dateEndRefund);
    require(payments[msg.sender][_id].summEth > 0);
    require(payments[msg.sender][_id].summToken > 0);
    uint value = payments[msg.sender][_id].summEth;
    uint valueToken = payments[msg.sender][_id].summToken;
    balancesSoftCap[msg.sender] = balancesSoftCap[msg.sender].sub(value);
    payments[msg.sender][_id].summEth = 0;
    payments[msg.sender][_id].summToken = 0;
    msg.sender.transfer(value);
    token.burn(msg.sender, valueToken);
   }  
  
  function transferToMultisig() public onlyOwner {
    require(address(this).balance >= softcap && now > endICO14);  
      wallet.transfer(address(this).balance);
  }  
}
/**
 * @title Crowdsale
 * @dev Crowdsale is a base contract for managing a token crowdsale.
 * Crowdsales have a start and end timestamps, where Contributors can make
 * token Contributions and the crowdsale will assign them tokens based
 * on a token per ETH rate. Funds collected are forwarded to a wallet
 * as they arrive. The contract requires a MintableToken that will be
 * minted as contributions arrive, note that the crowdsale contract
 * must be owner of the token in order to be able to mint it.
 */
function procureTokens(address beneficiary) public payable {
    uint256 tokens;
    uint256 weiAmount = msg.value;
    uint256 backAmount;
    require(beneficiary != address(0));
    //minimum/maximum amount in ETH
    require(weiAmount >= minNumbPerSubscr && weiAmount <= maxNumbPerSubscr);
    if (now >= startICO && now <= endICO && totalICO < hardCap){
      tokens = weiAmount.mul(rate);
      if (hardCap.sub(totalICO) < tokens){
        tokens = hardCap.sub(totalICO); 
        weiAmount = tokens.div(rate);
        backAmount = msg.value.sub(weiAmount);
      }
      totalICO = totalICO.add(tokens);
    }

    require(tokens > 0);
    token.mint(beneficiary, tokens);
    balancesSoftCap[beneficiary] = balancesSoftCap[beneficiary].add(weiAmount);

    uint256 dateEndRefund = now + 14 * 1 days;
    paymentCounter[beneficiary] = paymentCounter[beneficiary] + 1;
    payments[beneficiary][paymentCounter[beneficiary]] = BuyInfo(weiAmount, tokens, dateEndRefund); 
    
    if (backAmount > 0){
      msg.sender.transfer(backAmount);  
    }
    emit TokenProcurement(msg.sender, beneficiary, weiAmount, tokens);
  }
// low level token Pledge function