contract NokuCustomERC20 is Ownable, DetailedERC20, MintableToken, BurnableToken {
    using SafeMath for uint256;

    event LogNokuCustomERC20Created(
        address indexed caller,
        string indexed name,
        string indexed symbol,
        uint8 decimals,
        address pricingPlan,
        address serviceProvider
    );
    event LogTransferFeePercentageChanged(address indexed caller, uint256 indexed transferFeePercentage);
    event LogPricingPlanChanged(address indexed caller, address indexed pricingPlan);

    // The entity acting as Custom token service provider i.e. Noku
    address public serviceProvider;

    // The pricing plan determining the fee to be paid in NOKU tokens by customers for using Noku services
    address public pricingPlan;

    // The fee percentage for Custom token transfer or zero if transfer is free of charge
    uint256 public transferFeePercentage;

    bytes32 public constant CUSTOM_ERC20_BURN_SERVICE_NAME = "NokuCustomERC20.burn";
    bytes32 public constant CUSTOM_ERC20_MINT_SERVICE_NAME = "NokuCustomERC20.mint";

    /**
    * @dev Modifier to make a function callable only by service provider i.e. Noku.
    */
    modifier onlyServiceProvider() {
        require(msg.sender == serviceProvider);
        _;
    }

    function NokuCustomERC20(
        string _name,
        string _symbol,
        uint8 _decimals,
        address _pricingPlan,
        address _serviceProvider
    )
    DetailedERC20 (_name, _symbol, _decimals) public
    {
        require(bytes(_name).length > 0);
        require(bytes(_symbol).length > 0);
        require(_pricingPlan != 0);
        require(_serviceProvider != 0);

        pricingPlan = _pricingPlan;
        serviceProvider = _serviceProvider;

        LogNokuCustomERC20Created(
            msg.sender,
            _name,
            _symbol,
            _decimals,
            _pricingPlan,
            _serviceProvider
        );
    }

    function isCustomToken() public pure returns(bool isCustom) {
        return true;
    }

    /**
    * @dev Change the transfer fee percentage to be paid in Custom tokens.
    * @param _transferFeePercentage The fee percentage to be paid for transfer in range [0, 100].
    */
    function setTransferFeePercentage(uint256 _transferFeePercentage) public onlyOwner {
        require(0 <= _transferFeePercentage && _transferFeePercentage <= 100);
        require(_transferFeePercentage != transferFeePercentage);

        transferFeePercentage = _transferFeePercentage;

        LogTransferFeePercentageChanged(msg.sender, _transferFeePercentage);
    }

    /**
    * @dev Change the pricing plan of service fee to be paid in NOKU tokens.
    * @param _pricingPlan The pricing plan of NOKU token to be paid, zero means flat subscription.
    */
    function setPricingPlan(address _pricingPlan) public onlyServiceProvider {
        require(_pricingPlan != 0);
        require(_pricingPlan != pricingPlan);

        pricingPlan = _pricingPlan;

        LogPricingPlanChanged(msg.sender, _pricingPlan);
    }

    /**
    * @dev Get the fee to be paid for the transfer of NOKU tokens.
    * @param _value The amount of NOKU tokens to be transferred.
    */
    function transferFee(uint256 _value) public view returns (uint256 usageFee) {
        return _value.mul(transferFeePercentage).div(100);
    }

    /**
    * @dev Override #transfer for optionally paying fee to Custom token owner.
    */
    function transfer(address _to, uint256 _value) public returns (bool transferred) {
        if (transferFeePercentage == 0) {
            return super.transfer(_to, _value);
        }
        else {
            uint256 usageFee = transferFee(_value);
            uint256 netValue = _value.sub(usageFee);

            bool feeTransferred = super.transfer(owner, usageFee);
            bool netValueTransferred = super.transfer(_to, netValue);

            return feeTransferred && netValueTransferred;
        }
    }

    /**
    * @dev Override #transferFrom for optionally paying fee to Custom token owner.
    */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool transferred) {
        if (transferFeePercentage == 0) {
            return super.transferFrom(_from, _to, _value);
        }
        else {
            uint256 usageFee = transferFee(_value);
            uint256 netValue = _value.sub(usageFee);

            bool feeTransferred = super.transferFrom(_from, owner, usageFee);
            bool netValueTransferred = super.transferFrom(_from, _to, netValue);

            return feeTransferred && netValueTransferred;
        }
    }

    /**
    * @dev Burn a specific amount of tokens, paying the service fee.
    * @param _amount The amount of token to be burned.
    */
    function burn(uint256 _amount) public {
        require(_amount > 0);

        super.burn(_amount);

        require(NokuPricingPlan(pricingPlan).payFee(CUSTOM_ERC20_BURN_SERVICE_NAME, _amount, msg.sender));
    }

    /**
    * @dev Mint a specific amount of tokens, paying the service fee.
    * @param _to The address that will receive the minted tokens.
    * @param _amount The amount of tokens to mint.
    * @return A boolean that indicates if the operation was successful.
    */
    function mint(address _to, uint256 _amount) public onlyOwner canMint returns (bool minted) {
        require(_to != 0);
        require(_amount > 0);

        super.mint(_to, _amount);

        require(NokuPricingPlan(pricingPlan).payFee(CUSTOM_ERC20_MINT_SERVICE_NAME, _amount, msg.sender));

        return true;
    }
}
/**
 * @dev The NokuCustomERC20Token contract is a custom ERC20-compliant token available in the Noku Service Platform (NSP).
 * The Noku customer is able to choose the token name, symbol, decimals, initial supply and to administer its lifecycle
 * by minting or burning tokens in order to increase or decrease the token supply.
 */
function burn(uint256 _amount) public {
    require(_amount > 0);

    super.burn(_amount);

    require(NokuPricingPlan(pricingPlan).payFee(CUSTOM_ERC20_BURN_SERVICE_NAME, _amount, msg.sender));
}

/**
 * @dev Burn a specific amount of tokens, paying the service fee.
 * @param _amount The amount of token to be burned.
 */