contract SocialGoodToken is
    ERC20Pausable,
    ERC20Burnable,
    ERC20Mintable,
    ERC20Capped
{
    string private constant _name = "SocialGood";
    string private constant _symbol = "SG";
    uint8 private constant _decimals = 18;

    // set maximum token normal hard cap
    uint256 private constant NORMAL_HARD_CAP = 209250000e18; // 209,250,000 SG
    // set maximum token airdrop hard cap
    uint256 private constant AIRDROP_HARD_CAP = 750000e18; // 750,000 SG

    mapping(address => uint256) private _lockupAmounts;

    constructor() public ERC20Capped(NORMAL_HARD_CAP, AIRDROP_HARD_CAP) {}

    /**
     * @dev Returns the name of the token.
     */
    function name() public pure returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public pure returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public pure returns (uint8) {
        return _decimals;
    }

    function getAddressLockupAmount(address _account)
        public
        view
        returns (uint256)
    {
        return _lockupAmounts[_account];
    }

    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public onlyOwner {
        _burn(msg.sender, amount);
    }

    /**
     * @dev See {ERC20-_burnFrom}.
     */
    function burnFrom(address account, uint256 amount) public onlyOwner {
        _burnFrom(account, amount);
    }

    /**
     * @dev Used for validating inputs before execute lockup
     */
    function _preValidateAirdrop(address _account, uint256 _amount)
        internal
        pure
    {
        require(
            _account != address(0),
            "SocialGoodToken: airdrop target address is empty"
        );
        require(_amount != 0, "SocialGoodToken: amount is zero");
    }

    /**
     * @dev Used for migrating old SG token to new SG token.
     * The token amount will be locked until the owner unlock it manually.
     */
    function airdropLockup(
        address[] calldata _accounts,
        uint256[] calldata _amounts
    ) external onlyOwner whenNotPaused {
        require(
            _accounts.length == _amounts.length,
            "SocialGoodToken: the length of accounts, amounts are not the same"
        );
        uint256 length = _accounts.length;
        for (uint256 i = 0; i != length; i++) {
            _preValidateAirdrop(_accounts[i], _amounts[i]);
            _lockup(_accounts[i], _amounts[i]);
        }
    }

    /**
     * @dev Used for locking up token amount of any address.
     * This is an internal function, only called from the owner's airdropLockup function.
     */
    function _lockup(address _account, uint256 _amount) internal {
        _lockupAmounts[_account] = _lockupAmounts[_account].add(_amount);
        _incrementUsedAirdropCap(_amount);
    }

    /**
     * @dev Used for unlocking token when migrating from old SG token to new SG token.
     * The token amount will be minted to selected addresses up to the token issue limit.
     * Data will be read from _lockupAmounts and reset to zero after token is minted.
     */
    function unlocks(address[] calldata _accounts)
        external
        onlyOwner
        whenNotPaused
    {
        uint256 length = _accounts.length;
        for (uint256 i = 0; i != length; i++) {
            _unlock(_accounts[i]);
        }
    }

    function _unlock(address _account) internal {
        require(
            _lockupAmounts[_account] != 0,
            "SocialGoodToken: amount is zero"
        );
        _airdropMint(_account, _lockupAmounts[_account]);
        _lockupAmounts[_account] = 0;
    }
}
/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * @dev https://github.com/ethereum/EIPs/issues/20
 * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
function decimals() public pure returns (uint8) {
    return _decimals;
}

/**
 * @dev Returns the number of decimals used to get its user representation.
 * For example, if `decimals` equals `2`, a balance of `505` tokens should
 * be displayed to a user as `5,05` (`505 / 10 ** 2`).
 *
 * Tokens usually opt for a value of 18, imitating the relationship between
 * Ether and Wei.
 *
 * NOTE: This information is only used for _display_ purposes: it in
 * no way affects any of the arithmetic of the contract, including
 * {IERC20-balanceOf} and {IERC20-transfer}.
 */