contract CSCResourceFactory is OperationalControl, StringHelpers {

    event CSCResourceCreated(string resourceContract, address contractAddress, uint256 amount); 

    mapping(uint16 => address) public resourceIdToAddress; 
    mapping(bytes32 => address) public resourceNameToAddress; 
    mapping(uint16 => bytes32) public resourceIdToName; 

    uint16 resourceTypeCount;

    function CSCResourceFactory() public {
        managerPrimary = msg.sender;
        managerSecondary = msg.sender;
        bankManager = msg.sender;

    }

    function createNewCSCResource(string _name, string _symbol, uint _initialSupply) public anyOperator {

        require(resourceNameToAddress[stringToBytes32(_name)] == 0x0);

        address resourceContract = new CSCResource(_name, _symbol, _initialSupply);

        
        resourceIdToAddress[resourceTypeCount] = resourceContract;
        resourceNameToAddress[stringToBytes32(_name)] = resourceContract;
        resourceIdToName[resourceTypeCount] = stringToBytes32(_name);
        
        emit CSCResourceCreated(_name, resourceContract, _initialSupply);

        //Inc. for next resource
        resourceTypeCount += 1;

    }

    function setResourcesPrimaryManager(address _op) public onlyManager {
        
        require(_op != address(0));

        uint16 totalResources = getResourceCount();

        for(uint16 i = 0; i < totalResources; i++) {
            CSCResource resContract = CSCResource(resourceIdToAddress[i]);
            resContract.setPrimaryManager(_op);
        }

    }

    function setResourcesSecondaryManager(address _op) public onlyManager {

        require(_op != address(0));

        uint16 totalResources = getResourceCount();

        for(uint16 i = 0; i < totalResources; i++) {
            CSCResource resContract = CSCResource(resourceIdToAddress[i]);
            resContract.setSecondaryManager(_op);
        }

    }

    function setResourcesBanker(address _op) public onlyManager {

        require(_op != address(0));

        uint16 totalResources = getResourceCount();

        for(uint16 i = 0; i < totalResources; i++) {
            CSCResource resContract = CSCResource(resourceIdToAddress[i]);
            resContract.setBanker(_op);
        }

    }

    function setResourcesOtherManager(address _op, uint8 _state) public anyOperator {

        require(_op != address(0));

        uint16 totalResources = getResourceCount();

        for(uint16 i = 0; i < totalResources; i++) {
            CSCResource resContract = CSCResource(resourceIdToAddress[i]);
            resContract.setOtherManager(_op, _state);
        }

    }

    function withdrawFactoryResourceBalance(uint16 _resId) public onlyBanker {

        require(resourceIdToAddress[_resId] != 0);

        CSCResource resContract = CSCResource(resourceIdToAddress[_resId]);
        uint256 resBalance = resContract.balanceOf(this);
        resContract.transfer(bankManager, resBalance);

    }

    function transferFactoryResourceAmount(uint16 _resId, address _to, uint256 _amount) public onlyBanker {

        require(resourceIdToAddress[_resId] != 0);
        require(_to != address(0));

        CSCResource resContract = CSCResource(resourceIdToAddress[_resId]);
        uint256 resBalance = resContract.balanceOf(this);
        require(resBalance >= _amount);

        resContract.transfer(_to, _amount);
    }

    function mintResource(uint16 _resId, uint256 _amount) public onlyBanker {

        require(resourceIdToAddress[_resId] != 0);
        CSCResource resContract = CSCResource(resourceIdToAddress[_resId]);
        resContract.mint(this, _amount);
    }

    function burnResource(uint16 _resId, uint256 _amount) public onlyBanker {

        require(resourceIdToAddress[_resId] != 0);
        CSCResource resContract = CSCResource(resourceIdToAddress[_resId]);
        resContract.burn(_amount);
    }

    function getResourceName(uint16 _resId) public view returns (bytes32 name) {
        return resourceIdToName[_resId];
    }

    function getResourceCount() public view returns (uint16 resourceTotal) {
        return resourceTypeCount;
    }

    function getResourceBalance(uint16 _resId, address _wallet) public view returns (uint256 amt) {

        require(resourceIdToAddress[_resId] != 0);

        CSCResource resContract = CSCResource(resourceIdToAddress[_resId]);
        return resContract.balanceOf(_wallet);

    }

    /**
    * @dev helps in fetching the wallet resouce balance
    * @param _wallet The wallet address
    */
    function getWalletResourceBalance(address _wallet) external view returns(uint256[] resourceBalance){
        require(_wallet != address(0));
        
        uint16 totalResources = getResourceCount();
        
        uint256[] memory result = new uint256[](totalResources);
        
        for(uint16 i = 0; i < totalResources; i++) {
            CSCResource resContract = CSCResource(resourceIdToAddress[i]);
            result[i] = resContract.balanceOf(_wallet);
        }
        
        return result;
    }

}
function getWalletResourceBalance(address _wallet) external view returns(uint256[] resourceBalance){
    require(_wallet != address(0));
        
    uint16 totalResources = getResourceCount();
        
    uint256[] memory result = new uint256[](totalResources);
        
    for(uint16 i = 0; i < totalResources; i++) {
        CSCResource resContract = CSCResource(resourceIdToAddress[i]);
        result[i] = resContract.balanceOf(_wallet);
    }
        
    return result;
}

/**
 * @dev helps in fetching the wallet resouce balance
 * @param _wallet The wallet address
 */