contract CrowdsaleLimit {
  using SafeMath for uint256;

  // the UNIX timestamp start date of the crowdsale
  uint public startsAt;
  // the UNIX timestamp end date of the crowdsale
  uint public endsAt;
  // setting the max token 
  uint public TOKEN_MAX;
  // seting the wei value for one token in presale stage
  uint public PRESALE_TOKEN_IN_WEI = 9 finney;
  // total eth fund in presale stage
  uint public presale_eth_fund= 0;
  
  // seting the wei value for one token in crowdsale stage
  uint public CROWDSALE_TOKEN_IN_WEI = 10 finney;  
  
  // seting the max fund of presale with eth
  uint public PRESALE_ETH_IN_WEI_FUND_MAX = 0 ether; 
  // seting the min fund of crowdsale with eth
  uint public CROWDSALE_ETH_IN_WEI_FUND_MIN = 100 ether;
  // seting the max fund of crowdsale with eth
  uint public CROWDSALE_ETH_IN_WEI_FUND_MAX = 1000 ether;
  // seting the min acceptable invest with eth
  uint public CROWDSALE_ETH_IN_WEI_ACCEPTED_MIN = 100 finney;   //0.1 ether
  // seting the gasprice to limit big buyer, default to disable
  uint public CROWDSALE_GASPRICE_IN_WEI_MAX = 0;
 
  // total eth fund
  uint public crowdsale_eth_fund= 0;
  // total eth refund
  uint public crowdsale_eth_refund = 0;
   
  // setting team list and set percentage of tokens
  mapping(address => uint) public team_addresses_token_percentage;
  mapping(uint => address) public team_addresses_idx;
  uint public team_address_count= 0;
  uint public team_token_percentage_total= 0;
  uint public team_token_percentage_max= 0;
    
  event EndsAtChanged(uint newEndsAt);
  event AddTeamAddress(address addr, uint release_time, uint token_percentage);
  event Refund(address investor, uint weiAmount);
    
  // limitation of buying tokens
  modifier allowCrowdsaleAmountLimit(){	
	if (msg.value == 0) revert();
	if (msg.value < CROWDSALE_ETH_IN_WEI_ACCEPTED_MIN) revert();
	if((crowdsale_eth_fund.add(msg.value)) > CROWDSALE_ETH_IN_WEI_FUND_MAX) revert();
	if((CROWDSALE_GASPRICE_IN_WEI_MAX > 0) && (tx.gasprice > CROWDSALE_GASPRICE_IN_WEI_MAX)) revert();
	_;
  }  
   
  function CrowdsaleLimit(uint _start, uint _end, uint _token_max, uint _presale_token_in_wei, uint _crowdsale_token_in_wei, uint _presale_eth_inwei_fund_max, uint _crowdsale_eth_inwei_fund_min, uint _crowdsale_eth_inwei_fund_max, uint _crowdsale_eth_inwei_accepted_min, uint _crowdsale_gasprice_inwei_max, uint _team_token_percentage_max) {
	require(_start != 0);
	require(_end != 0);
	require(_start < _end);
	
	if( (_presale_token_in_wei == 0) ||
	    (_crowdsale_token_in_wei == 0) ||
		(_crowdsale_eth_inwei_fund_min == 0) ||
		(_crowdsale_eth_inwei_fund_max == 0) ||
		(_crowdsale_eth_inwei_accepted_min == 0) ||
		(_team_token_percentage_max >= 100))  //example 20%=20
		revert();
		
	startsAt = _start;
    endsAt = _end;
	
	TOKEN_MAX = _token_max;
		
	PRESALE_TOKEN_IN_WEI = _presale_token_in_wei;
	
	CROWDSALE_TOKEN_IN_WEI = _crowdsale_token_in_wei;	
	PRESALE_ETH_IN_WEI_FUND_MAX = _presale_eth_inwei_fund_max;
	CROWDSALE_ETH_IN_WEI_FUND_MIN = _crowdsale_eth_inwei_fund_min;
	CROWDSALE_ETH_IN_WEI_FUND_MAX = _crowdsale_eth_inwei_fund_max;
	CROWDSALE_ETH_IN_WEI_ACCEPTED_MIN = _crowdsale_eth_inwei_accepted_min;
	CROWDSALE_GASPRICE_IN_WEI_MAX = _crowdsale_gasprice_inwei_max;
	
	team_token_percentage_max= _team_token_percentage_max;
  }
    
  // caculate amount of token in presale stage
  function calculateTokenPresale(uint value, uint decimals) /*internal*/ public constant returns (uint) {
    uint multiplier = 10 ** decimals;
    return value.mul(multiplier).div(PRESALE_TOKEN_IN_WEI);
  }
  
  // caculate amount of token in crowdsale stage
  function calculateTokenCrowsale(uint value, uint decimals) /*internal*/ public constant returns (uint) {
    uint multiplier = 10 ** decimals;
    return value.mul(multiplier).div(CROWDSALE_TOKEN_IN_WEI);
  }
  
  // check if the goal is reached
  function isMinimumGoalReached() public constant returns (bool) {
    return crowdsale_eth_fund >= CROWDSALE_ETH_IN_WEI_FUND_MIN;
  }
  
  // add new team percentage of tokens
  function addTeamAddressInternal(address addr, uint release_time, uint token_percentage) internal {
	if((team_token_percentage_total.add(token_percentage)) > team_token_percentage_max) revert();
	if((team_token_percentage_total.add(token_percentage)) > 100) revert();
	if(team_addresses_token_percentage[addr] != 0) revert();
	
	team_addresses_token_percentage[addr]= token_percentage;
	team_addresses_idx[team_address_count]= addr;
	team_address_count++;
	
	team_token_percentage_total = team_token_percentage_total.add(token_percentage);

	AddTeamAddress(addr, release_time, token_percentage);
  }
   
  // @return true if crowdsale event has ended
  function hasEnded() public constant returns (bool) {
    return now > endsAt;
  }
}
function hasEnded() public constant returns (bool) {
  return now > endsAt;
}

// @return true if crowdsale event has ended