pragma solidity ^0.4.24;


contract Ownable {
    address public owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
   constructor() public {
        owner = msg.sender;
		}

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
		}

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0));
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
		}

}

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
		}
    uint256 c = a * b;
    assert(c / a == b);
    return c;
	}

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
	}

  /**
  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
	}

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
	}
}

interface tokenRecipient {
    function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external;
	}

contract DigiWill is Ownable {
    using SafeMath for uint256;

    string public name = "Digiwill";
    uint8 public decimals = 18;
    string public symbol = "DGW";
    uint public totalSupply;
	bool public enabledTokenTransfer = false;

    mapping (address => uint256) public balances;
    mapping (address => mapping (address => uint256)) public allowed;
	
	mapping (address => bool) public allowedToTransfer;
	mapping (address => bool) public blockedAddress;

///////////
// Constructor
///////////

    // @notice Constructor to create a DigiWillToken
       constructor() public {
        totalSupply = 2000000000 * 10**18;
        balances[msg.sender] = totalSupply;
        allowedToTransfer[msg.sender] = true;
		}


/////////////
// ERC20 Methods
/////////////

    // @notice Send `_amount` tokens to `_to` from `msg.sender`
    // @param _to The address of the recipient
    // @param _amount The amount of tokens to be transferred
    // @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _amount) public returns (bool success) {
        doTransfer(msg.sender, _to, _amount);
        return true;
		}

    // @notice Send `_amount` tokens to `_to` from `_from` on the condition it
    //  is approved by `_from`
    // @param _from The address holding the tokens being transferred
    // @param _to The address of the recipient
    // @param _amount The amount of tokens to be transferred
    // @return True if the transfer was successful
    function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) {
        // The standard ERC 20 transferFrom functionality
        require(allowed[_from][msg.sender] >= _amount);
        allowed[_from][msg.sender] -= _amount;
        doTransfer(_from, _to, _amount);
        return true;
		}

    // @dev This is the actual transfer function in the token contract, it can
    //  only be called by other functions in this contract.
    // @param _from The address holding the tokens being transferred
    // @param _to The address of the recipient
    // @param _amount The amount of tokens to be transferred
    // @return True if the transfer was successful
    function doTransfer(address _from, address _to, uint _amount) internal {
        // Do not allow transfer to 0x0 or the token contract itself
		
        require((_to != 0) && (_to != address(this)));
        require(_amount <= balances[_from]);
		require(enabledTokenTransfer == true || allowedToTransfer[_from] == true);
		
		require(!blockedAddress[_from] || blockedAddress[_from] == false);
		require(!blockedAddress[_to] || blockedAddress[_to] == false);

		balances[_from] = balances[_from].sub(_amount);
		balances[_to] = balances[_to].add(_amount);
		emit Transfer(_from, _to, _amount);
		}

    // @return The balance of `_owner`
    function balanceOf(address _owner) public constant returns (uint256 balance) {
        return balances[_owner];
		}
		
	 // @return The lock status of targetAddress
    function lockStatusOf(address targetAddress) public constant returns (bool state) {
        return blockedAddress[targetAddress];
		}
		
	// @return The transfer allowance of targetAddress
    function transferAllowanceOf(address targetAddress) public constant returns (bool state) {
        return allowedToTransfer[targetAddress];
		}

    // @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
    //  its behalf. This is a modified version of the ERC20 approve function
    //  to be a little bit safer
    // @param _spender The address of the account able to transfer the tokens
    // @param _amount The amount of tokens to be approved for transfer
    // @return True if the approval was successful
    function approve(address _spender, uint256 _amount) public returns (bool success) {
        // 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
        require((_amount == 0) || (allowed[msg.sender][_spender] == 0));

        allowed[msg.sender][_spender] = _amount;
        emit Approval(msg.sender, _spender, _amount);
        return true;
		}

    function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
			}
		}

    function burn(uint256 _value) public onlyOwner {
        require(balances[msg.sender] >= _value);
        balances[msg.sender] = balances[msg.sender].sub(_value);
        totalSupply = totalSupply.sub(_value);
		}

    /** @dev This function makes it easy to read the `allowed[]` map
    * @param _owner The address of the account that owns the token
    * @param _spender The address of the account able to transfer the tokens
    * @return Amount of remaining tokens of _owner that _spender is allowed
    *  to spend
	  */
    function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
        return allowed[_owner][_spender];
		}

    // @dev This function makes it easy to get the total number of tokens
    // @return The total number of tokens
    function totalSupply() public constant returns (uint) {
        return totalSupply;
		}
	
	// @dev This function set the lock status
	function setTokenTransferLock(bool lockStatus) public onlyOwner {
		enabledTokenTransfer = lockStatus;
		}
		
	// @dev This function set an address to allow transfer tokens
	function setAddressTransferAllowance(address targetAddress, bool lockStatus) public onlyOwner {
		allowedToTransfer[targetAddress] = lockStatus;
		}
	
	// @dev This function block an address to receive and send tokens	
	function setAddressBlockState(address targetAddress, bool lockStatus) public onlyOwner {
		require(targetAddress != owner);
		blockedAddress[targetAddress] = lockStatus;
		}

    event Transfer(
        address indexed _from,
        address indexed _to,
        uint256 _amount
        );

    event Approval(
        address indexed _owner,
        address indexed _spender,
        uint256 _amount
        );

    event Burn(
        address indexed _burner,
        uint256 _amount
        );
}