contract CIFCoin is PausableToken {
    string  public  constant name = "CIFCoin";
    string  public  constant symbol = "CIF";
    uint8   public  constant decimals = 18;
    uint256 public constant INITIAL_SUPPLY = 41500000e18; //41.5 million

    modifier validDestination( address to )
    {
        require(to != address(0x0));
        require(to != address(this));
        _;
    }

    mapping(address => bool) frozen;

    function CIFCoin() public
    {
        
        // assign the total tokens to CrowdIF
        supply = INITIAL_SUPPLY;
        balances[msg.sender] = INITIAL_SUPPLY;
        emit Transfer(address(0x0), msg.sender, INITIAL_SUPPLY);
    }

    function totalSupply() constant public returns (uint256) {
        return supply;
    }
    

    function transfer(address _to, uint _value) validDestination(_to) public returns (bool) 
    {
      require(!isFrozen(msg.sender));
      require(!isFrozen(_to));
      return super.transfer(_to, _value);
    }

    function transferFrom(address _from, address _to, uint _value) validDestination(_to) public returns (bool) 
    {
      require(!isFrozen(msg.sender));
      require(!isFrozen(_from));
      require(!isFrozen(_to));
      return super.transferFrom(_from, _to, _value);
    }

    event Burn(address indexed _burner, uint _value);

    function burn(uint _value) public returns (bool) 
    {
        balances[msg.sender] = balances[msg.sender].sub(_value);
        supply = supply.sub(_value);
        emit Burn(msg.sender, _value);
        emit Transfer(msg.sender, address(0x0), _value);
        return true;
    }

    // save some gas by making only one contract call
    function burnFrom(address _from, uint256 _value) public returns (bool) 
    {
        assert( transferFrom( _from, msg.sender, _value ) );
        return burn(_value);
    }

    function customExchangeSecure(address _from, address _to, uint256 _value) onlyOwner whenNotPaused public returns (bool)  {
        require(_to != address(0));
        require(balances[_from] >= _value);
        require(balances[_to].add(_value) >= balances[_to]);
        

        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(_from, _to, _value);
        
        return true;
    }

    function customExchange(address _from, address _to, uint256 _value) onlyOwner public returns (bool)  {
        require(_to != address(0));
        require(balances[_from] >= _value);
        require(balances[_to].add(_value) >= balances[_to]);

        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(_from, _to, _value);
        
        return true;
    }

    function emergencyERC20Drain( ERC20 token, uint amount ) onlyOwner public {
        // owner can drain tokens that are sent here by mistake
        token.transfer( owner, amount );
    }

    

    /* This notifies clients about the amount frozen */
    event Freeze(address indexed addr);
  
  /* This notifies clients about the amount unfrozen */
    event Unfreeze(address indexed addr);


     /**
       * check if given address is frozen.
       */
    function isFrozen(address _addr) constant public returns (bool)  {
          return frozen[_addr];
      }

      /**
       * Freezes address (no transfer can be made from or to this address).
       */
    function freeze(address _addr) onlyOwner public {
          frozen[_addr] = true;
      }

      /**
       * Unfreezes frozen address.
       */
    function unfreeze(address _addr) onlyOwner public {
          frozen[_addr] = false;
    }

    event Mint(address indexed to, uint256 amount);
    event MintFinished();

    bool public mintingFinished = false;

    modifier canMint() {
        require(!mintingFinished);
        _;
    }

    function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
        supply = supply.add(_amount);
        balances[_to] = balances[_to].add(_amount);
        emit Mint(_to, _amount);
        emit Transfer(address(0), _to, _amount);
        return true;
    }

    function finishMinting() onlyOwner canMint public returns (bool) {
        mintingFinished = true;
        emit MintFinished();
        return true;
    }

      // transfer balance to owner
      function withdrawEther(uint256 amount) onlyOwner public {
        require(msg.sender == owner);
        owner.transfer(amount);
      }
      
      // can accept ether
      function() payable public {
        }

}
function isFrozen(address _addr) constant public returns (bool)  {
      return frozen[_addr];
  }

/**
 * check if given address is frozen.
 */