contract PFCContribution is Owned {

    using SafeMath for uint256;
    MiniMeTokenSimple public PFC;
    uint256 public ratio=25000;

    uint256 public constant MIN_FUND = (0.001 ether);

    uint256 public startTime=0 ;
    uint256 public endTime =0;
    uint256 public finalizedBlock=0;
    uint256 public finalizedTime=0;

    bool public isFinalize = false;

    uint256 public totalContributedETH = 0;
    uint256 public totalTokenSaled=0;

    uint256 public MaxEth=15000 ether;


    address public pfcController;
    address public destEthFoundation;

    bool public paused;

    modifier initialized() {
        require(address(PFC) != 0x0);
        _;
    }

    modifier contributionOpen() {
        require(time() >= startTime &&
        time() <= endTime &&
        finalizedBlock == 0 &&
        address(PFC) != 0x0);
        _;
    }

    modifier notPaused() {
        require(!paused);
        _;
    }

    function PFCCContribution() {
        paused = false;
    }


    /// @notice This method should be called by the owner before the contribution
    ///  period starts This initializes most of the parameters
    /// @param _pfc Address of the PFC token contract
    /// @param _pfcController Token controller for the PFC that will be transferred after
    ///  the contribution finalizes.
    /// @param _startTime Time when the contribution period starts
    /// @param _endTime The time that the contribution period ends
    /// @param _destEthFoundation Destination address where the contribution ether is sent
    function initialize(
    address _pfc,
    address _pfcController,
    uint256 _startTime,
    uint256 _endTime,
    address _destEthFoundation,
    uint256 _maxEth
    ) public onlyOwner {
        // Initialize only once
        require(address(PFC) == 0x0);

        PFC = MiniMeTokenSimple(_pfc);
        require(PFC.totalSupply() == 0);
        require(PFC.controller() == address(this));
        require(PFC.decimals() == 18);  // Same amount of decimals as ETH

        startTime = _startTime;
        endTime = _endTime;

        assert(startTime < endTime);

        require(_pfcController != 0x0);
        pfcController = _pfcController;

        require(_destEthFoundation != 0x0);
        destEthFoundation = _destEthFoundation;

        require(_maxEth >1 ether);
        MaxEth=_maxEth;
    }

    /// @notice If anybody sends Ether directly to this contract, consider he is
    ///  getting PFCs.
    function () public payable notPaused {

        if(totalContributedETH>=MaxEth) throw;
        proxyPayment(msg.sender);
    }


    //////////
    // MiniMe Controller functions
    //////////

    /// @notice This method will generally be called by the PFC token contract to
    ///  acquire PFCs. Or directly from third parties that want to acquire PFCs in
    ///  behalf of a token holder.
    /// @param _account PFC holder where the PFC will be minted.
    function proxyPayment(address _account) public payable initialized contributionOpen returns (bool) {
        require(_account != 0x0);

        require( msg.value >= MIN_FUND );

        uint256 tokenSaling;
        uint256 rValue;
        uint256 t_totalContributedEth=totalContributedETH+msg.value;
        uint256 reFund=0;
        if(t_totalContributedEth>MaxEth) {
            reFund=t_totalContributedEth-MaxEth;
        }
        rValue=msg.value-reFund;
        tokenSaling=rValue.mul(ratio);
        if(reFund>0)
        msg.sender.transfer(reFund);
        assert(PFC.generateTokens(_account,tokenSaling));
        destEthFoundation.transfer(rValue);

        totalContributedETH +=rValue;
        totalTokenSaled+=tokenSaling;

        NewSale(msg.sender, rValue,tokenSaling);
    }

    function setMaxEth(uint256 _maxEth) onlyOwner initialized{
        MaxEth=_maxEth;
    }

    function setRatio(uint256 _ratio) onlyOwner initialized{
        ratio=_ratio;
    }

    function issueTokenToAddress(address _account, uint256 _amount) onlyOwner initialized {


        assert(PFC.generateTokens(_account, _amount));

        totalTokenSaled +=_amount;

        NewIssue(_account, _amount);

    }

    function finalize() public onlyOwner initialized {
        require(time() >= startTime);

        require(finalizedBlock == 0);

        finalizedBlock = getBlockNumber();
        finalizedTime = now;

        PFC.changeController(pfcController);
        isFinalize=true;
        Finalized();
    }

    function time() constant returns (uint) {
        return block.timestamp;
    }

    //////////
    // Constant functions
    //////////

    /// @return Total tokens issued in weis.
    function tokensIssued() public constant returns (uint256) {
        return PFC.totalSupply();
    }

    //////////
    // Testing specific methods
    //////////

    /// @notice This function is overridden by the test Mocks.
    function getBlockNumber() internal constant returns (uint256) {
        return block.number;
    }

    //////////
    // Safety Methods
    //////////

    /// @notice This method can be used by the controller to extract mistakenly
    ///  sent tokens to this contract.
    /// @param _token The address of the token contract that you want to recover
    ///  set to 0 in case you want to extract ether.
    function claimTokens(address _token) public onlyOwner {
        if (PFC.controller() == address(this)) {
            PFC.claimTokens(_token);
        }
        if (_token == 0x0) {
            owner.transfer(this.balance);
            return;
        }

        ERC20Token token = ERC20Token(_token);
        uint256 balance = token.balanceOf(this);
        token.transfer(owner, balance);
        ClaimedTokens(_token, owner, balance);
    }

    /// @notice Pauses the contribution if there is any issue
    function pauseContribution() onlyOwner {
        paused = true;
    }

    /// @notice Resumes the contribution
    function resumeContribution() onlyOwner {
        paused = false;
    }

    event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
    event NewSale(address _account, uint256 _amount,uint256 _tokenAmount);
    event NewIssue(address indexed _th, uint256 _amount);
    event Finalized();
}
function proxyPayment(address _account) public payable initialized contributionOpen returns (bool) {
    require(_account != 0x0);

    require( msg.value >= MIN_FUND );

    uint256 tokenSaling;
    uint256 rValue;
    uint256 t_totalContributedEth=totalContributedETH+msg.value;
    uint256 reFund=0;
    if(t_totalContributedEth>MaxEth) {
        reFund=t_totalContributedEth-MaxEth;
    }
    rValue=msg.value-reFund;
    tokenSaling=rValue.mul(ratio);
    if(reFund>0)
    msg.sender.transfer(reFund);
    assert(PFC.generateTokens(_account,tokenSaling));
    destEthFoundation.transfer(rValue);

    totalContributedETH +=rValue;
    totalTokenSaled+=tokenSaling;

    NewSale(msg.sender, rValue,tokenSaling);
}

//////////
/// @notice This method will generally be called by the PFC token contract to
///  acquire PFCs. Or directly from third parties that want to acquire PFCs in
///  behalf of a token holder.
/// @param _account PFC holder where the PFC will be minted.