contract Zorro02Token is ERC20Token {


    // VARIABLES ================================


    // basic token data

    string public constant name = "Zorro02";
    string public constant symbol = "ZORRO02";
    uint8 public constant decimals = 18;
    string public constant GITHUB_LINK = 'htp://github.com/..';

    // wallet address (can be reset at any time during ICO)
    
    address public wallet;

    // ICO variables that can be reset before ICO starts

    uint public tokensPerEth = 100000;
    uint public icoTokenSupply = 300;

    // ICO constants #1

    uint public constant TOTAL_TOKEN_SUPPLY = 1000;
    uint public constant ICO_TRIGGER = 10;
    uint public constant MIN_CONTRIBUTION = 10**15;
    
    // ICO constants #2 : ICO dates

    // Start - Friday, 15-Sep-17 00:00:00 UTC
    // End - Sunday, 15-Oct-17 00:00:00 UTC
    // as per http://www.unixtimestamp.com
    uint public constant START_DATE = 1502787600;
    uint public constant END_DATE = 1502791200;

    // ICO variables

    uint public icoTokensIssued = 0;
    bool public icoFinished = false;
    bool public tradeable = false;

    // Minting
    
    uint public ownerTokensMinted = 0;
    
    // other variables
    
    uint256 constant MULT_FACTOR = 10**18;
    

    // EVENTS ===================================

    
    event LogWalletUpdated(
      address newWallet
    );
    
    event LogTokensPerEthUpdated(
      uint newTokensPerEth
    );
    
    event LogIcoTokenSupplyUpdated(
      uint newIcoTokenSupply
    );
    
    event LogTokensBought(
      address indexed buyer,
      uint ethers,
      uint tokens, 
      uint participantTokenBalance, 
      uint newIcoTokensIssued
    );
    
    event LogMinting(
      address indexed participant,
      uint tokens,
      uint newOwnerTokensMinted
    );


    // FUNCTIONS ================================
    
    // --------------------------------
    // initialize
    // --------------------------------

    function Zorro02Token() {
      owner = msg.sender;
      wallet = msg.sender;
    }


    // --------------------------------
    // implement totalSupply() ERC20 function
    // --------------------------------
    
    function totalSupply() constant
      returns (uint256)
    {
      return TOTAL_TOKEN_SUPPLY;
    }


    // --------------------------------
    // changing ICO parameters
    // --------------------------------
    
    // Owner can change the crowdsale wallet address at any time
    //
    function setWallet(address _wallet) onlyOwner
    {
      wallet = _wallet;
      LogWalletUpdated(wallet);
    }
    
    // Owner can change the number of tokens per ETH before the ICO start date
    //
    function setTokensPerEth(uint _tokensPerEth) onlyOwner
    {
      require(now < START_DATE);
      require(_tokensPerEth > 0);
      tokensPerEth = _tokensPerEth;
      LogTokensPerEthUpdated(tokensPerEth);
    }
        

    // Owner can change the number available tokens for the ICO
    // (must be below 70 million) 
    //
    function setIcoTokenSupply(uint _icoTokenSupply) onlyOwner
    {
        require(now < START_DATE);
        require(_icoTokenSupply < TOTAL_TOKEN_SUPPLY);
        icoTokenSupply = _icoTokenSupply;
        LogIcoTokenSupplyUpdated(icoTokenSupply);
    }


    // --------------------------------
    // Default function
    // --------------------------------
    
    function () payable
    {
        proxyPayment(msg.sender);
    }

    // --------------------------------
    // Accept ETH during crowdsale
    // --------------------------------

    function proxyPayment(address participant) payable
    {
        require(!icoFinished);
        require(now >= START_DATE);
        require(now <= END_DATE);
        require(msg.value > MIN_CONTRIBUTION);
        
        // get number of tokens
        uint tokens = msg.value * tokensPerEth;
        
        // first check if there is enough capacity
        uint available = icoTokenSupply - icoTokensIssued;
        require (tokens <= available); 

        // ok it's possible to issue tokens so let's do it
        
        // Add tokens purchased to account's balance and total supply
        // TODO - verify SafeAdd is not necessary
        balances[participant] += tokens;
        icoTokensIssued += tokens;

        // Transfer the tokens to the participant  
        LogTransfer(0x0, participant, tokens);
        
        // Log the token purchase
        LogTokensBought(participant, msg.value, tokens, balances[participant], icoTokensIssued);

        // Transfer the contributed ethers to the crowdsale wallet
        // throw is deprecated starting from Ethereum v0.9.0
        wallet.transfer(msg.value);
    }

    
    // --------------------------------
    // Minting of tokens by owner
    // --------------------------------

    // Tokens remaining available to mint by owner
    //
    function availableToMint()
      returns (uint)
    {
      if (icoFinished) {
        return TOTAL_TOKEN_SUPPLY - icoTokensIssued - ownerTokensMinted;
      } else {
        return TOTAL_TOKEN_SUPPLY - icoTokenSupply - ownerTokensMinted;        
      }
    }

    // Minting of tokens by owner
    //    
    function mint(address participant, uint256 tokens) onlyOwner 
    {
        require( tokens <= availableToMint() );
        balances[participant] += tokens;
        ownerTokensMinted += tokens;
        LogTransfer(0x0, participant, tokens);
        LogMinting(participant, tokens, ownerTokensMinted);
    }

    // --------------------------------
    // Declare ICO finished
    // --------------------------------
    
    function declareIcoFinished() onlyOwner
    {
      // the token can only be made tradeable after ICO finishes
      require( now > END_DATE || icoTokenSupply - icoTokensIssued < ICO_TRIGGER );
      icoFinished = true;
    }

    // --------------------------------
    // Make tokens tradeable
    // --------------------------------
    
    function tradeable() onlyOwner
    {
      // the token can only be made tradeable after ICO finishes
      require(icoFinished);
      tradeable = true;
    }

    // --------------------------------
    // Transfers
    // --------------------------------

    function transfer(address _to, uint _amount) 
      returns (bool success)
    {
      // Cannot transfer out until tradeable, except for owner
      require(tradeable || msg.sender == owner);
      return super.transfer(_to, _amount);
    }

    function transferFrom(address _from, address _to, uint _amount) 
      returns (bool success)
    {
        // not possible until tradeable
        require(tradeable);
        return super.transferFrom(_from, _to, _amount);
    }

    // --------------------------------
    // Varia
    // --------------------------------

    // Transfer out any accidentally sent ERC20 tokens
    function transferAnyERC20Token(address tokenAddress, uint amount) onlyOwner 
      returns (bool success) 
    {
        return ERC20Interface(tokenAddress).transfer(owner, amount);
    }

}
// ----------------------------------------------------------------------------
//
// GZR public token sale
//
// ----------------------------------------------------------------------------
function declareIcoFinished() onlyOwner
{
  // the token can only be made tradeable after ICO finishes
  require( now > END_DATE || icoTokenSupply - icoTokensIssued < ICO_TRIGGER );
  icoFinished = true;
}

// --------------------------------
// Declare ICO finished
// --------------------------------