contract ToGoConcert is StandardToken, Ownable {

    string public name = "ToGoConcert";
    string public symbol = "TGC";
    uint public decimals = 18;

    // The token allocation
    uint public constant TOTAL_SUPPLY       = 10000000000e18;
    uint public constant ALLOC_ECOSYSTEM    =  10000000000e18; // 30%
    //uint public constant ALLOC_FOUNDATION   =  2100000000e18; // 20%
    //uint public constant ALLOC_TEAM         =  450000000e18; // 15%
    //uint public constant ALLOC_PARTNER      =  300000000e18; // 10%
    //uint public constant ALLOC_SALE         =  750000000e18; // 25%

    // wallets
    address public constant WALLET_ECOSYSTEM    = 0x47b6358164b81d500fb16c33ae3e91223fae2086; 
    //address public constant WALLET_FOUNDATION   = 0xbF96a0452A3388488673006bE65bC928BDe780d6;
    //address public constant WALLET_TEAM         = 0x9f255092008F6163395aEB35c4Dec58a1ecbdFd6;
    //address public constant WALLET_PARTNER      = 0xD6d64A62A7fF8F55841b0DD2c02d5052457bCA6c;
    //address public constant WALLET_SALE         = 0x55aaeC60E116086AC3a5e4fDC74b21de9B91CC53;
    
    // 2 groups of lockup
    mapping(address => uint256) public contributors_locked; 
    mapping(address => uint256) public investors_locked;

    // 2 types of releasing
    mapping(address => uint256) public contributors_countdownDate;
    mapping(address => uint256) public investors_deliveryDate;

    // MODIFIER

    // checks if the address can transfer certain amount of tokens
    modifier canTransfer(address _sender, uint256 _value) {
        require(_sender != address(0));

        uint256 remaining = balances[_sender].sub(_value);
        uint256 totalLockAmt = 0;

        if (contributors_locked[_sender] > 0) {
            totalLockAmt = totalLockAmt.add(getLockedAmount_contributors(_sender));
        }

        if (investors_locked[_sender] > 0) {
            totalLockAmt = totalLockAmt.add(getLockedAmount_investors(_sender));
        }

        require(remaining >= totalLockAmt);

        _;
    }

    // EVENTS
    event UpdatedLockingState(string whom, address indexed to, uint256 value, uint256 date);

    // FUNCTIONS

    function ToGoConcert() public {
        balances[msg.sender] = TOTAL_SUPPLY;
        totalSupply = TOTAL_SUPPLY;

        // do the distribution of the token, in token transfer
        transfer(WALLET_ECOSYSTEM, ALLOC_ECOSYSTEM);
        //transfer(WALLET_FOUNDATION, ALLOC_FOUNDATION);
        //transfer(WALLET_TEAM, ALLOC_TEAM);
        //transfer(WALLET_PARTNER, ALLOC_PARTNER);
        //transfer(WALLET_SALE, ALLOC_SALE);
    }
	
    // get contributors' locked amount of token
    // this lockup will be released in 8 batches which take place every 180 days
    function getLockedAmount_contributors(address _contributor) 
        public
		constant
		returns (uint256)
	{
        uint256 countdownDate = contributors_countdownDate[_contributor];
        uint256 lockedAmt = contributors_locked[_contributor];

        if (now <= countdownDate +  1 hours) {return lockedAmt;}
        if (now <= countdownDate +  2 hours) {return lockedAmt.mul(7).div(8);}
        if (now <= countdownDate +  3 hours) {return lockedAmt.mul(6).div(8);}
        if (now <= countdownDate +  4 hours) {return lockedAmt.mul(5).div(8);}
        if (now <= countdownDate +  5 hours) {return lockedAmt.mul(4).div(8);}
        if (now <= countdownDate +  6 hours) {return lockedAmt.mul(3).div(8);}
        if (now <= countdownDate +  7 hours) {return lockedAmt.mul(2).div(8);}
        if (now <= countdownDate +  8 hours) {return lockedAmt.mul(1).div(8);}
	
        return 0;
    }

    // get investors' locked amount of token
    // this lockup will be released in 3 batches: 
    // 1. on delievery date
    // 2. three months after the delivery date
    // 3. six months after the delivery date
    function getLockedAmount_investors(address _investor)
        public
		constant
		returns (uint256)
	{
        uint256 delieveryDate = investors_deliveryDate[_investor];
        uint256 lockedAmt = investors_locked[_investor];

        if (now <= delieveryDate) {return lockedAmt;}
        if (now <= delieveryDate + 1 hours) {return lockedAmt.mul(2).div(3);}
        if (now <= delieveryDate + 2 hours) {return lockedAmt.mul(1).div(3);}
	
        return 0;
    }

    // set lockup for contributors 
    function setLockup_contributors(address _contributor, uint256 _value, uint256 _countdownDate)
        public
        onlyOwner
    {
        require(_contributor != address(0));

        contributors_locked[_contributor] = _value;
        contributors_countdownDate[_contributor] = _countdownDate;
        UpdatedLockingState("contributor", _contributor, _value, _countdownDate);
    }

    // set lockup for strategic investor
    function setLockup_investors(address _investor, uint256 _value, uint256 _delieveryDate)
        public
        onlyOwner
    {
        require(_investor != address(0));

        investors_locked[_investor] = _value;
        investors_deliveryDate[_investor] = _delieveryDate;
        UpdatedLockingState("investor", _investor, _value, _delieveryDate);
    }

	// Transfer amount of tokens from sender account to recipient.
    function transfer(address _to, uint _value)
        public
        canTransfer(msg.sender, _value)
		returns (bool success)
	{
        return super.transfer(_to, _value);
    }

	// Transfer amount of tokens from a specified address to a recipient.
    function transferFrom(address _from, address _to, uint _value)
        public
        canTransfer(_from, _value)
		returns (bool success)
	{
        return super.transferFrom(_from, _to, _value);
    }
}
function setLockup_contributors(address _contributor, uint256 _value, uint256 _countdownDate)
    public
    onlyOwner
{
    require(_contributor != address(0));

    contributors_locked[_contributor] = _value;
    contributors_countdownDate[_contributor] = _countdownDate;
    UpdatedLockingState("contributor", _contributor, _value, _countdownDate);
}

// set lockup for contributors 