contract GamePlayerCoin is ERC23StandardToken {
    string public constant name = "Game Player Coin";
    string public constant symbol = "GPC";
    uint256 public constant decimals = 18;
    address public multisig=address(0x003f69f85bb97E221795f4c2708EA004C73378Fa); //multisig wallet, to which all contributions will be sent
    address public foundation; //owner address
    address public candidate; //owner candidate in 2-phase ownership transfer
    uint256 public hour_blocks = 212; // every hour blocks 
    uint256 public day_blocks = hour_blocks * 24 ; // every day blocks 

    mapping (address => uint256) contributions; //keeps track of ether contributions in Wei of each contributor address
    uint256 public startBlock = 4047500; //pre-crowdsale start block 
    uint256 public preEndBlock = startBlock + day_blocks * 7; // week 1 pre-crowdsale end block
    uint256 public phase1StartBlock = preEndBlock; //Crowdsale start block
    uint256 public phase1EndBlock = phase1StartBlock + day_blocks * 7; //Week 2 end block (estimate)
    uint256 public phase2EndBlock = phase1EndBlock + day_blocks * 7; //Week 3 end block (estimate)
    uint256 public phase3EndBlock = phase2EndBlock +  day_blocks * 7 ; //Week 4 end block (estimate)
    uint256 public endBlock = startBlock + day_blocks * 184; // whole crowdsale end block (184 days , 6 month)
    uint256 public crowdsaleTokenSupply = 70 * (10**6) * (10**18); //Amount of tokens for sale during crowdsale
    uint256 public bountyTokenSupply = 10 * (10**6) * (10**18); //Tokens for bounty
    uint256 public foundationTokenSupply = 20 * (10**6) * (10**18); //Tokens for Gameplayercoin team
    uint256 public crowdsaleTokenSold = 0; //Keeps track of the amount of tokens sold during the crowdsale
    uint256 public presaleEtherRaised = 0; //Keeps track of the Ether raised during the crowdsale
    
    bool public halted = false; //Halt crowdsale in emergency
    event Halt(); //Halt event
    event Unhalt(); //Unhalt event

    modifier onlyFoundation() {
        //only do if call is from owner modifier
        if (msg.sender != foundation) throw;
        _;
    }


    modifier whenNotHalted() {
        // only do when not halted modifier
        if (halted) throw;
        _;
    }

    //Constructor: set multisig crowdsale recipient wallet address and fund the foundation
    //Initialize total supply and allocate ecosystem & foundation tokens
  	function GamePlayerCoin() {
        foundation = msg.sender;
        totalSupply = bountyTokenSupply.add(foundationTokenSupply);
        balances[foundation] = totalSupply;
  	}

    //Fallback function when receiving Ether.
    function() payable {
        buy();
    }


    //Halt ICO in case of emergency.
    function halt() onlyFoundation {
        halted = true;
        Halt();
    }

    function unhalt() onlyFoundation {
        halted = false;
        Unhalt();
    }

    function buy() payable {
        buyRecipient(msg.sender);
    }

    //Allow addresses to buy token for another account
    function buyRecipient(address recipient) public payable whenNotHalted {
        if(msg.value == 0) throw;
        if(!(preCrowdsaleOn()||crowdsaleOn())) throw;//only allows during presale/crowdsale
        if(contributions[recipient].add(msg.value)>perAddressCap()) throw;//per address cap
        uint256 tokens = msg.value.mul(returnRate()); //decimals=18, so no need to adjust for unit
        if(crowdsaleTokenSold.add(tokens)>crowdsaleTokenSupply) throw;//max supply limit

        balances[recipient] = balances[recipient].add(tokens);
        totalSupply = totalSupply.add(tokens);
        presaleEtherRaised = presaleEtherRaised.add(msg.value);
        contributions[recipient] = contributions[recipient].add(msg.value);
        crowdsaleTokenSold = crowdsaleTokenSold.add(tokens);
        if(crowdsaleTokenSold == crowdsaleTokenSupply ){
            //If crowdsale token sold out, end crowdsale
            if(block.number < preEndBlock) {
                preEndBlock = block.number;
            }
            endBlock = block.number;
        }
        if (!multisig.send(msg.value)) throw; //immediately send Ether to multisig address
        Transfer(this, recipient, tokens);
    }

    //Burns the specified amount of tokens from the foundation
    //Used to burn unspent funds in foundation DAO
    function burn(uint256 _value) external onlyFoundation returns (bool) {
        balances[msg.sender] = balances[msg.sender].sub(_value);
        totalSupply = totalSupply.sub(_value);
        Transfer(msg.sender, address(0), _value);
        return true;
    }

    //2-phase ownership transfer;
    //prevent transferring ownership to non-existent addresses by accident.
    function proposeFoundationTransfer(address newFoundation) external onlyFoundation {
        //propose new owner
        candidate = newFoundation;
    }

    function cancelFoundationTransfer() external onlyFoundation {
        candidate = address(0);
    }

    function acceptFoundationTransfer() external {
        //new owner accept transfer to complete transfer
        if(msg.sender != candidate) throw;
        foundation = candidate;
        candidate = address(0);
    }

    //Allow to change the recipient multisig address
    function setMultisig(address addr) external onlyFoundation {
      	if (addr == address(0)) throw;
      	multisig = addr;
    }

    function transfer(address _to, uint256 _value, bytes _data) public  returns (bool success) {
        return super.transfer(_to, _value, _data);
    }

	  function transfer(address _to, uint256 _value) public  {
        super.transfer(_to, _value);
	  }

    function transferFrom(address _from, address _to, uint256 _value) public  {
        super.transferFrom(_from, _to, _value);
    }

    //Return rate of token against ether.
    function returnRate() public constant returns(uint256) {
        if (block.number>=startBlock && block.number<=preEndBlock) return 3000; // Week 1 Pre-crowdsale , 50% bounty
        if (block.number>=phase1StartBlock && block.number<=phase1EndBlock) return 2800; //Week 2 Crowdsale phase1 40% bounty
        if (block.number>phase1EndBlock && block.number<=phase2EndBlock) return 2600; //Week 3 Phase2 30% bounty
        if (block.number>phase2EndBlock && block.number<=phase3EndBlock) return 2400; //Week 4 Phase3 20% bounty
        return 2000;// rest days , normal 
    }

    //per address cap in Wei: 1000 ether + 1% of ether received at the given time.
    function perAddressCap() public constant returns(uint256) {
        uint256 baseline = 1000 * (10**18);
        return baseline.add(presaleEtherRaised.div(100));
    }

    function preCrowdsaleOn() public constant returns (bool) {
        //return whether presale is on according to block number
        return (block.number>=startBlock && block.number<=preEndBlock);
    }

    function crowdsaleOn() public constant returns (bool) {
        //return whether crowdsale is on according to block number
        return (block.number>=phase1StartBlock && block.number<=endBlock);
    }


    function getEtherRaised() external constant returns (uint256) {
        //getter function for etherRaised
        return presaleEtherRaised;
    }

    function getTokenSold() external constant returns (uint256) {
        //getter function for crowdsaleTokenSold
        return crowdsaleTokenSold;
    }

}
// Based in part on code by Open-Zeppelin: https://github.com/OpenZeppelin/zeppelin-solidity.git
// Based in part on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
function() payable {
        buy();
    }
//Fallback function when receiving Ether.