contract QueenBeeCompanyToken is StandardToken, BurnableToken, Ownable, MintableToken {
    using SafeMath for uint256;

    event LockAccount(address addr, uint256 amount);
    event UnlockAccount(address addr);
    event ChangeAdmin(
      address indexed previousAdmin,
      address indexed newAdmin
    );
    event EnableTransfer();
    event DisableTransfer();


    string public constant symbol = "QBZ";
    string public constant name = "QBEE";
    uint8 public constant decimals = 18;

    uint256 public constant INITIAL_SUPPLY            = 8000000000 * (10 ** uint256(decimals));
    uint256 public constant INITIAL_SUPPLY_15PERCENT  = 1200000000 * (10 ** uint256(decimals));
    uint256 public constant INITIAL_SUPPLY_40PERCENT  = 3200000000 * (10 ** uint256(decimals));

    address public constant earlyFoundation     = 0x1980C8271Ba6BFaF1D5C43e8dAe655de8CFaBdBe;
    address public constant advisorTeam         = 0xE65A71a07d0D431d01CE6342Ba56BB3A2f634165;
    address public constant business            = 0x8A8f70f546c81EF8B178BBc4544d1F008C88096c;
    address public constant publicAddr          = 0xC1486038AA29bF676478e2bB787F97298900E08b;
    address public constant reserveAffiliates   = 0x086b779Eb55744A8518708f016fd5530493ecab5;

    // Address of token administrator
    address public adminAddr;

    // Enable transfer after token sale is completed
    bool public transferEnabled = true;

    // Accounts to be locked for certain period
    mapping(address => uint256) private lockedAccounts;

    /*
     *
     * Permissions when transferEnabled is false :
     *              ContractOwner    Admin      Others
     * transfer            v           v           x
     * transferFrom        v           v           x
     *
     * Permissions when transferEnabled is true :
     *              ContractOwner    Admin      Others
     * transfer            v           v           v
     * transferFrom        v           v           v
     *
     */

    /*
     * Check if token transfer is allowed
     * Permission table above is result of this modifier
     */
    modifier onlyWhenTransferAllowed() {
        require(transferEnabled == true
			|| msg.sender == owner
            || msg.sender == adminAddr);
        _;
    }

    modifier onlyAllowedAmount(address from, uint256 amount) {
        require(balances[from].sub(amount) >= lockedAccounts[from]);
        _;
    }
    /*
     * The constructor of QueenBeeCoin contract
     *
     * @param _adminAddr: Address of token administrator
     */
    constructor(address _adminAddr) public {
        _mint(earlyFoundation, INITIAL_SUPPLY_15PERCENT);
        _mint(advisorTeam, INITIAL_SUPPLY_15PERCENT);
        _mint(business, INITIAL_SUPPLY_15PERCENT);
        _mint(publicAddr, INITIAL_SUPPLY_40PERCENT);
        _mint(reserveAffiliates, INITIAL_SUPPLY_15PERCENT);

        // token migration from old token
        allowed[earlyFoundation][msg.sender] = INITIAL_SUPPLY_15PERCENT;
        
        address beneficiary_1 = 0xf559b5A8910183E9B5ca7DFA5A30e3CC38177056;
        address beneficiary_2 = 0x8E39AAF968D65c2040f51145777700147B8025AB;
        address beneficiary_3 = 0x34B400774388b922E42b1339b6DB8Df623D60ca4;
        address beneficiary_4 = 0x4593E0a3bBEA7CEeb892e8ba8BBE808a3c8d3478;
        address beneficiary_5 = 0x5068c0bDBe8c92F5fd4D346d1072C59359623de7;
        address beneficiary_6 = 0xB2b588Ad768373b36109825871E65e99FEAc441B;
        address beneficiary_7 = 0x9B82b4D087928497cb6728402f68e0C33DA5205C;

        uint256 token_1 = 16000000 * 10**uint256(decimals);
        uint256 token_2 = 16000000 * 10**uint256(decimals);
        uint256 token_3 =  8000000 * 10**uint256(decimals);
        uint256 token_4 =  8000000 * 10**uint256(decimals);
        uint256 token_5 =  4000000 * 10**uint256(decimals);
        uint256 token_6 =  2000000 * 10**uint256(decimals);
        uint256 token_7 =  2000000 * 10**uint256(decimals);
        
        transferFrom(earlyFoundation, beneficiary_1, token_1);
        transferFrom(earlyFoundation, beneficiary_2, token_2);
        transferFrom(earlyFoundation, beneficiary_3, token_3);
        transferFrom(earlyFoundation, beneficiary_4, token_4);
        transferFrom(earlyFoundation, beneficiary_5, token_5);
        transferFrom(earlyFoundation, beneficiary_6, token_6);
        transferFrom(earlyFoundation, beneficiary_7, token_7);
        
        allowed[earlyFoundation][msg.sender] = 0; 
        adminAddr = _adminAddr;
    }

    /*
     * Change admin address 
     */
    function changeAdmin(address _adminAddr) public onlyOwner {
        emit ChangeAdmin(adminAddr, _adminAddr);
        adminAddr = _adminAddr;
    }


    /*
     * Set transferEnabled variable to true
     */
    function enableTransfer() external onlyOwner {
        transferEnabled = true;
        emit EnableTransfer();
    }

    /*
     * Set transferEnabled variable to false
     */
    function disableTransfer() external onlyOwner {
	      transferEnabled = false;
        emit DisableTransfer();
    }

    /*
     * Transfer token from message sender to another
     *
     * @param to: Destination address
     * @param value: Amount of QBST to transfer
     */
    function transfer(address to, uint256 value)
        public
        onlyWhenTransferAllowed
        onlyAllowedAmount(msg.sender, value)
        returns (bool)
    {
        return super.transfer(to, value);
    }

    /*
     * Transfer token from 'from' address to 'to' addreess
     *
     * @param from: Origin address
     * @param to: Destination address
     * @param value: Amount of QBST to transfer
     */
    function transferFrom(address from, address to, uint256 value)
        public
        onlyWhenTransferAllowed
        onlyAllowedAmount(from, value)
        returns (bool)
    {
        return super.transferFrom(from, to, value);
    }

    /*
     * Burn token, only owner is allowed
     *
     * @param value: Amount of QBST to burn
     */
    function burn(uint256 value) public onlyOwner {
        //require(transferEnabled);
        super.burn(value);
    }

    function mint(address to, uint256 value) public onlyOwner returns(bool) {
        //require(transferEnabled);
        require(totalSupply().add(value) <= INITIAL_SUPPLY);
        super.mint(to, value);
    }

    /*
     * Disable transfering tokens more than allowed amount from certain account
     *
     * @param addr: Account to set allowed amount
     * @param amount: Amount of tokens to allow
     */
    function lockAccount(address addr, uint256 amount)
        external
        onlyOwner
    {
        require(amount > 0 && amount <= balanceOf(addr));
        lockedAccounts[addr] = amount;
        emit LockAccount(addr, amount);
    }

    /*
     * Enable transfering tokens of locked account
     *
     * @param addr: Account to unlock
     */

    function unlockAccount(address addr)
        external
        onlyOwner
    {
        lockedAccounts[addr] = 0;
        emit UnlockAccount(addr);
    }
    
    function lockedValue(address addr) public view returns(uint256) {
        return lockedAccounts[addr];
    }
}
function enableTransfer() external onlyOwner {
    transferEnabled = true;
    emit EnableTransfer();
}

/*
 * Set transferEnabled variable to true
 */