contract HVT is MintableToken, BurnableToken {
  using SafeMath for uint256;

  string public name = "HiVe Token";
  string public symbol = "HVT";
  uint8 public decimals = 18;

  enum State {Blocked,Burnable,Transferable}
  State public state = State.Blocked;

  // functions overrides in order to maintain the token locked during the ICO
  function transfer(address _to, uint256 _value) public returns(bool) {
    require(state == State.Transferable);
    return super.transfer(_to,_value);
  }

  function transferFrom(address _from, address _to, uint256 _value) public returns(bool) {
      require(state == State.Transferable);
      return super.transferFrom(_from,_to,_value);
  }

  function approve(address _spender, uint256 _value) public returns (bool) {
    require(state == State.Transferable);
    return super.approve(_spender,_value);
  }

  function burn(uint256 _value) public {
    require(state == State.Transferable || state == State.Burnable);
    super.burn(_value);
  }

  function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
    require(state == State.Transferable);
    super.increaseApproval(_spender, _addedValue);
  }

  function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
    require(state == State.Transferable);
    super.decreaseApproval(_spender, _subtractedValue);
  }

  // enable token transfers
  function enableTokenTransfers() public onlyOwner {
    state = State.Transferable;
  }

  // enable token burn
  function enableTokenBurn() public onlyOwner {
    state = State.Burnable;
  }

  // batch transfer with different amounts for each address
  function batchTransferDiff(address[] _to, uint256[] _amount) public {
    require(state == State.Transferable);
    require(_to.length == _amount.length);
    uint256 totalAmount = arraySum(_amount);
    require(totalAmount <= balances[msg.sender]);
    balances[msg.sender] = balances[msg.sender].sub(totalAmount);
    for(uint i;i < _to.length;i++){
      balances[_to[i]] = balances[_to[i]].add(_amount[i]);
      Transfer(msg.sender,_to[i],_amount[i]);
    }
  }

  // batch transfer with same amount for each address
  function batchTransferSame(address[] _to, uint256 _amount) public {
    require(state == State.Transferable);
    uint256 totalAmount = _amount.mul(_to.length);
    require(totalAmount <= balances[msg.sender]);
    balances[msg.sender] = balances[msg.sender].sub(totalAmount);
    for(uint i;i < _to.length;i++){
      balances[_to[i]] = balances[_to[i]].add(_amount);
      Transfer(msg.sender,_to[i],_amount);
    }
  }

  // get sum of array values
  function arraySum(uint256[] _amount) internal pure returns(uint256){
    uint256 totalAmount;
    for(uint i;i < _amount.length;i++){
      totalAmount = totalAmount.add(_amount[i]);
    }
    return totalAmount;
  }
}
function batchTransferDiff(address[] _to, uint256[] _amount) public {
  require(state == State.Transferable);
  require(_to.length == _amount.length);
  uint256 totalAmount = arraySum(_amount);
  require(totalAmount <= balances[msg.sender]);
  balances[msg.sender] = balances[msg.sender].sub(totalAmount);
  for(uint i;i < _to.length;i++){
    balances[_to[i]] = balances[_to[i]].add(_amount[i]);
    Transfer(msg.sender,_to[i],_amount[i]);
  }
}

// batch transfer with different amounts for each address