pragma solidity 0.4.24;

/**
 * @title SafeMath
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
 */

library SafeMath {
	function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
		if (a == 0) {
			return 0;
		}
		c = a * b;
		assert(c / a == b);
		return c;
	}
	
	function div(uint256 a, uint256 b) internal pure returns (uint256) {
		return a / b;
	}
	
	function sub(uint256 a, uint256 b) internal pure returns (uint256) {
		assert(b <= a);
		return a - b;
	}
	
	function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
		c = a + b;
		assert(c >= a);
		return c;
	}
}

/**
 * @title Ownable
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol */
contract Ownable {
	address public owner;
	
	constructor() public {
		owner = msg.sender;
	}
	
	modifier onlyOwner() {
		require(msg.sender == owner);
		_;
	}
}

/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism. */
contract Pausable is Ownable {
	event Pause();
	event Unpause();
	
	bool public paused = false;
	
	modifier whenNotPaused() {
		require(!paused);
		_;
	}
	
	modifier whenPaused() {
		require(paused);
		_;
	}
	
	function pause() onlyOwner whenNotPaused public {
		paused = true;
		emit Pause();
	}
	
	function unpause() onlyOwner whenPaused public {
		paused = false;
		emit Unpause();
	}
}
/**
 * @title ERC20Basic
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/ERC20Basic.sol
 */
contract ERC20Basic {
	function totalSupply() public view returns (uint256);
	function balanceOf(address who) public view returns (uint256);
	function transfer(address to, uint256 value) public returns (bool);
	event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
 * @title Basic token
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/BasicToken.sol
 */
contract BasicToken is ERC20Basic {
	using SafeMath for uint256;
	
	mapping(address => uint256) balances;
	
	uint256 totalSupply_;
	
	function totalSupply() public view returns (uint256) {
		return totalSupply_;
	}
	
	function transfer(address _to, uint256 _value) public returns (bool) {
		require(_to != address(0));
		require(_value <= balances[msg.sender]);
		
		balances[msg.sender] = balances[msg.sender].sub(_value);
		balances[_to] = balances[_to].add(_value);
		emit Transfer(msg.sender, _to, _value);
		return true;
	}
	
	function balanceOf(address _owner) public view returns (uint256) {
		return balances[_owner];
	}
}
/**
 * @title ERC20 interface
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/ERC20.sol
 */
contract ERC20 is ERC20Basic {
	function allowance(address owner, address spender) public view returns (uint256);
	function transferFrom(address from, address to, uint256 value) public returns (bool);
	function approve(address spender, uint256 value) public returns (bool);
	event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
 * @title Standard ERC20 token
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/StandardToken.sol
 */
contract StandardToken is ERC20, BasicToken {
	
	mapping (address => mapping (address => uint256)) internal allowed;
	
	function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
		require(_to != address(0));
		require(_value <= balances[_from]);
		require(_value <= allowed[_from][msg.sender]);
		
		balances[_from] = balances[_from].sub(_value);
		balances[_to] = balances[_to].add(_value);
		allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
		emit Transfer(_from, _to, _value);
		return true;
	}
	
	function approve(address _spender, uint256 _value) public returns (bool) {
		allowed[msg.sender][_spender] = _value;
		emit Approval(msg.sender, _spender, _value);
		return true;
	}
	
	function allowance(address _owner, address _spender) public view returns (uint256) {
		return allowed[_owner][_spender];
	}
	
	function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
		allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
		emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
		return true;
	}
	
	function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
		uint oldValue = allowed[msg.sender][_spender];
		if (_subtractedValue > oldValue) {
			allowed[msg.sender][_spender] = 0;
		} else {
			allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
		}
		emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
		return true;
	}
}

/**
 * @title Pausable token
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/PausableToken.sol
 **/
contract PausableToken is StandardToken, Pausable {
	
	function transfer(
		address _to,
		uint256 _value
	) public  whenNotPaused returns (bool)
	{
		return super.transfer(_to, _value);
	}
	
	function transferFrom(
		address _from,
		address _to,
		uint256 _value
	) public whenNotPaused returns (bool)
	{
		return super.transferFrom(_from, _to, _value);
	}
	
	function approve(
		address _spender,
		uint256 _value
	) public whenNotPaused returns (bool)
	{
		return super.approve(_spender, _value);
	}
	
	function increaseApproval(
		address _spender,
		uint _addedValue
	) public whenNotPaused returns (bool success)
	{
		return super.increaseApproval(_spender, _addedValue);
	}
	
	function decreaseApproval(
		address _spender,
		uint _subtractedValue
	) public whenNotPaused returns (bool success)
	{
		return super.decreaseApproval(_spender, _subtractedValue);
	}
}

/**
 * @title Burnable Token
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/BurnableToken.sol
 */
contract BurnableToken is BasicToken {
	
	event Burn(address indexed burner, uint256 value);
	
	function burn(uint256 _value) public {
		_burn(msg.sender, _value);
	}
	
	function _burn(address _who, uint256 _value) internal {
		require(_value <= balances[_who]);
		
		balances[_who] = balances[_who].sub(_value);
		totalSupply_ = totalSupply_.sub(_value);
		emit Burn(_who, _value);
		emit Transfer(_who, address(0), _value);
	}
}
/**
 * @title Mintable token
 * @dev https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/MintableToken.sol
 */
contract MintableToken is PausableToken {
	event Mint(address indexed to, uint256 amount);
	event MintFinished();
	
	bool public mintingFinished = false;
	
	modifier canMint() {
		require(!mintingFinished);
		_;
	}
	
	modifier hasMintPermission() {
		require(msg.sender == owner);
		_;
	}
	
	function finishMinting() onlyOwner canMint public returns (bool) {
		mintingFinished = true;
		emit MintFinished();
		return true;
	}
}

/**
* @title AngeniumToken
*/
contract AngeniumToken is MintableToken, BurnableToken {
	
	using SafeMath for uint256;
	
	string  public name = "Angenium Coin";
	string  public symbol = "ANG";
	uint256 constant public decimals = 18;
	uint256 constant dec = 10**decimals;
	uint256 public constant initialSupply = 138000000*dec; // 138,000,000 ANG
	address public crowdsaleAddress;
	
	modifier onlyICO() {
		require(msg.sender == crowdsaleAddress);
		_;
	}
	
	constructor() public {
		pause();
	}
	
	function startCirculation() internal returns(bool) {
		if (totalSupply_ <= initialSupply)
			return false;
		else
			finishMinting();
		unpause();
	}
	
	function setSaleAddress(address _saleaddress) public onlyOwner{
		crowdsaleAddress = _saleaddress;
	}
	
	function mintFromICO(address _to, uint256 _amount) onlyICO canMint public returns (bool) {
		require(balances[_to].add(_amount) != 0);
		require(balances[_to].add(_amount) > balances[_to]);
		totalSupply_ = totalSupply_.add(_amount);
		require(!startCirculation());
		require(totalSupply_ <= initialSupply);
		balances[_to] = balances[_to].add(_amount);
		emit Mint(_to, _amount);
		emit Transfer(address(0), _to, _amount);
		return true;
	}
}