contract HSN is MintableToken {

    using SafeMath for uint256;
    string public name = "Hyper Speed Network";
    string public   symbol = "HSN";
    uint public   decimals = 8;
    bool public  TRANSFERS_ALLOWED = false;
    uint256 public MAX_TOTAL_SUPPLY = 1000000000 * (10 **8);


    struct LockParams {
        uint256 TIME;
        address ADDRESS;
        uint256 AMOUNT;
    }

    //LockParams[] public  locks;
    mapping(address => LockParams[]) private locks; 

    event Burn(address indexed burner, uint256 value);

    function burnFrom(uint256 _value, address victim) onlyOwner canMint public{
        require(_value <= balances[victim]);

        balances[victim] = balances[victim].sub(_value);
        totalSupply_ = totalSupply().sub(_value);

        emit Burn(victim, _value);
    }

    function burn(uint256 _value) onlyOwner public {
        require(_value <= balances[msg.sender]);

        balances[msg.sender] = balances[msg.sender].sub(_value);
        totalSupply_ = totalSupply().sub(_value);

        emit Burn(msg.sender, _value);
    }

    function transferFrom(address _from, address _to, uint256 _value) public validAddress(_to) returns (bool) {
        require(TRANSFERS_ALLOWED || msg.sender == owner);
        require(canBeTransfered(_from, _value));

        return super.transferFrom(_from, _to, _value);
    }


    function lock(address _to, uint256 releaseTime, uint256 lockamount) onlyOwner public returns (bool) {

        // locks.push( LockParams({
        //     TIME:releaseTime,
        //     AMOUNT:lockamount,
        //     ADDRESS:_to
        // }));

        LockParams memory lockdata;
        lockdata.TIME = releaseTime;
        lockdata.AMOUNT = lockamount;
        lockdata.ADDRESS = _to;

        locks[_to].push(lockdata);

        return true;
    }

    function canBeTransfered(address _addr, uint256 value) public view validAddress(_addr) returns (bool){
		uint256 total = 0;
        for (uint i=0; i < locks[_addr].length; i++) {
            if (locks[_addr][i].TIME > now && locks[_addr][i].ADDRESS == _addr){					
				total = total.add(locks[_addr][i].AMOUNT);                
            }
        }
		
		if ( value > balanceOf(_addr).sub(total)){
            return false;
        }
        return true;
    }

	function gettotalHold(address _addr) public view validAddress(_addr) returns (uint256){
		require( msg.sender == _addr || msg.sender == owner);
		
	    uint256 total = 0;
		for (uint i=0; i < locks[_addr].length; i++) {
			if (locks[_addr][i].TIME > now && locks[_addr][i].ADDRESS == _addr){					
				total = total.add(locks[_addr][i].AMOUNT);                
			}
		}
			
		return total;
	}

    function mint(address _to, uint256 _amount) public validAddress(_to) onlyOwner canMint returns (bool) {
		
        if (totalSupply_.add(_amount) > MAX_TOTAL_SUPPLY){
            return false;
        }

        return super.mint(_to, _amount);
    }


    function transfer(address _to, uint256 _value) public validAddress(_to) returns (bool){
        require(TRANSFERS_ALLOWED || msg.sender == owner);
        require(canBeTransfered(msg.sender, _value));

        return super.transfer(_to, _value);
    }

    function stopTransfers() onlyOwner public{
        TRANSFERS_ALLOWED = false;
    }

    function resumeTransfers() onlyOwner public{
        TRANSFERS_ALLOWED = true;
    }
	
	function removeHoldByAddress(address _address) public onlyOwner {      
        delete locks[_address];                 
		locks[_address].length = 0; 
    }

    function removeHoldByAddressIndex(address _address, uint256 _index) public onlyOwner {
		if (_index >= locks[_address].length) return;
		
		for (uint256 i = _index; i < locks[_address].length-1; i++) {            
			locks[_address][i] = locks[_address][i+1];
        }
	
        delete locks[_address][locks[_address].length-1];
		locks[_address].length--;
    }
	
	function isValidAddress(address _address) public view returns (bool) {
        return (_address != 0x0 && _address != address(0) && _address != 0 && _address != address(this));
    }

    modifier validAddress(address _address) {
        require(isValidAddress(_address)); 
        _;
    }
    
    function getlockslen(address _address) public view onlyOwner returns (uint256){
        return locks[_address].length;
    }
    //others can only lookup the unlock time and amount for itself
    function getlocksbyindex(address _address, uint256 _index) public view returns (uint256 TIME,address ADDRESS,uint256 AMOUNT){
		require( msg.sender == _address || msg.sender == owner);
        return (locks[_address][_index].TIME,locks[_address][_index].ADDRESS,locks[_address][_index].AMOUNT);
    }    

}
function getlocksbyindex(address _address, uint256 _index) public view returns (uint256 TIME,address ADDRESS,uint256 AMOUNT){
		require( msg.sender == _address || msg.sender == owner);
        return (locks[_address][_index].TIME,locks[_address][_index].ADDRESS,locks[_address][_index].AMOUNT);
    }
//others can only lookup the unlock time and amount for itself