contract Storage is SafeMath, StringMover {

    function Storage() public {
        controllerAddress = msg.sender;
    }

    address public controllerAddress = 0x0;
    modifier onlyController() { require(msg.sender==controllerAddress); _; }

    function setControllerAddress(address _newController) public onlyController {
        controllerAddress = _newController;
    }

    address public hotWalletAddress = 0x0;

    function setHotWalletAddress(address _address) public onlyController {
       hotWalletAddress = _address;
    }


    // Fields - 1
    mapping(uint => string) docs;
    uint public docCount = 0;

    // Fields - 2
    mapping(string => mapping(uint => int)) fiatTxs;
    mapping(string => uint) fiatBalancesCents;
    mapping(string => uint) fiatTxCounts;
    uint fiatTxTotal = 0;

    // Fields - 3
    mapping(string => mapping(uint => int)) goldTxs;
    mapping(string => uint) goldHotBalances;
    mapping(string => uint) goldTxCounts;
    uint goldTxTotal = 0;

    // Fields - 4
    struct Request {
        address sender;
        string userId;
        uint reference;
        bool buyRequest;         // otherwise - sell
        uint inputAmount;
        // 0 - init
        // 1 - processed
        // 2 - cancelled
        uint8 state;
        uint outputAmount;
    }

    mapping (uint=>Request) requests;
    uint public requestsCount = 0;

    ///////
    function addDoc(string _ipfsDocLink) public onlyController returns(uint) {
        docs[docCount] = _ipfsDocLink;
        uint out = docCount;
        docCount++;

        return out;
    }

    function getDocCount() public constant returns (uint) {
        return docCount;
    }

    function getDocAsBytes64(uint _index) public constant returns (bytes32,bytes32) {
        require(_index < docCount);
        return stringToBytes64(docs[_index]);
    }

    function addFiatTransaction(string _userId, int _amountCents) public onlyController returns(uint) {
        require(0 != _amountCents);

        uint c = fiatTxCounts[_userId];

        fiatTxs[_userId][c] = _amountCents;

        if (_amountCents > 0) {
            fiatBalancesCents[_userId] = safeAdd(fiatBalancesCents[_userId], uint(_amountCents));
        } else {
            fiatBalancesCents[_userId] = safeSub(fiatBalancesCents[_userId], uint(-_amountCents));
        }

        fiatTxCounts[_userId] = safeAdd(fiatTxCounts[_userId], 1);

        fiatTxTotal++;
        return c;
    }

    function getFiatTransactionsCount(string _userId) public constant returns (uint) {
        return fiatTxCounts[_userId];
    }

    function getAllFiatTransactionsCount() public constant returns (uint) {
        return fiatTxTotal;
    }

    function getFiatTransaction(string _userId, uint _index) public constant returns(int) {
        require(_index < fiatTxCounts[_userId]);
        return fiatTxs[_userId][_index];
    }

    function getUserFiatBalance(string _userId) public constant returns(uint) {
        return fiatBalancesCents[_userId];
    }

    function addGoldTransaction(string _userId, int _amount) public onlyController returns(uint) {
        require(0 != _amount);

        uint c = goldTxCounts[_userId];

        goldTxs[_userId][c] = _amount;

        if (_amount > 0) {
            goldHotBalances[_userId] = safeAdd(goldHotBalances[_userId], uint(_amount));
        } else {
            goldHotBalances[_userId] = safeSub(goldHotBalances[_userId], uint(-_amount));
        }

        goldTxCounts[_userId] = safeAdd(goldTxCounts[_userId], 1);

        goldTxTotal++;
        return c;
    }

    function getGoldTransactionsCount(string _userId) public constant returns (uint) {
        return goldTxCounts[_userId];
    }

    function getAllGoldTransactionsCount() public constant returns (uint) {
        return goldTxTotal;
    }

    function getGoldTransaction(string _userId, uint _index) public constant returns(int) {
        require(_index < goldTxCounts[_userId]);
        return goldTxs[_userId][_index];
    }

    function getUserHotGoldBalance(string _userId) public constant returns(uint) {
        return goldHotBalances[_userId];
    }

    function addBuyTokensRequest(address _who, string _userId, uint _reference, uint _amount) public onlyController returns(uint) {

        Request memory r;
        r.sender = _who;
        r.userId = _userId;
        r.reference = _reference;
        r.buyRequest = true;
        r.inputAmount = _amount;
        r.state = 0;

        requests[requestsCount] = r;
        uint out = requestsCount;
        requestsCount++;
        return out;
    }

    function addSellTokensRequest(address _who, string _userId, uint _reference, uint _amount) public onlyController returns(uint) {
        Request memory r;
        r.sender = _who;
        r.userId = _userId;
        r.reference = _reference;
        r.buyRequest = false;
        r.inputAmount = _amount;
        r.state = 0;

        requests[requestsCount] = r;
        uint out = requestsCount;
        requestsCount++;
        return out;
    }

    function getRequestsCount() public constant returns(uint) {
        return requestsCount;
    }

    function getRequest(uint _index) public constant returns(address, bytes32, uint, bool, uint8, uint) {
        require(_index < requestsCount);

        Request memory r = requests[_index];

        bytes32 userBytes = stringToBytes32(r.userId);

        return (r.sender, userBytes, r.reference, r.buyRequest, r.state, r.inputAmount);
    }
    
    function getRequestBaseInfo(uint _index) public constant returns(address, uint8, uint, uint) {
        require(_index < requestsCount);

        Request memory r = requests[_index];

        return (r.sender, r.state, r.inputAmount, r.outputAmount);
    }

    function cancelRequest(uint _index) onlyController public {
        require(_index < requestsCount);
        require(0==requests[_index].state);

        requests[_index].state = 2;
    }

    function setRequestFailed(uint _index) onlyController public {
        require(_index < requestsCount);
        require(0==requests[_index].state);

        requests[_index].state = 3;
    }

    function setRequestProcessed(uint _index, uint _outputAmount) onlyController public {
        require(_index < requestsCount);
        require(0==requests[_index].state);

        requests[_index].state = 1;
        requests[_index].outputAmount = _outputAmount;
    }
}
function addDoc(string _ipfsDocLink) public onlyController returns(uint) {
    docs[docCount] = _ipfsDocLink;
    uint out = docCount;
    docCount++;

    return out;
}

///////