contract TradeableToken is StandardToken, Ownable {
    using SafeMath for uint256;

    event Sale(address indexed buyer, uint256 amount);
    event Redemption(address indexed seller, uint256 amount);
    event DistributionError(address seller, uint256 amount);

    /**
    * State of the contract:
    * Collecting - collecting ether and tokens
    * Distribution - distribution of bought tokens and ether is in process
    */
    enum State{Collecting, Distribution}

    State   public currentState;                //Current state of the contract
    uint256 public previousPeriodRate;          //Previous rate: how many tokens one could receive for 1 ether in the last period
    uint256 public currentPeriodEndTimestamp;   //Timestamp after which no more trades are accepted and contract is waiting to start distribution
    uint256 public currentPeriodStartBlock;     //Number of block when current perions was started

    uint256 public currentPeriodRate;           //Current rate: how much tokens one should receive for 1 ether in current distribution period
    uint256 public currentPeriodEtherCollected; //How much ether was collected (to buy tokens) during current period and waiting for distribution
    uint256 public currentPeriodTokenCollected; //How much tokens was collected (to sell tokens) during current period and waiting for distribution

    mapping(address => uint256) receivedEther;  //maps address of buyer to amount of ether he sent
    mapping(address => uint256) soldTokens;     //maps address of seller to amount of tokens he sent

    uint32 constant MILLI_PERCENT_DIVIDER = 100*1000;
    uint32 public buyFeeMilliPercent;           //The buyer's fee in a thousandth of percent. So, if buyer's fee = 5%, then buyFeeMilliPercent = 5000 and if without buyer shoud receive 200 tokens with fee it will receive 200 - (200 * 5000 / MILLI_PERCENT_DIVIDER)
    uint32 public sellFeeMilliPercent;          //The seller's fee in a thousandth of percent. (see above)

    uint256 public minBuyAmount;                //Minimal amount of ether to buy
    uint256 public minSellAmount;               //Minimal amount of tokens to sell

    modifier canBuyAndSell() {
        require(currentState == State.Collecting);
        require(now < currentPeriodEndTimestamp);
        _;
    }

    function TradeableToken() public {
        currentState = State.Distribution;
        //currentPeriodStartBlock = 0;
        currentPeriodEndTimestamp = now;    //ensure that nothing can be collected until new period is started by owner
    }

    /**
    * @notice Send Ether to buy tokens
    */
    function() payable public {
        require(msg.value > 0);
        buy(msg.sender, msg.value);
    }    

    /**
    * @notice Transfer or sell tokens
    * Sells tokens transferred to this contract itself or to zero address
    * @param _to The address to transfer to or token contract address to burn.
    * @param _value The amount to be transferred.
    */
    function transfer(address _to, uint256 _value) public returns (bool) {
        if( (_to == address(this)) || (_to == 0) ){
            return sell(msg.sender, _value);
        }else{
            return super.transfer(_to, _value);
        }
    }

    /**
    * @notice Transfer tokens from one address to another  or sell them if _to is this contract or zero address
    * @param _from address The address which you want to send tokens from
    * @param _to address The address which you want to transfer to
    * @param _value uint256 the amout of tokens to be transfered
    */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        if( (_to == address(this)) || (_to == 0) ){
            var _allowance = allowed[_from][msg.sender];
            require (_value <= _allowance);
            allowed[_from][msg.sender] = _allowance.sub(_value);
            return sell(_from, _value);
        }else{
            return super.transferFrom(_from, _to, _value);
        }
    }

    /**
    * @dev Fuction called when somebody is buying tokens
    * @param who The address of buyer (who will own bought tokens)
    * @param amount The amount to be transferred.
    */
    function buy(address who, uint256 amount) canBuyAndSell internal returns(bool){
        require(amount >= minBuyAmount);
        currentPeriodEtherCollected = currentPeriodEtherCollected.add(amount);
        receivedEther[who] = receivedEther[who].add(amount);  //if this is first operation from this address, initial value of receivedEther[to] == 0
        Sale(who, amount);
        return true;
    }

    /**
    * @dev Fuction called when somebody is selling his tokens
    * @param who The address of seller (whose tokens are sold)
    * @param amount The amount to be transferred.
    */
    function sell(address who, uint256 amount) canBuyAndSell internal returns(bool){
        require(amount >= minSellAmount);
        currentPeriodTokenCollected = currentPeriodTokenCollected.add(amount);
        soldTokens[who] = soldTokens[who].add(amount);  //if this is first operation from this address, initial value of soldTokens[to] == 0
        totalSupply = totalSupply.sub(amount);
        Redemption(who, amount);
        Transfer(who, address(0), amount);
        return true;
    }
    /**
    * @notice Set fee applied when buying tokens
    * @param _buyFeeMilliPercent fee in thousandth of percent (5% = 5000)
    */
    function setBuyFee(uint32 _buyFeeMilliPercent) onlyOwner public {
        require(_buyFeeMilliPercent < MILLI_PERCENT_DIVIDER);
        buyFeeMilliPercent = _buyFeeMilliPercent;
    }
    /**
    * @notice Set fee applied when selling tokens
    * @param _sellFeeMilliPercent fee in thousandth of percent (5% = 5000)
    */
    function setSellFee(uint32 _sellFeeMilliPercent) onlyOwner public {
        require(_sellFeeMilliPercent < MILLI_PERCENT_DIVIDER);
        sellFeeMilliPercent = _sellFeeMilliPercent;
    }
    /**
    * @notice set minimal amount of ether which can be used to buy tokens
    * @param _minBuyAmount minimal amount of ether
    */
    function setMinBuyAmount(uint256 _minBuyAmount) onlyOwner public {
        minBuyAmount = _minBuyAmount;
    }
    /**
    * @notice set minimal amount of ether which can be used to buy tokens
    * @param _minSellAmount minimal amount of tokens
    */
    function setMinSellAmount(uint256 _minSellAmount) onlyOwner public {
        minSellAmount = _minSellAmount;
    }

    /**
    * @notice Collect ether received for token purshases
    * This is possible both during Collection and Distribution phases
    */
    function collectEther(uint256 amount) onlyOwner public {
        owner.transfer(amount);
    }

    /**
    * @notice Start distribution phase
    * @param _currentPeriodRate exchange rate for current distribution
    */
    function startDistribution(uint256 _currentPeriodRate) onlyOwner public {
        require(currentState != State.Distribution);    //owner should not be able to change rate after distribution is started, ensures that everyone have the same rate
        require(_currentPeriodRate != 0);                //something has to be distributed!
        //require(now >= currentPeriodEndTimestamp)     //DO NOT require period end timestamp passed, because there can be some situations when it is neede to end it sooner. But this should be done with extremal care, because of possible race condition between new sales/purshases and currentPeriodRate definition

        currentState = State.Distribution;
        currentPeriodRate = _currentPeriodRate;
    }

    /**
    * @notice Distribute tokens to buyers
    * @param buyers an array of addresses to pay tokens for their ether. Should be composed from outside by reading Sale events 
    */
    function distributeTokens(address[] buyers) onlyOwner public {
        require(currentState == State.Distribution);
        require(currentPeriodRate > 0);
        for(uint256 i=0; i < buyers.length; i++){
            address buyer = buyers[i];
            require(buyer != address(0));
            uint256 etherAmount = receivedEther[buyer];
            if(etherAmount == 0) continue; //buyer not found or already paid
            uint256 tokenAmount = etherAmount.mul(currentPeriodRate);
            uint256 fee = tokenAmount.mul(buyFeeMilliPercent).div(MILLI_PERCENT_DIVIDER);
            tokenAmount = tokenAmount.sub(fee);
            
            receivedEther[buyer] = 0;
            currentPeriodEtherCollected = currentPeriodEtherCollected.sub(etherAmount);
            //mint tokens
            totalSupply = totalSupply.add(tokenAmount);
            balances[buyer] = balances[buyer].add(tokenAmount);
            Transfer(address(0), buyer, tokenAmount);
        }
    }

    /**
    * @notice Distribute ether to sellers
    * If not enough ether is available on contract ballance
    * @param sellers an array of addresses to pay ether for their tokens. Should be composed from outside by reading Redemption events 
    */
    function distributeEther(address[] sellers) onlyOwner payable public {
        require(currentState == State.Distribution);
        require(currentPeriodRate > 0);
        for(uint256 i=0; i < sellers.length; i++){
            address seller = sellers[i];
            require(seller != address(0));
            uint256 tokenAmount = soldTokens[seller];
            if(tokenAmount == 0) continue; //seller not found or already paid
            uint256 etherAmount = tokenAmount.div(currentPeriodRate);
            uint256 fee = etherAmount.mul(sellFeeMilliPercent).div(MILLI_PERCENT_DIVIDER);
            etherAmount = etherAmount.sub(fee);
            
            soldTokens[seller] = 0;
            currentPeriodTokenCollected = currentPeriodTokenCollected.sub(tokenAmount);
            if(!seller.send(etherAmount)){
                //in this case we can only log error and let owner to handle it manually
                DistributionError(seller, etherAmount);
                owner.transfer(etherAmount); //assume this should not fail..., overwise - change owner
            }
        }
    }

    function startCollecting(uint256 _collectingEndTimestamp) onlyOwner public {
        require(_collectingEndTimestamp > now);      //Need some time for collection
        require(currentState == State.Distribution);    //Do not allow to change collection terms after it is started
        require(currentPeriodEtherCollected == 0);      //All sold tokens are distributed
        require(currentPeriodTokenCollected == 0);      //All redeemed tokens are paid
        previousPeriodRate = currentPeriodRate;
        currentPeriodRate = 0;
        currentPeriodStartBlock = block.number;
        currentPeriodEndTimestamp = _collectingEndTimestamp;
        currentState = State.Collecting;
    }
}
/**
 * @title TradeableToken can be bought and sold from/to it's own contract during it's life time
 * Sold tokens and Ether received to buy tokens are collected during specified period and then time comes
 * contract owner should specify price for the last period and send tokens/ether to their new owners.
 */
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
    if( (_to == address(this)) || (_to == 0) ){
        var _allowance = allowed[_from][msg.sender];
        require (_value <= _allowance);
        allowed[_from][msg.sender] = _allowance.sub(_value);
        return sell(_from, _value);
    }else{
        return super.transferFrom(_from, _to, _value);
    }
}

/**
 * @notice Transfer tokens from one address to another  or sell them if _to is this contract or zero address
 * @param _from address The address which you want to send tokens from
 * @param _to address The address which you want to transfer to
 * @param _value uint256 the amout of tokens to be transfered
 */