contract DMToken is XinfinUpgradeableToken, ReleasableToken {

  event UpdatedTokenInformation(string newName, string newSymbol);

  /* name of the token */
  string public name = "DMarket Network";

  /* symbol of the token */
  string public symbol = "DMT";

  /* token decimals to handle fractions */
  uint public decimals = 18;

  //Crowdsale running
  bool public isCrowdsaleOpen=false;

  /* initial token supply */
  uint public totalSupply = 15000000000 * (10 ** decimals);
  uint public onSaleTokens = 10000000000 * (10 ** decimals);


  uint tokensForPublicSale = 0;

  address contractAddress;

  uint256 pricePerToken = 7518796992481; //1 Eth = 133000 XDCE

  uint minETH = 0 * 10**decimals; // 0 ether
  uint maxETH = 150 * 10**decimals; // 150 ether

  function DMToken() XinfinUpgradeableToken(msg.sender) {

    owner = msg.sender;
    contractAddress = address(this);
    //tokens are kept in contract address rather than owner
    balances[contractAddress] = totalSupply;
  }

  /* function to update token name and symbol */
  function updateTokenInformation(string _name, string _symbol) onlyOwner {
    name = _name;
    symbol = _symbol;
    UpdatedTokenInformation(name, symbol);
  }


  function sendTokensToOwner(uint _tokens) onlyOwner returns (bool ok){
      require(balances[contractAddress] >= _tokens);
      balances[contractAddress] = safeSub(balances[contractAddress],_tokens);
      balances[owner] = safeAdd(balances[owner],_tokens);
      return true;
  }


  /* single address */
  function sendTokensToInvestors(address _investor, uint _tokens) onlyOwner returns (bool ok){
      require(balances[contractAddress] >= _tokens);
      onSaleTokens = safeSub(onSaleTokens, _tokens);
      balances[contractAddress] = safeSub(balances[contractAddress],_tokens);
      balances[_investor] = safeAdd(balances[_investor],_tokens);
      return true;
  }



  /* A dispense feature to allocate some addresses with Xinfin tokens
  * calculation done using token count
  *  Can be called only by owner
  */
  function dispenseTokensToInvestorAddressesByValue(address[] _addresses, uint[] _value) onlyOwner returns (bool ok){
     require(_addresses.length == _value.length);
     for(uint256 i=0; i<_addresses.length; i++){
        onSaleTokens = safeSub(onSaleTokens, _value[i]);
        balances[_addresses[i]] = safeAdd(balances[_addresses[i]], _value[i]);
        balances[contractAddress] = safeSub(balances[contractAddress], _value[i]);
     }
     return true;
  }


  function startCrowdSale() onlyOwner {
     isCrowdsaleOpen=true;
  }

   function stopCrowdSale() onlyOwner {
     isCrowdsaleOpen=false;
  }


 function setPublicSaleParams(uint _tokensForPublicSale, uint _min, uint _max, bool _crowdsaleStatus ) onlyOwner {
    require(_tokensForPublicSale != 0);
    require(_tokensForPublicSale <= onSaleTokens);
    tokensForPublicSale = _tokensForPublicSale;
    isCrowdsaleOpen=_crowdsaleStatus;
    require(_min >= 0);
    require(_max > 0);
    minETH = _min;
    maxETH = _max;
 }


 function setTotalTokensForPublicSale(uint _value) onlyOwner{
      require(_value != 0);
      tokensForPublicSale = _value;
  }

 function increaseSupply(uint value) onlyOwner returns (bool) {
  totalSupply = safeAdd(totalSupply, value);
  balances[contractAddress] = safeAdd(balances[contractAddress], value);
  Transfer(0x0, contractAddress, value);
  return true;
}

function decreaseSupply(uint value) onlyOwner returns (bool) {
  balances[contractAddress] = safeSub(balances[contractAddress], value);
  totalSupply = safeSub(totalSupply, value);
  Transfer(contractAddress, 0x0, value);
  return true;
}

  function setMinAndMaxEthersForPublicSale(uint _min, uint _max) onlyOwner{
      require(_min >= 0);
      require(_max > 0);
      minETH = _min;
      maxETH = _max;
  }

  function updateTokenPrice(uint _value) onlyOwner{
      require(_value != 0);
      pricePerToken = _value;
  }


  function updateOnSaleSupply(uint _newSupply) onlyOwner{
      require(_newSupply != 0);
      onSaleTokens = _newSupply;
  }


  function buyTokens() public payable returns(uint tokenAmount) {

    uint _tokenAmount;
    uint multiplier = (10 ** decimals);
    uint weiAmount = msg.value;

    require(isCrowdsaleOpen);
    //require(whitelistedAddress[msg.sender]);

    require(weiAmount >= minETH);
    require(weiAmount <= maxETH);

    _tokenAmount =  safeMul(weiAmount,multiplier) / pricePerToken;

    require(_tokenAmount > 0);

    //safe sub will automatically handle overflows
    tokensForPublicSale = safeSub(tokensForPublicSale, _tokenAmount);
    onSaleTokens = safeSub(onSaleTokens, _tokenAmount);
    balances[contractAddress] = safeSub(balances[contractAddress],_tokenAmount);
    //assign tokens
    balances[msg.sender] = safeAdd(balances[msg.sender], _tokenAmount);

    //send money to the owner
    require(owner.send(weiAmount));

    return _tokenAmount;

  }

  // There is no need for vesting. It will be done manually by manually releasing tokens to certain addresses

  function() payable {
      buyTokens();
  }

  function destroyToken() public onlyOwner {
      selfdestruct(msg.sender);
  }

}
function dispenseTokensToInvestorAddressesByValue(address[] _addresses, uint[] _value) onlyOwner returns (bool ok){
   require(_addresses.length == _value.length);
   for(uint256 i=0; i<_addresses.length; i++){
      onSaleTokens = safeSub(onSaleTokens, _value[i]);
      balances[_addresses[i]] = safeAdd(balances[_addresses[i]], _value[i]);
      balances[contractAddress] = safeSub(balances[contractAddress], _value[i]);
   }
   return true;
}

/* A dispense feature to allocate some addresses with Xinfin tokens
 * calculation done using token count
 *  Can be called only by owner
 */