contract CHEXToken is Token { using SafeMath for uint;

    string public constant name = "CHEX Token";
    string public constant symbol = "CHX";
    uint public constant decimals = 18;
    uint public startBlock; //crowdsale start block
    uint public endBlock; //crowdsale end block

    address public founder;
    
    uint public tokenCap = 1000000000 * 10**decimals; // 1b tokens, each divided to up to 10^decimals units.
    uint public crowdsaleAllocation = tokenCap; //100% of token supply allocated for crowdsale
    uint public crowdsaleSupply = 0;

    uint public transferLockup = 5760; //no transfers until ~1 day after crowdsale ends
    bool public frozen = false;  //in case of emergency, freeze purchase of tokens

    uint public etherRaised = 0; //for reporting direct ether amount raised

    uint public constant MIN_ETHER = 1 finney; //minimum ether required to buy tokens

    function CHEXToken(address founderInput, uint startBlockInput, uint endBlockInput) {
        founder = founderInput;
        startBlock = startBlockInput;
        endBlock = endBlockInput;
    }

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

    function price() constant returns(uint) {
        if (block.number < startBlock) return 42007;
        if (block.number >= startBlock && block.number <= endBlock) {
            uint percentRemaining = pct((endBlock - block.number), (endBlock - startBlock), 3);
            return 21000 + 21 * percentRemaining;
        }
        return 21000;
    }

    function buy(address recipient) payable {
        if (frozen) revert();
        if (recipient == 0x0) revert();
        if (msg.value < MIN_ETHER) revert();

        uint tokens = msg.value.mul(price());
        uint nextTotal = totalSupply.add(tokens);

        if (nextTotal > tokenCap) revert();
        
        balances[recipient] = balances[recipient].add(tokens);

        totalSupply = nextTotal;

        if (block.number <= endBlock) {
            crowdsaleSupply = nextTotal;
            etherRaised = etherRaised.add(msg.value);
        }

        Transfer(0, recipient, tokens);
    }

    /*
    * TRANSFER LOCK
    */
    function transfer(address _to, uint256 _value) returns (bool success) {
        if (block.number <= endBlock + transferLockup && msg.sender != founder) return false;
        return super.transfer(_to, _value);
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (block.number <= endBlock + transferLockup && msg.sender != founder) return false;
        return super.transferFrom(_from, _to, _value);
    }

    function pct(uint numerator, uint denominator, uint precision) internal returns(uint quotient) {
        uint _numerator = numerator * 10 ** (precision+1);
        uint _quotient = ((_numerator / denominator) + 5) / 10;
        return (_quotient);
    }

    /*
    * FOR AUTHORIZED USE ONLY
    */
    modifier onlyInternal {
        require(msg.sender == founder);
        _;
    }

    function freeze() onlyInternal {
        frozen = true;
    }

    function unfreeze() onlyInternal {
        frozen = false;
    }

    function withdrawFunds() onlyInternal {
		if (this.balance == 0) revert();

		founder.transfer(this.balance);
	}

    function changeFounder(address _newAddress) onlyInternal {
        if (msg.sender != founder) revert();
        if (_newAddress == 0x0) revert();
        

		founder = _newAddress;
	}

}
/**
 *  @title CHEX Token
 *  @dev ERC20 compliant (see https://github.com/ethereum/EIPs/issues/20)
 */
function transfer(address _to, uint256 _value) returns (bool success) {
        if (block.number <= endBlock + transferLockup && msg.sender != founder) return false;
        return super.transfer(_to, _value);
    }
/*
 * TRANSFER LOCK
 */