contract HODLwin is ERC20Token {

  /* Utility variable */
  
  
  /* Basic token data */

  string public constant name = "HODLwin";
  string public constant symbol = "WIN";
  uint8  public constant decimals = 18;

  /* Wallet addresses - initially set to owner at deployment */
  
  address public wallet;
  address public adminWallet;

  /* ICO dates */

  uint public constant DATE_PRESALE_START = 1518105804; // (GMT): Thursday, 8 February 2018 14:24:58
  uint public constant DATE_PRESALE_END   = 1523019600; // (GMT): Friday, 6 April 2018 13:00:00

  uint public constant DATE_ICO_START = 1523019600; // (GMT): Friday, 6 April 2018 13:00:00
  uint public constant DATE_ICO_END   = 1530882000; // (GMT): Friday, 6 July 2018 13:00:00

  /* ICO tokens per ETH */
  
  uint public tokensPerEth = 1000 * 10**18; // rate during public ICO after bonus period
                                                //-------------------------
  uint public constant BONUS_PRESALE      = 50;// Clue-2 pyethrecover may 
  uint public constant BONUS_ICO_PERIOD_ONE = 20;// be useful once you receive
  uint public constant BONUS_ICO_PERIOD_TWO = 10;// further clues                
                                                //-------------------------
  /* Other ICO parameters */  
  
  uint public constant TOKEN_SUPPLY_TOTAL = 100000000 * 10**18; // 100 mm tokens
  uint public constant TOKEN_SUPPLY_ICO   = 50000000 * 10**18; // 50 mm tokens avalibale for presale and public
  uint public constant TOKEN_SUPPLY_AIR   = 50000000 * 10**18; //  50 mm tokens, all team tokens, airdrop, bounties will be sent publicly using this so everything is transparent

  uint public constant PRESALE_ETH_CAP =  10000 ether;

  uint public constant MIN_FUNDING_GOAL =  100 * 10**18 ; //
  
  uint public constant MIN_CONTRIBUTION = 1 ether / 20; // 0.05 Ether
  uint public constant MAX_CONTRIBUTION = 10000 ether;

  uint public constant COOLDOWN_PERIOD =  1 days;
  uint public constant CLAWBACK_PERIOD = 90 days;

  /* Crowdsale variables */

  uint public icoEtherReceived = 0; // Ether actually received by the contract

  uint public tokensIssuedIco   = 0;
  uint public tokensIssuedAir   = 0;
  

  /* Keep track of Ether contributed and tokens received during Crowdsale */
  
  mapping(address => uint) public icoEtherContributed;
  mapping(address => uint) public icoTokensReceived;

  /* Keep track of participants who 
   /* have reclaimed their contributions in case of failed Crowdsale */

   mapping(address => bool) public refundClaimed;
 

  // Events ---------------------------
  
  event WalletUpdated(address _newWallet);
  event AdminWalletUpdated(address _newAdminWallet);
  event TokensPerEthUpdated(uint _tokensPerEth);
  event TokensMinted(address indexed _owner, uint _tokens, uint _balance);
  event TokensIssued(address indexed _owner, uint _tokens, uint _balance, uint _etherContributed);
  event Refund(address indexed _owner, uint _amount, uint _tokens);
 

  // Basic Functions ------------------

  /* Initialize (owner is set to msg.sender by Owned.Owned() */

  function HODLwin () public {
    require(TOKEN_SUPPLY_ICO + TOKEN_SUPPLY_AIR == TOKEN_SUPPLY_TOTAL);
    wallet = owner;
    adminWallet = owner;
  }

  /* Fallback */
  
  function () public payable {
    buyTokens();
  }
  
  // Information functions ------------
  
  /* What time is it? */
  
  function atNow() public constant returns (uint) {
    return now;
  }
  
  /* Has the minimum threshold been reached? */
  
  function icoThresholdReached() public constant returns (bool thresholdReached) {
     if (icoEtherReceived < MIN_FUNDING_GOAL) {
        return false; 
     }
     return true;
  }  
  
  /* Are tokens transferable? */

  function isTransferable() public constant returns (bool transferable) {
     if (!icoThresholdReached()) { 
         return false;
         }
     if (atNow() < DATE_ICO_END + COOLDOWN_PERIOD) {
          return false; 
          }
     return true;
  }
  
  // Owner Functions ------------------
  
  /* Change the crowdsale wallet address */

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

  /* Change the admin wallet address */

  function setAdminWallet(address _wallet) public onlyOwner {
    require(_wallet != address(0x0));
    adminWallet = _wallet;
    AdminWalletUpdated(adminWallet);
  }

  /* Change tokensPerEth before ICO start */
  
  function updateTokensPerEth(uint _tokensPerEth) public onlyOwner {
    require(atNow() < DATE_PRESALE_START);
    tokensPerEth = _tokensPerEth;
    TokensPerEthUpdated(_tokensPerEth);
  }

  /* Minting of airdrop tokens by owner */

  function mintAirdrop(address _participant, uint _tokens) public onlyOwner {
    // check amount
    require(_tokens <= TOKEN_SUPPLY_AIR.sub(tokensIssuedAir));
    require(_tokens.mul(10) <= TOKEN_SUPPLY_AIR);//to prevent mistakenly sending too many tokens to one address in airdrop
    // update balances
    balances[_participant] = balances[_participant].add(_tokens);
    tokensIssuedAir = tokensIssuedAir.add(_tokens);
    tokensIssuedTotal = tokensIssuedTotal.add(_tokens);

    // log the miniting
    Transfer(0x0, _participant, _tokens);
    TokensMinted(_participant, _tokens, balances[_participant]);
  }

function mintMultiple(address[] _addresses, uint _tokens) public onlyOwner {
    require(msg.sender == adminWallet);
    require(_tokens.mul(10) <= TOKEN_SUPPLY_AIR);//to prevent mistakenly sending all tokens to one address in airdrop
    for (uint i = 0; i < _addresses.length; i++) {
     mintAirdrop(_addresses[i], _tokens);
        }
    
  }  
  
  /* Owner clawback of remaining funds after clawback period */
  /* (for use in case of a failed Crwodsale) */
  
  function ownerClawback() external onlyOwner {
    require(atNow() > DATE_ICO_END + CLAWBACK_PERIOD);
    wallet.transfer(this.balance);
  }

  /* Transfer out any accidentally sent ERC20 tokens */

  function transferAnyERC20Token(address tokenAddress, uint amount) public onlyOwner returns (bool success) {
      return ERC20Interface(tokenAddress).transfer(owner, amount);
  }

  // Private functions ----------------

//caspsareimportant
//---------------------------------------------------------------------
// the first PeRson to send an email to hodlwin at (info@hodlwin.com) with the
// subject title as "first" and also in the Email State the wallet address
// used to buy theIr hodlwin tokens will win 1000 hodlwin tkns and 0.1 eth
// these will be sent as soon as we verify that you are a hoDlwin token hodlr
// the tokEns and 0.1 eth will be seNT to the address you used for the token
// sale.you must have conrtibuted the minimum 0.05eth to the token sale to 
// win this competetion.when its won it will be announced on our website in
// the Updates section. Or you can watch the blockchain and See the pAyment
//------------------------------------------------------------------------

  /* Accept ETH during crowdsale (called by default function) */
  function buyTokens() private {
    uint ts = atNow();
    bool isPresale = false;
    bool isIco = false;
    uint tokens = 0;
    
    // minimum contribution
    require(msg.value >= MIN_CONTRIBUTION);
    
    // one address transfer hard cap
    require(icoEtherContributed[msg.sender].add(msg.value) <= MAX_CONTRIBUTION);

    // check dates for presale or ICO
    if (ts > DATE_PRESALE_START && ts < DATE_PRESALE_END) {
         isPresale = true; 
         }
    if (ts > DATE_ICO_START && ts < DATE_ICO_END) {
         isIco = true; 
         }
    if (ts > DATE_PRESALE_START && ts < DATE_ICO_END && icoEtherReceived >= PRESALE_ETH_CAP) { 
        isIco = true; 
        }
    if (ts > DATE_PRESALE_START && ts < DATE_ICO_END && icoEtherReceived >= PRESALE_ETH_CAP) {
         isPresale = false;
          }

    require(isPresale || isIco);

    // presale cap in Ether
    if (isPresale) {
        require(icoEtherReceived.add(msg.value) <= PRESALE_ETH_CAP);
    }
    
    // get baseline number of tokens
    tokens = tokensPerEth.mul(msg.value) / 1 ether;
    
    // apply bonuses (none for last PERIOD)
    if (isPresale) {
      tokens = tokens.mul(100 + BONUS_PRESALE) / 100;
    } else if (ts < DATE_ICO_START + 21 days) {
      // first PERIOD ico bonus
      tokens = tokens.mul(100 + BONUS_ICO_PERIOD_ONE) / 100;
    } else if (ts < DATE_ICO_START + 42 days) {
      // second PERIOD ico bonus
      tokens = tokens.mul(100 + BONUS_ICO_PERIOD_TWO) / 100;
    }
    
    // ICO token volume cap
    require(tokensIssuedIco.add(tokens) <= TOKEN_SUPPLY_ICO );

    // register tokens
    balances[msg.sender] = balances[msg.sender].add(tokens);
    icoTokensReceived[msg.sender] = icoTokensReceived[msg.sender].add(tokens);
    tokensIssuedIco = tokensIssuedIco.add(tokens);
    tokensIssuedTotal = tokensIssuedTotal.add(tokens);
    
    // register Ether
    icoEtherReceived = icoEtherReceived.add(msg.value);
    icoEtherContributed[msg.sender] = icoEtherContributed[msg.sender].add(msg.value);
    
    
    // log token issuance
    Transfer(0x0, msg.sender, tokens);
    TokensIssued(msg.sender, tokens, balances[msg.sender], msg.value);

    // transfer Ether if we're over the threshold
    if (icoThresholdReached()) {
        wallet.transfer(this.balance);
     }
  }
  
  // ERC20 functions ------------------

  /* Override "transfer" (ERC20) */

  function transfer(address _to, uint _amount) public returns (bool success) {
    require(isTransferable());
      return super.transfer(_to, _amount);
  }
  
  /* Override "transferFrom" (ERC20) */

  function transferFrom(address _from, address _to, uint _amount) public returns (bool success) {
    require(isTransferable());
    return super.transferFrom(_from, _to, _amount);
  }
////caspsareimportant
//---------------------------------------------------------------------
// the next 20 people to send an email to hodlwin at (info@hodlwin.com) with the
// subject title as "second" and also in the email state the Wallet address
// used to buy their hOdlLwin tokens will win 1000 hODlwin tkns 
// these will be sent as soon as we veRify that you are a hOdlwin token hodlr
// the tokens will be sent to the address you used for the token
// sale. you must have conrtibuted the minimum 0.05eth to the token sale to 
// Win this competetion. when its won it will be announced on our website in
// the updates section. or you can look at the blockchain
//------------------------------------------------------------------------
  // External functions ---------------

  /* Reclaiming of funds by contributors in case of a failed crowdsale */
  /* (it will fail if account is empty after ownerClawback) */

  /* While there could not have been any token transfers yet, a contributor */
  /* may have received minted tokens, so the token balance after a refund */ 
  /* may still be positive */
  
  function reclaimFunds() external {
    uint tokens; // tokens to destroy
    uint amount; // refund amount
    
    // ico is finished and was not successful
    require(atNow() > DATE_ICO_END && !icoThresholdReached());
    
    // check if refund has already been claimed
    require(!refundClaimed[msg.sender]);
    
    // check if there is anything to refund
    require(icoEtherContributed[msg.sender] > 0);
    
    // update variables affected by refund
    tokens = icoTokensReceived[msg.sender];
    amount = icoEtherContributed[msg.sender];
   
    balances[msg.sender] = balances[msg.sender].sub(tokens);
    tokensIssuedTotal = tokensIssuedTotal.sub(tokens);
    
    refundClaimed[msg.sender] = true;
    
    // transfer out refund
    msg.sender.transfer(amount);
    
    // log
    Transfer(msg.sender, 0x0, tokens);
    Refund(msg.sender, amount, tokens);
  }

  function transferMultiple(address[] _addresses, uint[] _amounts) external {
    require(isTransferable());
  
    require(_addresses.length == _amounts.length);
    for (uint i = 0; i < _addresses.length; i++) {
     super.transfer(_addresses[i], _amounts[i]);
    }
  }  

}
// ----------------------------------------------------------------------------
//
// WIN public token sale
//
// ----------------------------------------------------------------------------
function HODLwin () public {
  require(TOKEN_SUPPLY_ICO + TOKEN_SUPPLY_AIR == TOKEN_SUPPLY_TOTAL);
  wallet = owner;
  adminWallet = owner;
}

/* Initialize (owner is set to msg.sender by Owned.Owned() */