contract Crowdsale is StandardToken, Pausable, SafeMath, Utils{
	string public constant name = "Mudra";
	string public constant symbol = "MDR";
	uint256 public constant decimals = 18;
	string public version = "1.0";
	bool public tradingStarted = false;

    /**
   * @dev modifier that throws if trading has not started yet
   */
   modifier hasStartedTrading() {
   	require(tradingStarted);
   	_;
   }
  /**
   * @dev Allows the owner to enable the trading. This can not be undone
   */
   function startTrading() only(finalOwner) {
   	tradingStarted = true;
   }

   function transfer(address _to, uint _value) hasStartedTrading returns (bool success) {super.transfer(_to, _value);}

   function transferFrom(address _from, address _to, uint _value) hasStartedTrading returns (bool success) {super.transferFrom(_from, _to, _value);}

   enum State{
   	Inactive,
   	Funding,
   	Success,
   	Failure
   }

   modifier only(address allowed) {
   	if (msg.sender != allowed) throw;
   	_;
   }

   uint256 public investmentETH;
   uint256 public investmentBTC;
   mapping(uint256 => bool) transactionsClaimed;
   uint256 public initialSupply;
   address finalOwner;
   address wallet;
   uint256 public constant _totalSupply = 100 * (10**6) * 10 ** decimals; // 100M ~ 10 Crores
   uint256 public fundingStartBlock; // crowdsale start block
   uint256 public constant minBtcValue = 10000; // ~ approx 1$
   uint256 public tokensPerEther = 460; // 1 ETH = 460 tokens
   uint256 public tokensPerBTC = 115 * 10 ** 10 * 10 ** 2; // 1 btc = 11500 Tokens
   uint256 public constant tokenCreationMax = 10 * (10**6) * 10 ** decimals; // 10M ~ 1 Crores
   address[] public investors;

   //displays number of uniq investors
   function investorsCount() constant external returns(uint) { return investors.length; }

   function Crowdsale(uint256 _fundingStartBlock,address owner,address _wallet){
   	owner = msg.sender;
   	fundingStartBlock =_fundingStartBlock;
   	totalSupply = _totalSupply;
   	initialSupply = 0;
   	finalOwner = owner;
      wallet = _wallet;

      //check configuration if something in setup is looking weird
      if (
       tokensPerEther == 0
       || tokensPerBTC == 0
       || finalOwner == 0x0
       || wallet == 0x0
       || fundingStartBlock == 0
       || totalSupply == 0
       || tokenCreationMax == 0
       || fundingStartBlock <= block.number)
      throw;

   }

   // don't just send ether to the contract expecting to get tokens
   //function() { throw; }
   ////@dev This function manages the Crowdsale State machine
   ///We make it a function and do not assign to a variable//
   ///so that no chance of stale variable
   function getState() constant public returns(State){
   	///once we reach success lock the State
   	if(block.number<fundingStartBlock) return State.Inactive;
   	else if(block.number>fundingStartBlock && initialSupply<tokenCreationMax) return State.Funding;
   	else if (initialSupply >= tokenCreationMax) return State.Success;
   	else return State.Failure;
   }

   ///get total tokens in that address mapping
   function getTokens(address addr) public returns(uint256){
   	return balances[addr];
   }

   ///get the block number state
   function getStateFunding() public returns (uint256){
   	// average 6000 blocks mined in 24 hrs
   	if(block.number<fundingStartBlock + 180000) return 20; // 1 month 20%
   	else if(block.number>=fundingStartBlock+ 180001 && block.number<fundingStartBlock + 270000) return 10; // next 15 days
   	else if(block.number>=fundingStartBlock + 270001 && block.number<fundingStartBlock + 36000) return 5; // next 15 days
   	else return 0;
   }
   ///a function using safemath to work with
   ///the new function
   function calNewTokens(uint256 tokens) returns (uint256){
   	uint256 disc = getStateFunding();
   	tokens = safeAdd(tokens,safeDiv(safeMul(tokens,disc),100));
   	return tokens;
   }

   function() external payable stopInEmergency{
   	// Abort if not in Funding Active state.
   	if(getState() == State.Success) throw;
   	if (msg.value == 0) throw;
   	uint256 newCreatedTokens = safeMul(msg.value,tokensPerEther);
   	newCreatedTokens = calNewTokens(newCreatedTokens);
   	///since we are creating tokens we need to increase the total supply
   	initialSupply = safeAdd(initialSupply,newCreatedTokens);
   	if(initialSupply>tokenCreationMax) throw;
      if (balances[msg.sender] == 0) investors.push(msg.sender);
      investmentETH += msg.value;
      balances[msg.sender] = safeAdd(balances[msg.sender],newCreatedTokens);
      // Pocket the money
      if(!wallet.send(msg.value)) throw;
   }


   ///token distribution initial function for the one in the exchanges
   ///to be done only the owner can run this function
   function tokenAssignExchange(address addr,uint256 val)
   external
   only(finalOwner)
   {
   	if(getState() == State.Success) throw;
   	if (val == 0) throw;
   	uint256 newCreatedTokens = safeMul(val,tokensPerEther);
   	newCreatedTokens = calNewTokens(newCreatedTokens);
   	initialSupply = safeAdd(initialSupply,newCreatedTokens);
   	if(initialSupply>tokenCreationMax) throw;
      if (balances[addr] == 0) investors.push(addr);
      investmentETH += val;
      balances[addr] = safeAdd(balances[addr],newCreatedTokens);
   }

   ///function to run when the transaction has been veified
   function processTransaction(bytes txn, uint256 txHash,address addr,bytes20 btcaddr)
   external
   only(finalOwner)
   returns (uint)
   {
   	if(getState() == State.Success) throw;
   	var (output1,output2,output3,output4) = BTC.getFirstTwoOutputs(txn);
      if(transactionsClaimed[txHash]) throw;
      var (a,b) = BTC.checkValueSent(txn,btcaddr,minBtcValue);
      if(a){
         transactionsClaimed[txHash] = true;
         uint256 newCreatedTokens = safeMul(b,tokensPerBTC);
         ///since we are creating tokens we need to increase the total supply
         newCreatedTokens = calNewTokens(newCreatedTokens);
         initialSupply = safeAdd(initialSupply,newCreatedTokens);
         ///remember not to go off the LIMITS!!
         if(initialSupply>tokenCreationMax) throw;
         if (balances[addr] == 0) investors.push(addr);
         investmentBTC += b;
         balances[addr] = safeAdd(balances[addr],newCreatedTokens);
         return 1;
      }
      else return 0;
   }

   ///change exchange rate
   function changeExchangeRate(uint256 eth, uint256 btc)
   external
   only(finalOwner)
   {
    if(eth == 0 || btc == 0) throw;
    tokensPerEther = eth;
    tokensPerBTC = btc;
 }

 ///blacklist the users which are fraudulent
 ///from getting any tokens
 ///to do also refund just in cases
 function blacklist(address addr)
 external
 only(finalOwner)
 {
    balances[addr] = 0;
 }

}
function investorsCount() constant external returns(uint) { return investors.length; }

//displays number of uniq investors