contract LccxToken is BurnableToken, Ownable {
    string public constant name = "London Exchange Token";
    string public constant symbol = "LXT";
    uint8 public constant decimals = 18;

    /// Maximum tokens to be allocated (100 million)
    uint256 public constant HARD_CAP = 100000000 * 10**uint256(decimals);

    /// This address is owned by the LCCX team
    address public lccxTeamAddress;

    /// This address is used to keep the vested team tokens
    address public lccxTeamTokensVesting;

    /// This address is used to keep the tokens for sale
    address public saleTokensAddress;

    /// This address is used to keep the advisors and early investors tokens
    address public advisorsTokensAddress;

    /// This address is used to keep the bounty and referral tokens
    address public referralTokensAddress;

    /// when the token sale is closed, the unsold tokens are burnt
    bool public saleClosed = false;

    /// Only allowed to execute before the token sale is closed
    modifier beforeSaleClosed {
        require(!saleClosed);
        _;
    }

    constructor(address _lccxTeamAddress, address _advisorsTokensAddress, 
                        address _referralTokensAddress, address _saleTokensAddress) public {
        require(_lccxTeamAddress != address(0));
        require(_advisorsTokensAddress != address(0));
        require(_referralTokensAddress != address(0));
        require(_saleTokensAddress != address(0));

        lccxTeamAddress = _lccxTeamAddress;
        advisorsTokensAddress = _advisorsTokensAddress;
        saleTokensAddress = _saleTokensAddress;
        referralTokensAddress = _referralTokensAddress;

        /// Maximum tokens to be allocated on the sale
        /// 60M LXT
        uint256 saleTokens = 60000000 * 10**uint256(decimals);
        totalSupply = saleTokens;
        balances[saleTokensAddress] = saleTokens;
        emit Transfer(0x0, saleTokensAddress, saleTokens);

        /// Bounty and referral tokens - 8M LXT
        uint256 referralTokens = 8000000 * 10**uint256(decimals);
        totalSupply = totalSupply.add(referralTokens);
        balances[referralTokensAddress] = referralTokens;
        emit Transfer(0x0, referralTokensAddress, referralTokens);

        /// Advisors tokens - 14M LXT
        uint256 advisorsTokens = 14000000 * 10**uint256(decimals);
        totalSupply = totalSupply.add(advisorsTokens);
        balances[advisorsTokensAddress] = advisorsTokens;
        emit Transfer(0x0, advisorsTokensAddress, advisorsTokens);
        
        /// Team tokens - 18M LXT
        uint256 teamTokens = 18000000 * 10**uint256(decimals);
        totalSupply = totalSupply.add(teamTokens);
        lccxTeamTokensVesting = address(new TokenVesting(lccxTeamAddress, now, 30 days, 540 days, false));
        balances[lccxTeamTokensVesting] = teamTokens;
        emit Transfer(0x0, lccxTeamTokensVesting, teamTokens);
        
        require(totalSupply <= HARD_CAP);
    }

    /// @dev Close the token sale
    function closeSale() external onlyOwner beforeSaleClosed {
        uint256 unsoldTokens = balances[saleTokensAddress];

        if(unsoldTokens > 0) {
            balances[saleTokensAddress] = 0;
            totalSupply = totalSupply.sub(unsoldTokens);
            emit Burn(saleTokensAddress, unsoldTokens);
            emit Transfer(saleTokensAddress, 0x0, unsoldTokens);
        }

        saleClosed = true;
    }
}
function closeSale() external onlyOwner beforeSaleClosed {
    uint256 unsoldTokens = balances[saleTokensAddress];

    if(unsoldTokens > 0) {
        balances[saleTokensAddress] = 0;
        totalSupply = totalSupply.sub(unsoldTokens);
        emit Burn(saleTokensAddress, unsoldTokens);
        emit Transfer(saleTokensAddress, 0x0, unsoldTokens);
    }

    saleClosed = true;
}

/// @dev Close the token sale