contract Token is ERC20 {

  string public constant name = "FundYourselfNow Token";
  string public constant symbol = "FYN";
  uint8 public constant decimals = 18;  // 18 is the most common number of decimal places
  uint256 public tokenCap = 12500000e18; // 12.5 million FYN cap 

  address public walletAddress;
  uint256 public creationTime;
  bool public transferStop;
 
  mapping( address => uint ) _balances;
  mapping( address => mapping( address => uint ) ) _approvals;
  uint _supply;

  event TokenMint(address newTokenHolder, uint amountOfTokens);
  event TokenSwapOver();
  event EmergencyStopActivated();

  modifier onlyFromWallet {
      if (msg.sender != walletAddress) throw;
      _;
  }

  // Check if transfer should stop
  modifier checkTransferStop {
      if (transferStop == true) throw;
      _;
  }
 

  /**
   *
   * Fix for the ERC20 short address attack
   *
   * http://vessenes.com/the-erc20-short-address-attack-explained/
   */

  modifier onlyPayloadSize(uint size) {
     if (!(msg.data.length == size + 4)) throw;
     _;
   } 
 
  function Token( uint initial_balance, address wallet, uint256 crowdsaleTime) {
    _balances[msg.sender] = initial_balance;
    _supply = initial_balance;
    walletAddress = wallet;
    creationTime = crowdsaleTime;
    transferStop = true;
  }

  function totalSupply() constant returns (uint supply) {
    return _supply;
  }

  function balanceOf( address who ) constant returns (uint value) {
    return _balances[who];
  }

  function allowance(address owner, address spender) constant returns (uint _allowance) {
    return _approvals[owner][spender];
  }

  // A helper to notify if overflow occurs
  function safeToAdd(uint a, uint b) private constant returns (bool) {
    return (a + b >= a && a + b >= b);
  }
  
  // A helper to notify if overflow occurs for multiplication
  function safeToMultiply(uint _a, uint _b) private constant returns (bool) {
    return (_b == 0 || ((_a * _b) / _b) == _a);
  }

  // A helper to notify if underflow occurs for subtraction
  function safeToSub(uint a, uint b) private constant returns (bool) {
    return (a >= b);
  }


  function transfer( address to, uint value)
    checkTransferStop
    onlyPayloadSize(2 * 32)
    returns (bool ok) {

    if (to == walletAddress) throw; // Reject transfers to wallet (wallet cannot interact with token contract)
    if( _balances[msg.sender] < value ) {
        throw;
    }
    if( !safeToAdd(_balances[to], value) ) {
        throw;
    }

    _balances[msg.sender] -= value;
    _balances[to] += value;
    Transfer( msg.sender, to, value );
    return true;
  }

  function transferFrom( address from, address to, uint value)
    checkTransferStop
    returns (bool ok) {

    if (to == walletAddress) throw; // Reject transfers to wallet (wallet cannot interact with token contract)

    // if you don't have enough balance, throw
    if( _balances[from] < value ) {
        throw;
    }
    // if you don't have approval, throw
    if( _approvals[from][msg.sender] < value ) {
        throw;
    }
    if( !safeToAdd(_balances[to], value) ) {
        throw;
    }
    // transfer and return true
    _approvals[from][msg.sender] -= value;
    _balances[from] -= value;
    _balances[to] += value;
    Transfer( from, to, value );
    return true;
  }

  function approve(address spender, uint value)
    checkTransferStop
    returns (bool ok) {

    // To change the approve amount you first have to reduce the addresses`
    //  allowance to zero by calling `approve(_spender,0)` if it is not
    //  already 0 to mitigate the race condition described here:
    //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    //
    // Note that this doesn't prevent attacks; the user will have to personally
    //  check to ensure that the token count has not changed, before issuing
    //  a new approval. Increment/decrement is not commonly spec-ed, and 
    //  changing to a check-my-approvals-before-changing would require user
    //  to find out his current approval for spender and change expected
    //  behaviour for ERC20.


    if ((value!=0) && (_approvals[msg.sender][spender] !=0)) throw;

    _approvals[msg.sender][spender] = value;
    Approval( msg.sender, spender, value );
    return true;
  }

  // The function currentSwapRate() returns the current exchange rate
  // between FYN tokens and Ether during the token swap period
  function currentSwapRate() constant returns(uint) {
      uint presalePeriod = 3 days;
      uint presaleTransitionWindow = 3 hours;
      if (creationTime + presalePeriod > now) {  // 2017-06-10 11am GMT+8
          return 140; // Presale Window is triggered by both time and "Start Token Swap / End Token Swap". Restricted to announement range and basic testing.
      } 
      else if (creationTime + presalePeriod + 3 weeks > now) { // 2017-06-13 11am GMT+8, but we will only Start Token Swap at 2pm
          return 120;
      }
      else if (creationTime + presalePeriod + 6 weeks + 6 days + 3 hours + presaleTransitionWindow + 1 days > now) { // 2017-07-31 5pm GMT+8 (+1 day window  )
          // 1 day buffer to allow one final transaction from anyone to close everything
          // otherwise wallet will receive ether but send 0 tokens
          // we cannot throw as we will lose the state change to start swappability of tokens 
          // This is actually just a price guide, actual closing is done at the Wallet level
          return 100;
      }
      else {
          return 0;
      }
  }

  // The function mintTokens is only usable by the chosen wallet
  // contract to mint a number of tokens proportional to the
  // amount of ether sent to the wallet contract. The function
  // can only be called during the tokenswap period
  function mintTokens(address newTokenHolder, uint etherAmount)
    external
    onlyFromWallet {
        if (!safeToMultiply(currentSwapRate(), etherAmount)) throw;
        uint tokensAmount = currentSwapRate() * etherAmount;

        if(!safeToAdd(_balances[newTokenHolder],tokensAmount )) throw;
        if(!safeToAdd(_supply,tokensAmount)) throw;

        if ((_supply + tokensAmount) > tokenCap) throw;

        _balances[newTokenHolder] += tokensAmount;
        _supply += tokensAmount;

        TokenMint(newTokenHolder, tokensAmount);
  }

  function mintReserve(address beneficiary) 
    external
    onlyFromWallet {
        if (tokenCap <= _supply) throw;
        if(!safeToSub(tokenCap,_supply)) throw;
        uint tokensAmount = tokenCap - _supply;

        if(!safeToAdd(_balances[beneficiary], tokensAmount )) throw;
        if(!safeToAdd(_supply,tokensAmount)) throw;

        _balances[beneficiary] += tokensAmount;
        _supply += tokensAmount;
        
        TokenMint(beneficiary, tokensAmount);
  }

  // The function disableTokenSwapLock() is called by the wallet
  // contract once the token swap has reached its end conditions
  function disableTokenSwapLock()
    external
    onlyFromWallet {
        transferStop = false;
        TokenSwapOver();
  }

  // Once activated, a new token contract will need to be created, mirroring the current token holdings. 
  function stopToken() onlyFromWallet {
    transferStop = true;
    EmergencyStopActivated();
  }
}
function safeToSub(uint a, uint b) private constant returns (bool) {
  return (a >= b);
}

// A helper to notify if underflow occurs for subtraction