if ( typeof browser == 'undefined' )
{
    browser = chrome;
}

var manifestV = 2;

var _agnia = {};
_agnia.providers = {};
_agnia.providers2 = {};

if ( typeof window == 'undefined' || manifestV == 3 )
{
    manifestV = 3;
    window = {};
    document = {};
    window.Promise = Promise;
    importScripts ( './httpRequest.js' , './vendor/pbkdf2.js' , './vendor/aes.js' , './vendor/sha3.js' , './vendor/sha256.js' , './vendor/eth-crypto.js' );
    window.crypto = crypto;
    importScripts ( './vendor/web3.min.js' , './vendor/string.js' , "./vendor/ethereumjs-util.js" , "./vendor/eciesjs.js" , "./jwt.js" , "./conf.js" , "./i18n.js" , "./i18n-functions.js" , "./files.js" , "./providers/double-opt-in.js" , "./providers/certificate-esp.js" , "./providers/uned.js" , "./providers/agnia_verifier.js" , "./providers/barclays.js" );
    Web3 = window.Web3;
    EthJS = window.EthJS;
}

var icon_locked = 'icons/icon96_locked.png';
var icon_unlocked = 'icons/icon96.png';
if ( typeof skin_icon_locked != 'undefined' && skin_icon_locked != '' )
{
    icon_locked = skin_icon_locked;
}    
if ( typeof skin_icon_unlocked != 'undefined' && skin_icon_unlocked != '' )
{
    icon_unlocked = skin_icon_unlocked;
}    

if ( manifestV == 3 )
{
    browser.action.setIcon ( { path: '../' + icon_locked } );
}
else
{
    browser.browserAction.setIcon ( { path: icon_locked } );
}

_agnia.web3 = new Web3();

_agnia.context = null;
_agnia.context_processed = null;


_agnia.saveContext = function()
{
    if ( manifestV == 3 )
    {
        browser.storage.session.set ( { '_agnia_context': _agnia.context } );
    }
}

_agnia.initContext = function ( callback )
{
    console.log ( 'Leemos context' );
    if ( manifestV == 2 )
    {
        _agnia.context = {};
        _agnia.context.password = null;
        _agnia.context.wallet_name = null;
        _agnia.context.cryptedWallet = null;
        _agnia.context.wallet = null;
        _agnia.context.popupStatus = {};
        _agnia.context.tabIds = {};
        _agnia.context.cameraRequested = false;
        _agnia.context.dids = {};
        _agnia.context_processed = {};
        _agnia.context_processed.fieldsIdx = null;
        _agnia.context_processed.permissionsIdx = null;
        _agnia.context_processed.sendResponseFunctions = {};
        callback();
    }
    else if ( manifestV == 3 )
    {
        browser.storage.session.get ( '_agnia_context' , function ( context )
        {
            if ( typeof context == 'undefined' )
            {
                _agnia.context = {};
                _agnia.context.password = null;
                _agnia.context.wallet_name = null;
                _agnia.context.cryptedWallet = null;
                _agnia.context.wallet = null;
                _agnia.context.popupStatus = {};
                _agnia.context.tabIds = {};
                _agnia.context.cameraRequested = false;
                _agnia.context.dids = {};
                _agnia.context_processed = {};
                _agnia.context_processed.fieldsIdx = null;
                _agnia.context_processed.permissionsIdx = null;
                _agnia.context_processed.sendResponseFunctions = {};
            }
            else if ( typeof context['_agnia_context'] == 'undefined' )
            {
                _agnia.context = {};
                _agnia.context.password = null;
                _agnia.context.wallet_name = null;
                _agnia.context.cryptedWallet = null;
                _agnia.context.wallet = null;
                _agnia.context.popupStatus = {};
                _agnia.context.tabIds = {};
                _agnia.context.cameraRequested = false;
                _agnia.context.dids = {};
                _agnia.context_processed = {};
                _agnia.context_processed.fieldsIdx = null;
                _agnia.context_processed.permissionsIdx = null;
                _agnia.context_processed.sendResponseFunctions = {};
            }
            else
            {
                _agnia.context = context['_agnia_context'];
                _agnia.context_processed = {};
                _agnia.context_processed.fieldsIdx = {};
                _agnia.context_processed.permissionsIdx = {};
                _agnia.context_processed.sendResponseFunctions = {};
                _agnia.processContext();
            }
            _agnia.context.dids = {};
            callback();
        } );
    }
}

_agnia.getDid = function ( did , callback )
{
    if ( typeof _agnia.context.dids[did] != 'undefined' )
    {
        callback ( { errnum: 0 , data: _agnia.context.dids[did] } )
    }
    else
    {
        postData ( {
            url: getDidUrl ,
            method: 'POST',
            data: {
                did: did
            },
            complete: function ( resp , status )
            {
                if ( status == 'success' )
                {
                    var data = resp.responseJSON;
                    if ( data.errnum == 0 && typeof data.data != 'undefined' )
                    {
                        if ( typeof data.proof == 'undefined' )
                        {
                            callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) } );
                            return;
                        }
                        if ( ! jwt.validateResponseProof ( data.data , data.proof , didsStorageDid ) )
                        {
                            callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) } );
                            return;
                        }
                        _agnia.context.dids[did] = data.data.data;
                        callback ( { errnum: 0 , data: _agnia.context.dids[did] } );
                    }
    
                }
                else
                {
                    callback ( { errnum: 3 } );
                }
            }
        } );

    }
}

_agnia.processContext = function()
{
    for ( var name in  _agnia.context.wallet )
    {
        let account2 = {};
        account2.data = _agnia.context.wallet[name].data;
        account2.wallet_name = _agnia.context.wallet[name].wallet_name;
        _agnia.context_processed.fieldsIdx = {};
        for ( var dataType in account2.data.attributes )
        {
            for ( var i = 0 ; i < account2.data.attributes[dataType].length ; i++ )
            {
                _agnia.context_processed.fieldsIdx[account2.data.attributes[dataType][i].key] = account2.data.attributes[dataType][i];
            }
        }
        _agnia.context_processed.permissionsIdx = {};
        for ( var i = 0 ; i < account2.data.permissions.length ; i++ )
        {
            _agnia.context_processed.permissionsIdx[account2.data.permissions[i].key] = account2.data.permissions[i];
        }
    }
}

_agnia.internal_cmds = {};
_agnia.internal_cmds.open = function ( params )
{
    if ( typeof params.url != 'undefined' && params.url != '' )
    {
        browser.tabs.query ( { url: browser.runtime.getURL ( '/*' ) } ,
            function ( tabs )
            {
                if ( tabs.length == 0 )
                {
                    browser.tabs.create (
                        {
                            url: browser.runtime.getURL ( params.url )
                        }
                    );
                }
                else
                {
                    browser.tabs.remove ( tabs[0].id );
                    browser.tabs.create (
                        {
                            url: browser.runtime.getURL ( params.url )
                        }
                    );
                }
            }
        );
    }
    return null;
}
_agnia.internal_cmds.getWallet = function ( params , sendResponse )
{
    if ( _agnia.context.wallet != null )
    {
        if ( _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == true && typeof _agnia.context.lastDownload != 'undefined' && new Date().getTime() - _agnia.context.lastDownload > remoteCacheTime * 1000 )
        {
            _agnia.getRemoteWallet ( function ( resp ) 
            {
                if ( typeof resp != 'undefined' && typeof resp.errnum != 'undefined' && resp.errnum === 0 )
                {
                    sendResponse ( { errnum: 0 , data: _agnia.context.wallet[_agnia.context.wallet_name] , returnData: params.returnData } );
                }
                else
                {
                    sendResponse ( { errnum: 4 } );
                }
            } );
        }
        else
        {
            sendResponse ( { errnum: 0 , data: _agnia.context.wallet[_agnia.context.wallet_name] , returnData: params.returnData } );
        }
    }
    else
    {
        browser.storage.local.get ( 'wallet' , function ( res )
        {
            if ( typeof res['wallet'] == 'undefined' )
            {
                sendResponse ( { errnum: 1 } );
            }
            else
            {
                _agnia.context.cryptedWallet = res['wallet'];
                if ( _agnia.context.password === null )
                {
                    _agnia.saveContext();
                    sendResponse ( { errnum: 2 } );
                }
                else
                {
                    _agnia.context.wallet_name = Object.keys ( _agnia.context.cryptedWallet )[0];
                    var decrypted = _agnia.decrypt ( _agnia.context.cryptedWallet[_agnia.context.wallet_name] , _agnia.context.password );
                    if ( decrypted === null )
                    {
                        _agnia.context.password = null
                        _agnia.saveContext();
                        sendResponse ( { errnum: 3 } );
                    }
                    else
                    {
                        try
                        {
                            var parsed = JSON.parse ( decrypted );
                            if ( typeof parsed == 'object' )
                            {
                                if ( manifestV == 3 )
                                {
                                    browser.action.setIcon ( { path: '../' + icon_unlocked } );
                                }
                                else
                                {
                                    browser.browserAction.setIcon ( { path: icon_unlocked } );
                                }
                                if ( _agnia.context.wallet === null )
                                {
                                    _agnia.context.wallet = {};
                                }
                                _agnia.context.wallet[_agnia.context.wallet_name] = parsed;
                                if ( typeof _agnia.context.wallet[_agnia.context.wallet_name].config == 'undefined' )
                                {
                                    _agnia.context.wallet[_agnia.context.wallet_name].config = { remote_storage: false };
                                }
                                if ( _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == true )
                                {
                                    _agnia.getRemoteWallet ( function ( resp ) 
                                    {
                                        if ( typeof resp != 'undefined' && typeof resp.errnum != 'undefined' && resp.errnum === 0 )
                                        {
                                            sendResponse ( { errnum: 0 , data: _agnia.context.wallet[_agnia.context.wallet_name] , returnData: params.returnData } );
                                        }
                                        else
                                        {
                                            sendResponse ( { errnum: 4 } );
                                        }
                                    } );
                                }
                                else
                                {
                                    _agnia.context_processed.fieldsIdx = {};
                                    _agnia.context_processed.permissionsIdx = {};
                                    _agnia.processContext();
                                    _agnia.saveContext();
                                    sendResponse ( { errnum: 0 , data: _agnia.context.wallet[_agnia.context.wallet_name] , returnData: params.returnData } );
                                }
                            }
                        }
                        catch
                        {
                            _agnia.saveContext();
                            sendResponse ( { errnum: 3 } );
                        }
                    }
                }
            }
        } );
    }
}
_agnia.internal_cmds.getProviders = function ( params , sendResponse )
{
    if ( _agnia.providers != null )
    {
        sendResponse ( { errnum: 0 , data: _agnia.providers } );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}
_agnia.internal_cmds.getPopupStatus = function ( params , sendResponse )
{
    sendResponse ( { errnum: 0 , data: _agnia.context.popupStatus } );
}
_agnia.internal_cmds.savePopupStatus = function ( params , sendResponse )
{
    _agnia.context.popupStatus = params;
    _agnia.saveContext();
    sendResponse ( { errnum: 0 } );
}
_agnia.internal_cmds.getCameraAccess = function ( params , sendResponse )
{
    if ( _agnia.context.cameraRequested === true )
    {
        sendResponse ( { errnum: 0 } );
    }
    else
    {
        browser.storage.local.get ( 'cameraRequested' , function ( res )
        {
            if ( typeof res['cameraRequested'] == 'undefined' || !res['cameraRequested'] )
            {
                _agnia.context_processed.sendResponseFunctions.getCameraAccess = sendResponse;
                browser.tabs.create ( { url: browser.runtime.getURL ( 'test-camera-access.html' ) } , function ( tab ) 
                {
                    _agnia.context.tabIds.getCameraAccess = tab.id;
                    _agnia.saveContext();
                } );
            }
            else
            {
                sendResponse ( { errnum: 0 } );
            }
        } );
    }
}
_agnia.internal_cmds.cameraUnlocked = function ( params , sendResponse )
{
    if ( typeof _agnia.context.tabIds.getCameraAccess != 'undefined' )
    {
        browser.tabs.remove ( _agnia.context.tabIds.getCameraAccess );
        delete _agnia.context.tabIds.getCameraAccess;
    }
    if ( typeof params.errnum != 'undefined' && params.errnum === 0 )
    {
        _agnia.context.cameraRequested = true;
        browser.storage.local.set ( { 'cameraRequested': true } );
    }
    if ( typeof _agnia.context_processed.sendResponseFunctions.getCameraAccess != 'undefined' )
    {
        _agnia.context_processed.sendResponseFunctions.getCameraAccess ( params );
        delete _agnia.context_processed.sendResponseFunctions.getCameraAccess;
    }
    _agnia.saveContext();
}

_agnia.internal_cmds.createWallet = function ( params , sendResponse )
{
    if ( _agnia.context.password === null && _agnia.context.cryptedWallet === null && _agnia.context.wallet === null && typeof params.wallet_name == 'string' && typeof params.password == 'string' )
    {
        let account = {};
        let account2 = {};
        var keys = _agnia.web3.eth.accounts.create();
        account.did = jwt.keysToDid ( keys );
        account.did.verificationMethod[0].privateKeyHex = keys.privateKey;

        var requestData = {};
        requestData['params'] = {};
        requestData['params'] = { 'did': jwt.keysToDid ( keys ) };
        requestData['timestamp'] = ( new Date() ).getTime() / 1000;

        postData ( {
            url: saveDidUrl ,
            method: 'POST',
            data: {
                data: serializeObject ( requestData ),
                proof: serializeObject ( jwt.createRequestProof ( requestData , account.did ) ),
                did: account.did.id
            },
            complete: function ( resp , status )
            {
                if ( status == 'success' )
                {
                    var data = resp.responseJSON;
                    if ( data.errnum == 0 && typeof data.data != 'undefined' )
                    {
                        if ( typeof data.proof == 'undefined' )
                        {
                            sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                            return;
                        }
                        if ( ! jwt.validateResponseProof ( data.data , data.proof , didsStorageDid ) )
                        {
                            sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                            return;
                        }
                        account.data = { attributes: {}, profiles: [] , permissions: [] };
                        account.wallet_name = params.wallet_name;
                        account.config = {};
                        account2.data = account.data;
                        account2.wallet_name = account.wallet_name;
                        _agnia.context.wallet = {};
                        _agnia.context.wallet[params.wallet_name] = account;
                        _agnia.context.wallet_name = params.wallet_name;
                        _agnia.context_processed.fieldsIdx = {};
                        _agnia.context_processed.permissionsIdx = {};
                        _agnia.context.password = params.password;
                        _agnia.saveWallet();
                        if ( manifestV == 3 )
                        {
                            browser.action.setIcon ( { path: '../' + icon_unlocked } );
                        }
                        else
                        {
                            browser.browserAction.setIcon ( { path: icon_unlocked } );
                        }
                        sendResponse ( { errnum: 0 } );
                    }
    
                }
                else
                {
                    sendResponse ( { errnum: 2 } );
                }
            }
        } );
    
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.unlock = function ( params , sendResponse )
{
    if ( _agnia.context.password === null && typeof params.password == 'string' )
    {
        _agnia.context.password = params.password;
        _agnia.saveContext();
        sendResponse ( { errnum: 0 } );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.lock = function ( params , sendResponse )
{
    _agnia.context.password = null;
    _agnia.context.wallet_name = null;
    _agnia.context.cryptedWallet = null;
    _agnia.context.wallet = null;
    _agnia.context.popupStatus = {};
    if ( manifestV == 3 )
    {
        browser.action.setIcon ( { path: '../' + icon_locked } );
    }
    else
    {
        browser.browserAction.setIcon ( { path: icon_locked } );
    }
    _agnia.saveContext();
    sendResponse ( { errnum: 0 } );
}

_agnia.internal_cmds.saveRemoteConfig = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof _agnia.context.wallet_name != 'undefined' && _agnia.context.wallet_name != '' && typeof _agnia.context.wallet[_agnia.context.wallet_name] != 'undefined' && typeof params != 'undefined' && typeof params['remote_storage'] != 'undefined' )
    {
        if ( typeof _agnia.context.wallet[_agnia.context.wallet_name].config != 'undefined' && typeof _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage != 'undefined' && _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == true && params['remote_storage'] == false )
        {
            console.log ( 'Pasamos el wallet a local' );
            sendResponse ( { errnum: 0 , returnData: params['returnData'] } );
            _agnia.downloadWallet();
        }
        else if ( ( typeof _agnia.context.wallet[_agnia.context.wallet_name].config == 'undefined' || typeof _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == 'undefined' || _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == false ) && params['remote_storage'] == true )
        {
            console.log ( 'Pasamos el wallet a remoto' );
            sendResponse ( { errnum: 0 , returnData: params['returnData'] } );
            _agnia.uploadWallet();
        }
        else
        {
            sendResponse ( { errnum: 2 , returnData: params['returnData'] } );
        }
    }
    else
    {
        sendResponse ( { errnum: 1 , returnData: params['returnData'] } );
    }
}

_agnia.internal_cmds.loadFile = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['key'] != 'undefined' )
    {
        loadFile ( params['key'] , function ( data ) 
        {
            sendResponse ( { errnum: 0 , data: data , returnData: params['returnData'] } );
        } );
    }
    else
    {
        sendResponse ( { errnum: 1 , returnData: params['returnData'] } );
    }
}

_agnia.internal_cmds.importWallet = function ( params , sendResponse )
{
    if ( _agnia.context.password === null && _agnia.context.cryptedWallet === null && _agnia.context.wallet === null && typeof params.wallet_name == 'string' && typeof params.password == 'string' && typeof params.imported_wallet == 'string' && typeof params.file_password == 'string' )
    {
        var imported_wallet = _agnia.decrypt ( params.imported_wallet , params.file_password );
        if ( imported_wallet == null )
        {
            sendResponse ( { errnum: 2 } );
        }
        else
        {
            try
            {
                imported_wallet = JSON.parse ( imported_wallet );
                if ( typeof imported_wallet.wallet != 'undefined' )
                {
                    _agnia.context.wallet = {};
                    _agnia.context.password = params.password;
                    _agnia.context.wallet_name = params.wallet_name;
                    imported_wallet.wallet.wallet_name = params.wallet_name;
                    _agnia.context.wallet[_agnia.context.wallet_name] = imported_wallet.wallet;
                    if ( typeof imported_wallet.files == 'object' )
                    {
                        for ( var fileKey in imported_wallet.files )
                        {
                            saveFile ( imported_wallet.files[fileKey].name , imported_wallet.files[fileKey].type , imported_wallet.files[fileKey].data , fileKey )
                        }
                    }
                    if ( _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == true )
                    {
                        _agnia.getRemoteWallet ( function ( resp ) 
                        {
                            if ( typeof resp != 'undefined' && typeof resp.errnum != 'undefined' && resp.errnum === 0 )
                            {
                                if ( manifestV == 3 )
                                {
                                    browser.action.setIcon ( { path: '../' + icon_unlocked } );
                                }
                                else
                                {
                                    browser.browserAction.setIcon ( { path: icon_unlocked } );
                                }
                                _agnia.saveWallet()
                                sendResponse ( { errnum: 0 } );
                            }
                            else
                            {
                                sendResponse ( { errnum: 4 } );
                            }
                        } );
                    }
                    else
                    {
                        _agnia.context_processed.fieldsIdx = {};
                        _agnia.context_processed.permissionsIdx = {};
                        _agnia.processContext();
                        _agnia.saveContext();
                        if ( manifestV == 3 )
                        {
                            browser.action.setIcon ( { path: '../' + icon_unlocked } );
                        }
                        else
                        {
                            browser.browserAction.setIcon ( { path: icon_unlocked } );
                        }
                        _agnia.saveWallet()
                        sendResponse ( { errnum: 0 } );
                    }
                }
                else
                {
                    sendResponse ( { errnum: 4 } );
                }
            }
            catch (exception)
            {
                _agnia.context = {};
                console.log ( exception );
                sendResponse ( { errnum: 3 } );
            }
        }
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.exportWallet = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['wallet_name'] != 'undefined' && params['wallet_name'] != '' && typeof _agnia.context.wallet[params['wallet_name']] != 'undefined' && typeof params['password'] != 'undefined' )
    {
        if ( _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == true && (typeof params['full_export'] == 'undefined' || params['full_export'] == false ) )
        {
            var aux_wallet = {};
            for ( var key in _agnia.context.wallet[_agnia.context.wallet_name] )
            {
                if ( key == 'did' || key == 'config' )
                {
                    aux_wallet[key] = _agnia.context.wallet[_agnia.context.wallet_name][key];
                }
            }
            var exported_wallet = _agnia.encrypt ( JSON.stringify ( { wallet: aux_wallet } ) , params['password'] );
            sendResponse ( { errnum: 0 , data: { exported_wallet: exported_wallet } , returnData: params['returnData'] } );
        }
        else
        {
            var filesList = _agnia.getFilesList();
            var files = {};
            loadFiles ( filesList , 0 , files , function () 
            {
                var exported_wallet = _agnia.encrypt ( JSON.stringify ( { wallet: _agnia.context.wallet[_agnia.context.wallet_name] , files: files } ) , params['password'] );
                sendResponse ( { errnum: 0 , data: { exported_wallet: exported_wallet } , returnData: params['returnData'] } );
            } );
        }

    }

}

_agnia.internal_cmds.addClaim = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['wallet_name'] != 'undefined' && params['wallet_name'] != '' && typeof _agnia.context.wallet[params['wallet_name']] != 'undefined' && typeof params['claim'] != 'undefined' )
    {
        var meta_claim = params.claim;
        var claim = meta_claim.claim;
        var key;
        do
        {
            key = _agnia.getKey();
        }
        while ( typeof _agnia.context_processed.fieldsIdx[key] != 'undefined' );
        meta_claim['key'] = key;
        var data_type = claim['type'][claim['type'].length - 1];
        if ( typeof _agnia.context.wallet[params['wallet_name']].data.attributes[data_type] == 'undefined' )
        {
            _agnia.context.wallet[params['wallet_name']].data.attributes[data_type] = [];
        }
        for ( var key in claim['credentialSubject'] )
        {
            if ( typeof claim['credentialSubject'][key] == 'object' && typeof claim['credentialSubject'][key]['name'] != 'undefined' && typeof claim['credentialSubject'][key]['type'] != 'undefined' && typeof claim['credentialSubject'][key]['data'] != 'undefined' )
            {
                claim['credentialSubject'][key].file_key = saveFile ( claim['credentialSubject'][key].name , claim['credentialSubject'][key].type , claim['credentialSubject'][key].data );
                delete claim['credentialSubject'][key].data;
            }
        }
        _agnia.context.wallet[params['wallet_name']].data.attributes[data_type].push ( meta_claim );
        _agnia.context_processed.fieldsIdx[key] = meta_claim;
        _agnia.saveWallet ( 
            function()
            {
                sendResponse ( { errnum: 0 , data: meta_claim } );
            },
            function()
            {
                sendResponse ( { errnum: 2 } );
            },
            function()
            {
                _agnia.internal_cmds.addClaim ( params , sendResponse );
            }
        );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.deleteClaim = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['wallet_name'] != 'undefined' && params['wallet_name'] != '' && typeof _agnia.context.wallet[params['wallet_name']] != 'undefined' && typeof params['type'] != 'undefined' && params['type'] != '' && typeof params['key'] != 'undefined' && params['key'] != '' )
    {
        if ( typeof _agnia.context.wallet[params['wallet_name']].data.attributes[params['type']] != 'undefined' )
        {
            var pos = -1;
            for ( var i = 0 ; i < _agnia.context.wallet[params['wallet_name']].data.attributes[params['type']].length ; i++ )
            {
                if ( _agnia.context.wallet[params['wallet_name']].data.attributes[params['type']][i].key == params['key'] )   
                {
                    pos = i;
                    break;
                }
            }
            if ( pos != -1 )
            {
                _agnia.context.wallet[params['wallet_name']].data.attributes[params['type']].splice ( i , 1 );
            }
            if ( _agnia.context.wallet[params['wallet_name']].data.attributes[params['type']].length == 0 )
            {
                delete ( _agnia.context.wallet[params['wallet_name']].data.attributes[params['type']] );
            }
            delete ( _agnia.context_processed.fieldsIdx[params['key']] );
            _agnia.saveWallet( 
                function()
                {
                    sendResponse ( { errnum: 0 , data: params } );
                },
                function()
                {
                    sendResponse ( { errnum: 2 } );
                },
                function()
                {
                    _agnia.internal_cmds.deleteClaim ( params , sendResponse );
                }
            );
        }
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.revokePermission = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['wallet_name'] != 'undefined' && params['wallet_name'] != '' && typeof _agnia.context.wallet[params['wallet_name']] != 'undefined' && typeof params['transaction'] != 'undefined' && params['transaction'] != '' )
    {
        _agnia.revokeTransaction ( params['transaction'] , params['wallet_name'] , function ( resp , status )
            {
                if ( status == 'success' )
                {
                    var data = resp.responseJSON;
                    if ( data.errnum )
                    {
                        sendResponse ( { errnum: data.errnum , errstr: data.errstr } );
                    }
                    else if ( typeof data.data != 'undefined' )
                    {
                        if ( typeof data.signature == 'undefined' )
                        {
                            sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) } );
                            return;
                        }
                        var signer = _agnia.getSigner ( data.data , data.signature );
                        if ( signer != grantPermissionAddress )
                        {
                            sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) } );
                            return;
                        }
                        // Habría que almacenar en el wallet los permisos concedidos.
                        if ( typeof _agnia.context.wallet[_agnia.context.wallet_name]['data'].permissions == 'undefined' )
                        {
                            _agnia.context.wallet[params['wallet_name']]['data'].permissions = [];
                        }
                        for ( var i = 0 ; i < _agnia.context.wallet[params['wallet_name']]['data'].permissions.length ; i++ )
                        {
                            if ( _agnia.context.wallet[params['wallet_name']]['data'].permissions[i].verification.transaction == params['transaction'] )
                            {
                                _agnia.context.wallet[params['wallet_name']]['data'].permissions[i].revocation = data.data;
                                break;
                            }
                        }
                        _agnia.saveWallet( 
                            function()
                            {
                                sendResponse ( { errnum: 0 , data: data.data } );
                            },
                            function()
                            {
                                sendResponse ( { errnum: 2 } );
                            },
                            function()
                            {
                                _agnia.internal_cmds.revokePermission ( params , sendResponse );
                            }
                        );
                    }
                }
                else
                {
                    console.log ( getI18n ( 'errors.error' ) );
                    sendResponse ( { errnum: 1 , errstr: getI18n ( 'errors.error' ) , returnData: params['returnData'] } );
                }
            } );

    }
    else
    {
        sendResponse ( { errnum: 1 , returnData: params['returnData'] } );
    }
}

_agnia.internal_cmds.getFile = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['permission'] != 'undefined' && params['permission'] != '' && typeof params['field'] != 'undefined' )
    {
        var permission;
        var found = false;
        for ( let i = 0 ; i < _agnia.context.wallet[_agnia.context.wallet_name].data.permissions.length ; i++ )
        {
            if ( _agnia.context.wallet[_agnia.context.wallet_name].data.permissions[i].key == params['permission'] )
            {
                permission = _agnia.context.wallet[_agnia.context.wallet_name].data.permissions[i];
                if ( parseInt ( params['field'] ) < permission.permission.fields.length )
                {
                    found = true;
                    if ( typeof permission.permission.fields[parseInt ( params['field'] )].value.file_key == 'undefined' )
                    {
                        sendResponse ( { errnum: 0 , data: permission.permission.fields[parseInt ( params['field'] )] } );
                    }
                    else
                    {
                        loadFile ( permission.permission.fields[parseInt ( params['field'] )].value.file_key , function ( data )
                        {
                            sendResponse ( { errnum: 0 , data: { value: data } } );
                        } );
                    }

                }
                break;
            }
        }
        if ( !found )
        {
            sendResponse ( { errnum: 3 } );
        }
    }
    else if ( typeof params != 'undefined' && typeof params['claimType'] != 'undefined' && params['claimType'] != '' && typeof params['claim'] != 'undefined' && params['claim'] != '' && typeof params['field'] != 'undefined' )
    {
        var claim;
        var found = false;
        if ( typeof _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']] != 'undefined' )
        {
            for ( let i = 0 ; i < _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']].length ; i++ )
            {
                if ( _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']][i].key == params['claim'] )
                {
                    claim = _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']][i];
                    var fileKey = '';
                    if ( params['field'] == '' && typeof claim.data.value['file_key'] != 'undefined' )
                    {
                        fileKey = claim.data.value['file_key'];
                    }
                    else if ( params['field'] != '' && typeof claim.data.value[params['field']]['file_key'] != 'undefined' )
                    {
                        fileKey = claim.data.value[params['field']]['file_key'];
                    }
                    if ( fileKey != '' )
                    {
                        found = true;
                        loadFile ( fileKey , function ( data )
                        {
                            sendResponse ( { errnum: 0 , data: { value: data } } );
                        } );
                    }
                    break;
                }
            }
        }
        if ( !found )
        {
            sendResponse ( { errnum: 3 } );
        }
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.getClaim = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['claimType'] != 'undefined' && params['claimType'] != '' && typeof params['claim'] != 'undefined' && params['claim'] != '' )
    {
        var claim;
        var found = false;
        if ( typeof _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']] != 'undefined' )
        {
            for ( let i = 0 ; i < _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']].length ; i++ )
            {
                if ( _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']][i].key == params['claim'] )
                {
                    claim = _agnia.context.wallet[_agnia.context.wallet_name].data.attributes[params['claimType']][i];
                    sendResponse ( { errnum: 0 , data: { value: claim } } );
                    break;
                }
            }
        }
        if ( !found )
        {
            sendResponse ( { errnum: 3 } );
        }
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.createPresentation = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['claims'] == 'object' && typeof params['claims'].length != 'undefined' )
    {
        var presentation = {
            "@context": [
                "https://www.w3.org/2018/credentials/v1"
            ],
            "type": ["VerifiablePresentation"],
            "holder": _agnia.context.wallet[params['wallet']].did.id,
            "verifiableCredential": params['claims']
        };

        var proof = jwt.createPresentationProof ( presentation , _agnia.context.wallet[params['wallet']].did )
        presentation['proof'] = proof;

        sendResponse ( { errnum: 0 , data: presentation } );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.sign = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['wallet'] != 'undefined' && params['wallet'] != '' && typeof _agnia.context.wallet[params['wallet']] != 'undefined' && typeof params['data'] != 'undefined' )
    {
        let signature = _agnia.sign ( params['data'] , _agnia.context.wallet[params['wallet']].keys.privateKey );
        sendResponse ( { errnum: 0 , data: signature } );
    }
    else if ( typeof params != 'undefined' && typeof _agnia.context.wallet_name != 'undefined' && _agnia.context.wallet_name != '' && typeof _agnia.context.wallet[_agnia.context.wallet_name] != 'undefined' && typeof params['data'] != 'undefined' )
    {
        let signature = _agnia.sign ( params['data'] , _agnia.context.wallet[_agnia.context.wallet_name].keys.privateKey );
        sendResponse ( { errnum: 0 , data: signature , returnData: params['returnData'] , address:  _agnia.context.wallet[_agnia.context.wallet_name].keys.address } );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.getSigner = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['data'] != 'undefined' && typeof params['signature'] != 'undefined' )
    {
        let signer = _agnia.getSigner ( params['data'] , params['signature'] )
        sendResponse ( { errnum: 0 , data: signer } );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.createRequestProof = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['wallet'] != 'undefined' && params['wallet'] != '' && typeof _agnia.context.wallet[params['wallet']] != 'undefined' && typeof params['data'] != 'undefined' )
    {
        let proof = jwt.createRequestProof ( params['data'] , _agnia.context.wallet[params['wallet']].did );
        sendResponse ( { errnum: 0 , data: proof } );
    }
    else if ( typeof params != 'undefined' && typeof _agnia.context.wallet_name != 'undefined' && _agnia.context.wallet_name != '' && typeof _agnia.context.wallet[_agnia.context.wallet_name] != 'undefined' && typeof params['data'] != 'undefined' )
    {
        let proof = jwt.createRequestProof ( params['data'] , _agnia.context.wallet[_agnia.context.wallet_name].did );
        sendResponse ( { errnum: 0 , data: proof , returnData: params['returnData'] , did:  _agnia.context.wallet[_agnia.context.wallet_name].did.id } );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.verifyRequestProof = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['data'] != 'undefined' && typeof params['proof'] != 'undefined' && typeof params['did'] != 'undefined' )
    {
        _agnia.getDid ( params['did'] , function ( data )
        {
            if ( data.errnum != 0 )
            {
                sendResponse ( { errnum: 2 } );
            }
            else
            {
                sendResponse ( { errnum: 0 , data: jwt.validateResponseProof ( params['data'] , params['proof'] , data['data'] ) } );
            }
        } )
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.internal_cmds.checkPassword = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof params['password'] != 'undefined'  && typeof _agnia.context != 'undefined' && typeof _agnia.context.password != 'undefined' && _agnia.context.password === params['password'] )
    {
        sendResponse ( { errnum: 0 } );
    }
    else
    {
        sendResponse ( { errnum: 1 } );
    }
}

_agnia.public_cmds = {};
_agnia.public_cmds.isWalletUnlocked = function ( params , sendResponse )
{
    if ( _agnia.context.wallet != null )
    {
        sendResponse ( { errnum: 0 } );
    }
    else
    {
        sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.wallet_locked' ) } );
    }

}

_agnia.public_cmds.getData = function ( params , sendResponse )
{
    if ( typeof params['type'] == 'string' )
    {
        if ( _agnia.context.wallet != null )
        {
            var data;
            if ( _agnia.context.wallet_name != null )
            {
                data = _agnia.context.wallet[_agnia.context.wallet_name].data;
            }
            if ( typeof data == 'undefined' )
            {
                sendResponse ( { errnum: 3 , returnData: params['returnData'] } ); // wallet vacio
            }
            else if ( typeof data.attributes[params['type']] == 'undefined' || data.attributes[params['type']].length == 0 )
            {
                sendResponse ( { errnum: 4 , errstr: getI18n ( 'errors.no_data' ) , returnData: params['returnData'] } ); // wallet sin datos de este tipo
            }
            else
            {
                sendResponse ( { errnum: 0 , data: data.attributes[params['type']] , returnData: params['returnData'] } );
            }
        }
        else
        {
            sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.wallet_locked' ) , returnData: params['returnData'] } ); // wallet bloqueado
        }
    }
    else
    {
        sendResponse ( { errnum: 1 , errstr: getI18n ( 'errors.error' ) , returnData: params['returnData'] } ); // parametro incorrecto
    }
}

_agnia.public_cmds.sign = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof _agnia.context.wallet_name != 'undefined' && _agnia.context.wallet_name != '' && typeof _agnia.context.wallet[_agnia.context.wallet_name] != 'undefined' && typeof params['data'] != 'undefined' )
    {
        let signature = _agnia.sign ( params['data'] , _agnia.context.wallet[_agnia.context.wallet_name].keys.privateKey );
        sendResponse ( { errnum: 0 , data: signature , returnData: params['returnData'] , address:  _agnia.context.wallet[_agnia.context.wallet_name].keys.address } );
    }
    else
    {
        sendResponse ( { errnum: 1 , returnData: params['returnData'] } );
    }
}

_agnia.public_cmds.storePermissions = function ( params , sendResponse )
{
    if ( typeof params != 'undefined' && typeof _agnia.context.wallet_name != 'undefined' && _agnia.context.wallet_name != '' && typeof _agnia.context.wallet[_agnia.context.wallet_name] != 'undefined' && typeof params['permissions'] != 'undefined' && typeof params['organization'] != 'undefined' && typeof params['organization'].address != 'undefined' )
    {
        var permissions = [];
        for ( var i = 0 ; i < params['permissions'].length ; i++ )
        {
            var permission = { permission: params['permissions'][i].permission };
            var fields = {};
            for ( var j = 0 ; j < params['permissions'][i].fields.length ; j++ )
            {
                var field = { 'value': params['permissions'][i].fields[j].value };
                if ( typeof params['permissions'][i].fields[j].agniaKey != 'undefined' && typeof _agnia.context_processed.fieldsIdx[params['permissions'][i].fields[j].agniaKey] != 'undefined' )
                {
                    field['data'] = _agnia.context_processed.fieldsIdx[params['permissions'][i].fields[j].agniaKey].data;
                    field['verification'] = _agnia.context_processed.fieldsIdx[params['permissions'][i].fields[j].agniaKey].verification;
                }
                fields[params['permissions'][i].fields[j].name] = field;
            }
            permission.signature = _agnia.sign ( { permission: params['permissions'][i].permission , fields: fields } , _agnia.context.wallet[_agnia.context.wallet_name].keys.privateKey );
            permissions.push ( permission );
        }
        var requestData = {};
        requestData['params'] = {};
        requestData['params']['whom'] = params['organization'].address;
        requestData['params']['permissions'] = permissions;
        requestData['timestamp'] = ( new Date() ).getTime() / 1000;
        postData ( {
            url: grantPermissionsUrl ,
            method: 'POST',
            data: {
                data: serializeObject ( requestData ),
                signature: _agnia.sign ( requestData , _agnia.context.wallet[_agnia.context.wallet_name].keys.privateKey ),
                address: _agnia.context.wallet[_agnia.context.wallet_name].keys.address
            },
            complete: function ( resp , status )
            {
                if ( status == 'success' )
                {
                    var data = resp.responseJSON;
                    if ( data.errnum )
                    {
                        sendResponse ( { errnum: data.errnum , errstr: data.errstr , returnData: params['returnData'] } );
                    }
                    else if ( typeof data.data != 'undefined' )
                    {
                        if ( typeof data.signature == 'undefined' )
                        {
                            sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                            return;
                        }
                        var signer = _agnia.getSigner ( data.data , data.signature );
                        if ( signer != grantPermissionAddress )
                        {
                            sendResponse ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                            return;
                        }
                        // Habría que almacenar en el wallet los permisos concedidos.
                        if ( typeof _agnia.context.wallet[_agnia.context.wallet_name]['data'].permissions == 'undefined' )
                        {
                            _agnia.context.wallet[_agnia.context.wallet_name]['data'].permissions = [];
                        }
                        var organization = { address: params['organization'].address };
                        var names = [ 'name' , 'permissions' , 'allowed_urls' ];
                        for ( var i = 0 ; i < names.length ; i++ )
                        {
                            if ( typeof params['organization'][names[i]] != 'undefined' )
                            {
                                organization[names[i]] = params['organization'][names[i]];
                            }
                        }
                        for ( var i = 0 ; i < params['permissions'].length ; i++ )
                        {
                            var key;
                            do
                            {
                                key = _agnia.getKey();
                            }
                            while ( typeof _agnia.context_processed.permissionsIdx[key] != 'undefined' );
                            for ( var j = 0 ; j < params['permissions'][i].fields.length ; j++ )
                            {
                                if ( typeof params['permissions'][i].fields[j].value == 'object' )
                                {
                                    if ( typeof params['permissions'][i].fields[j].value.length != 'undefined' )
                                    {
                                        for ( var k = 0 ; k < params['permissions'][i].fields[j].value.length ; k++ )
                                        {
                                            params['permissions'][i].fields[j].value[k].file_key = saveFile ( params['permissions'][i].fields[j].value[k].name , params['permissions'][i].fields[j].value[k].type , params['permissions'][i].fields[j].value[k].data );
                                            delete params['permissions'][i].fields[j].value[k].data;
                                        }
                                    }
                                    else if ( typeof params['permissions'][i].fields[j].value.name != 'undefined' && typeof params['permissions'][i].fields[j].value.type != 'undefined' && typeof params['permissions'][i].fields[j].value.data != 'undefined' )
                                    {
                                        params['permissions'][i].fields[j].value.file_key = saveFile ( params['permissions'][i].fields[j].value.name , params['permissions'][i].fields[j].value.type , params['permissions'][i].fields[j].value.data );
                                        delete params['permissions'][i].fields[j].value.data;
                                    }
                                }
                            }
                            var permission = { permission: params['permissions'][i] , organization: organization , verification: data.data[params['permissions'][i].permission] , key: key };
                            _agnia.context.wallet[_agnia.context.wallet_name].data.permissions.push ( permission );
                            _agnia.context_processed.permissionsIdx[key] = permission;
                        }
                        _agnia.saveWallet ( 
                            function()
                            {
                                sendResponse ( { errnum: 0 , data: data.data , returnData: params['returnData'] } );
                            },
                            function()
                            {
                                sendResponse ( { errnum: 2 } );
                            },
                            function()
                            {
                                _agnia.public_cmds.storePermissions ( params , sendResponse );
                            }
                        );
                    }
                }
                else
                {
                    console.log ( getI18n ( 'errors.error' ) );
                    sendResponse ( { errnum: 1 , errstr: getI18n ( 'errors.error' ) , returnData: params['returnData'] } );
                }
            }
        } );

    }
    else
    {
        sendResponse ( { errnum: 1 , returnData: params['returnData'] } );
    }
}

_agnia.public_cmds.getSigner = _agnia.internal_cmds.getSigner;

_agnia.public_cmds.loadFile = _agnia.internal_cmds.loadFile;

_agnia.baseUrl = browser.runtime.getURL ( '/' );

_agnia.keySize = 256;
_agnia.ivSize = 128;
_agnia.iterations = 100;

_agnia.getKey = function()
{
    var result           = '';
    var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var charactersLength = characters.length;
    for ( var i = 0 ; i < 10 ; i++ )
    {
       result += characters.charAt ( Math.floor ( Math.random() * charactersLength ) );
    }
    result += ( new Date() ).getTime().toString();
    return result;
}

_agnia.sign = function ( data , privateKey )
{
    var signature = _agnia.web3.eth.accounts.sign ( serializeObject ( data ) , privateKey );
    return signature.signature;
}

_agnia.getSigner = function ( data , signature )
{
    var signer = _agnia.web3.eth.accounts.recover ( serializeObject ( data ) , signature );
    return signer;
}

_agnia.asymmetricCrypt = function ( msg , did )
{
    var publicKey = '0x' + b64ToHex ( did.verificationMethod[0].publicKeyJwk.x ) + b64ToHex ( did.verificationMethod[0].publicKeyJwk.y )
    var encrypted = window.EciesJS.Util.encrypt ( publicKey , serializeObject ( msg ) )
    return window.EthCrypto.Util.util.uint8ArrayToHex ( encrypted );
}

_agnia.asymmetricDecrypt = function ( encryptedStr , did )
{
    var decrypted = window.EciesJS.Util.decrypt ( did.verificationMethod[0].privateKeyHex , window.EthCrypto.Util.util.hexToUnit8Array ( encryptedStr ) );
    return JSON.parse ( decrypted.toString() );
}

_agnia.encrypt = function ( msg , pass )
{
    var salt = CryptoJS.lib.WordArray.random ( 128 / 8 );
  
    var key = CryptoJS.PBKDF2 ( pass , salt , {
        keySize: _agnia.keySize / 32,
        iterations: _agnia.iterations
    } );

    var iv = CryptoJS.lib.WordArray.random ( 128 / 8 );

    var encrypted = CryptoJS.AES.encrypt ( msg , key , { 
        iv: iv, 
        padding: CryptoJS.pad.Pkcs7,
        mode: CryptoJS.mode.CBC
    } );

    // salt, iv will be hex 32 in length
    // append them to the ciphertext for use  in decryption
    var transitmessage = salt.toString() + iv.toString() + encrypted.toString();
    return transitmessage;
}

_agnia.decrypt = function ( transitmessage , pass )
{
    var salt = CryptoJS.enc.Hex.parse ( transitmessage.substr ( 0, 32 ) );
    var iv = CryptoJS.enc.Hex.parse ( transitmessage.substr ( 32, 32 ) )
    var encrypted = transitmessage.substring ( 64 );

    var key = CryptoJS.PBKDF2 ( pass , salt , {
        keySize: _agnia.keySize / 32,
        iterations: _agnia.iterations
    } );

    var decrypted = CryptoJS.AES.decrypt ( encrypted , key , { 
        iv: iv, 
        padding: CryptoJS.pad.Pkcs7,
        mode: CryptoJS.mode.CBC
    } );
    try
    {
        var decryptedStr = decrypted.toString ( CryptoJS.enc.Utf8 );
        if ( decryptedStr.length == 0 )
        {
            return null;
        }
        return decryptedStr;
    }
    catch
    {
        return null;
    }
}

_agnia.saveWallet = function ( successCallback , errorCallback , retryCallback )
{
    if ( _agnia.context.wallet_name != null && _agnia.context.password != null && _agnia.context.wallet != null )
    {
        if ( _agnia.context.cryptedWallet === null )
        {
            _agnia.context.cryptedWallet = {};
        }
        if ( _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage == true )
        {
            this.saveRemoteWallet ( function ( resp )
                {
                    if ( typeof resp != 'undefined' && typeof resp['errnum'] != 'undefined' && resp['errnum'] === 0 )
                    {
                        var aux_wallet = {};
                        for ( var key in _agnia.context.wallet[_agnia.context.wallet_name] )
                        {
                            if ( key != 'data' )
                            {
                                aux_wallet[key] = _agnia.context.wallet[_agnia.context.wallet_name][key];
                            }
                        }
                        _agnia.context.cryptedWallet[_agnia.context.wallet_name] = _agnia.encrypt ( JSON.stringify ( aux_wallet ) , _agnia.context.password );
                        browser.storage.local.set ( {
                            wallet: _agnia.context.cryptedWallet
                        } );
                        _agnia.saveContext();
                        if ( typeof successCallback == 'function' )
                        {
                            successCallback();
                        }
                    }
                    else
                    {
                        if ( typeof errorCallback == 'function' )
                        {
                            errorCallback();
                        }
                    }
                } , retryCallback
            );
        }
        else
        {
            _agnia.context.cryptedWallet[_agnia.context.wallet_name] = _agnia.encrypt ( JSON.stringify ( _agnia.context.wallet[_agnia.context.wallet_name] ) , _agnia.context.password );
            browser.storage.local.set ( {
                wallet: _agnia.context.cryptedWallet
            } );
            _agnia.saveContext();
            if ( typeof successCallback == 'function' )
            {
                successCallback();
            }
        }
    }

}

_agnia.getRemoteWallet = function ( callback )
{
    if ( _agnia.context.wallet_name != null && _agnia.context.password != null && _agnia.context.wallet != null )
    {
        var requestData = {};
        requestData['params'] = {};
        requestData['timestamp'] = ( new Date() ).getTime() / 1000;
        postData ( {
            url: getRemoteWalletUrl ,
            method: 'POST',
            data: {
                data: serializeObject ( requestData ),
                proof: serializeObject ( jwt.createRequestProof ( requestData , _agnia.context.wallet[_agnia.context.wallet_name].did ) ),
                did: _agnia.context.wallet[_agnia.context.wallet_name].did.id
            },
            complete: function ( resp , status )
            {
                if ( status == 'success' )
                {
                    var data = resp.responseJSON;
                    if ( data.errnum == 0 && typeof data.data != 'undefined' )
                    {
                        if ( typeof data.proof == 'undefined' )
                        {
                            callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) } );
                            return;
                        }
                        _agnia.getDid ( storageDid , function ( dataDid )
                        {
                            if ( dataDid.errnum != 0 )
                            {
                                sendResponse ( { errnum: 2 } );
                            }
                            else
                            {
                                if ( ! jwt.validateResponseProof ( data.data , data.proof , dataDid.data ) )
                                {
                                    callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) } );
                                    return;
                                }
                                var walletData = _agnia.asymmetricDecrypt ( data.data.data , _agnia.context.wallet[_agnia.context.wallet_name].did );
                                _agnia.context.wallet[_agnia.context.wallet_name].data = walletData;
                                _agnia.context.wallet[_agnia.context.wallet_name].version = data.data.version;
                                _agnia.context_processed.fieldsIdx = {};
                                _agnia.context_processed.permissionsIdx = {};
                                _agnia.context.lastDownload = new Date().getTime();
                                _agnia.processContext();
                                _agnia.saveContext();
                            }
                            if ( typeof callback == 'function' )
                            {
                                callback ( { errnum: data.errnum } );
                            }
                        } );
                
                    }
                }
                else
                {
                    callback ( { errnum: -1 , errstr: getI18n ( 'errors.retrieving_wallet' ) } );
                }
            }
        } );
    }
}

_agnia.saveRemoteWallet = function ( callback , retry )
{
    if ( _agnia.context.wallet_name != null && _agnia.context.password != null && _agnia.context.wallet != null )
    {
        var requestData = {};
        requestData['params'] = {};
        if ( typeof _agnia.context.wallet[_agnia.context.wallet_name].version == 'undefined' )
        {
            requestData['params']['version'] = 0;
        }
        else
        {
            requestData['params']['version'] = _agnia.context.wallet[_agnia.context.wallet_name].version;
        }
        requestData['params']['data'] = _agnia.asymmetricCrypt ( _agnia.context.wallet[_agnia.context.wallet_name].data , _agnia.context.wallet[_agnia.context.wallet_name].did );
        requestData['timestamp'] = ( new Date() ).getTime() / 1000;
        postData ( {
            url: saveRemoteWalletUrl ,
            method: 'POST',
            data: {
                data: serializeObject ( requestData ),
                proof: serializeObject ( jwt.createRequestProof ( requestData , _agnia.context.wallet[_agnia.context.wallet_name].did ) ),
                did: _agnia.context.wallet[_agnia.context.wallet_name].did.id
            },
            complete: function ( resp , status )
            {
                if ( status == 'success' )
                {
                    var data = resp.responseJSON;
                    if ( typeof data.proof == 'undefined' )
                    {
                        callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                        return;
                    }
                    _agnia.getDid ( storageDid , function ( dataDid )
                    {
                        if ( dataDid.errnum != 0 )
                        {
                            callback ( { errnum: 2 } );
                        }
                        else
                        {
                            if ( ! jwt.validateResponseProof ( data.data , data.proof , dataDid.data ) )
                            {
                                callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                                return;
                            }

                            if ( data.errnum )
                            {
                                if ( data.errnum == 3 && typeof data.data != 'undefined' && typeof data.data.version != 'undefined' && typeof data.data.data != 'undefined' )
                                {
                                    var walletData = _agnia.asymmetricDecrypt ( data.data.data , _agnia.context.wallet[_agnia.context.wallet_name].did );
                                    _agnia.context.wallet[_agnia.context.wallet_name].data = walletData;
                                    _agnia.context.wallet[_agnia.context.wallet_name].version = data.data.version;
                                    _agnia.context_processed.fieldsIdx = {};
                                    _agnia.context_processed.permissionsIdx = {};
                                    _agnia.context.lastDownload = new Date().getTime();
                                    _agnia.processContext();
                                    if ( typeof retry == 'function' )
                                    {
                                        retry();
                                    }
                                }
                                else
                                {
                                    callback ( data )
                                }
                            }
                            else if ( typeof data.data != 'undefined' )
                            {
                                _agnia.context.wallet[_agnia.context.wallet_name].version = data.data.version
                                if ( typeof callback == 'function' )
                                {
                                    callback ( data );
                                }
                            }
                        }
                    } );
                }
            }
        } );
    }
}

_agnia.deleteRemoteWallet = function ( callback )
{
    if ( _agnia.context.wallet_name != null && _agnia.context.password != null && _agnia.context.wallet != null )
    {
        var requestData = {};
        requestData['params'] = {};
        requestData['timestamp'] = ( new Date() ).getTime() / 1000;
        postData ( {
            url: deleteRemoteWalletUrl ,
            method: 'POST',
            data: {
                data: serializeObject ( requestData ),
                proof: serializeObject ( jwt.createRequestProof ( requestData , _agnia.context.wallet[_agnia.context.wallet_name].did ) ),
                did: _agnia.context.wallet[_agnia.context.wallet_name].did.id
            },
            complete: function ( resp , status )
            {
                if ( typeof callback == 'function' )
                {

                    if ( status == 'success' )
                    {
                        var data = resp.responseJSON;
                        if ( data.errnum )
                        {
                            callback ( data )
                        }
                        else if ( typeof data.data != 'undefined' )
                        {
                            if ( typeof data.proof == 'undefined' )
                            {
                                callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                                return;
                            }
                            _agnia.getDid ( storageDid , function ( dataDid )
                            {
                                if ( dataDid.errnum != 0 )
                                {
                                    callback ( { errnum: 2 } );
                                    return;
                                }
                                else
                                {
                                    if ( ! jwt.validateResponseProof ( data.data , data.proof , dataDid.data ) )
                                    {
                                        callback ( { errnum: 2 , errstr: getI18n ( 'errors.response_signature_mismatch' ) , returnData: params['returnData'] } );
                                        return;
                                    }
        
                                    delete _agnia.context.wallet[_agnia.context.wallet_name].version;
                                    if ( typeof callback == 'function' )
                                    {
                                        callback ( data );
                                    }
                                }
                            } );
                        }
                    }
                }
            }
        } );
    }
}

_agnia.getFilesList = function()
{
    var filesList = [];
    var filesIdx = {};
    if ( typeof _agnia.context_processed != 'undefined' && typeof _agnia.context_processed.fieldsIdx != 'undefined' )
    {
        for ( var key in _agnia.context_processed.fieldsIdx )
        {
            var claim = _agnia.context_processed.fieldsIdx[key];
            if ( typeof claim.data != 'undefined' && typeof claim.data.value == 'object' )
            {
                if ( typeof claim.data.value.file_key != 'undefined' && typeof claim.data.value.name != 'undefined' && typeof claim.data.value.type != 'undefined' )
                {
                    if ( typeof filesIdx[claim.data.value.file_key] == 'undefined' )
                    {
                        filesIdx[claim.data.value.file_key] = 1;
                        filesList.push ( claim.data.value.file_key );
                    }
                }
                else
                {
                    for ( var fieldName in claim.data.value )
                    {
                        if ( typeof claim.data.value[fieldName].file_key != 'undefined' && typeof claim.data.value[fieldName].name != 'undefined' && typeof claim.data.value[fieldName].type != 'undefined' )
                        {
                            if ( typeof filesIdx[claim.data.value[fieldName].file_key] == 'undefined' )
                            {
                                filesIdx[claim.data.value[fieldName].file_key] = 1;
                                filesList.push ( claim.data.value[fieldName].file_key );
                            }
                        }
                    }
                }
            }
        }
    }
    if ( typeof _agnia.context_processed != 'undefined' && typeof _agnia.context_processed.permissionsIdx != 'undefined' )
    {
        for ( var key in _agnia.context_processed.permissionsIdx )
        {
            var permission = _agnia.context_processed.permissionsIdx[key];
            if ( typeof permission.permission.fields == 'object' && typeof permission.permission.fields.length != 'undefined' )
            {
                for ( var i = 0 ; i < permission.permission.fields.length ; i++ )
                {
                    if ( typeof permission.permission.fields[i].value == 'object' && typeof permission.permission.fields[i].value.file_key != 'undefined' && typeof permission.permission.fields[i].value.name != 'undefined' && typeof permission.permission.fields[i].value.type != 'undefined')
                    {
                        if ( typeof filesIdx[permission.permission.fields[i].value.file_key] == 'undefined' )
                        {
                            filesIdx[permission.permission.fields[i].value.file_key] = 1;
                            filesList.push ( permission.permission.fields[i].value.file_key );
                        }
                    }
                }
            }
        }
    }
    return filesList;
}

_agnia.doUploading = function()
{
    if ( _agnia.context.popupStatus.status == 'uploading' )
    {
        if ( _agnia.context.uploadIndex < _agnia.context.uploadFiles.length )
        {
            uploadFile ( _agnia.context.uploadFiles[_agnia.context.uploadIndex] , function ( data )
            {
                if ( data.errnum != 0 )
                {
                    _agnia.context.popupStatus.progress = -1;
                    _agnia.saveContext();
                }
                else
                {
                    _agnia.context.uploadIndex++;
                    _agnia.context.popupStatus.progress++;
                    _agnia.saveContext();
                    _agnia.doUploading();
                }
            } );
        }
        else
        {
            if ( _agnia.context.uploadFiles.length > 0 )
            {
                for ( var i = 0 ; i < _agnia.context.uploadFiles.length ; i++ )
                {
                    deleteLocalFile ( _agnia.context.uploadFiles[i] );
                }
            }
            _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage = true;
            _agnia.context.popupStatus.progress++;
            _agnia.saveWallet ( undefined , undefined , function() { _agnia.saveWallet(); } );
        }
    }
}

_agnia.uploadWallet = function ()
{
    var filesList = _agnia.getFilesList();
    _agnia.context.popupStatus = { status: 'uploading' , progress: 0 , complete: filesList.length + 1 };
    _agnia.context.uploadIndex = 0;
    _agnia.context.uploadFiles = filesList;
    _agnia.saveContext();
    _agnia.doUploading();
}

_agnia.doDownloading = function()
{
    if ( _agnia.context.popupStatus.status == 'downloading' )
    {
        if ( _agnia.context.downloadIndex < _agnia.context.downloadFiles.length )
        {
            downloadFile ( _agnia.context.downloadFiles[_agnia.context.downloadIndex] , function ( data )
            {
                if ( data.errnum != 0 )
                {
                    _agnia.context.popupStatus.progress = -1;
                    _agnia.saveContext();
                }
                else
                {
                    _agnia.context.downloadIndex++;
                    _agnia.context.popupStatus.progress++;
                    _agnia.saveContext();
                    _agnia.doDownloading();
                }
            } );
        }
        else
        {
            if ( _agnia.context.downloadFiles.length > 0 )
            {
                deleteAllRemoteFiles();
            }
            _agnia.context.wallet[_agnia.context.wallet_name].config.remote_storage = false;
            _agnia.context.popupStatus.progress++;
            _agnia.saveWallet();
            _agnia.deleteRemoteWallet();
        }
    }
}

_agnia.downloadWallet = function()
{
    var filesList = _agnia.getFilesList();
    _agnia.context.popupStatus = { status: 'downloading' , progress: 0 , complete: filesList.length + 1 };
    _agnia.context.downloadIndex = 0;
    _agnia.context.downloadFiles = filesList;
    _agnia.saveContext();
    _agnia.doDownloading();
}

_agnia.hash = function ( message )
{
    return _agnia.web3.utils.sha3 ( message );
}

_agnia.revokeTransaction = function ( transaction , wallet_name , callback )
{
    var requestData = {};
    requestData['params'] = {};
    requestData['params']['transaction'] = transaction;
    requestData['params']['timestamp'] = parseInt ( ( new Date() ).getTime() / 1000 );
    requestData['params']['signature'] = _agnia.sign ( { 'transaction': transaction , 'timestamp': requestData['params']['timestamp'] } , _agnia.context.wallet[wallet_name].keys.privateKey );
    requestData['timestamp'] = ( new Date() ).getTime() / 1000;
    postData ( {
        url: revokeTransactionUrl ,
        method: 'POST',
        data: {
            data: serializeObject ( requestData ),
            signature: _agnia.sign ( requestData , _agnia.context.wallet[wallet_name].keys.privateKey ),
            address: _agnia.context.wallet[wallet_name].keys.address
        },
        complete: callback
    } );

}

function processMessage ( message , sender , sendResponse )
{
    if ( sender.url.indexOf ( _agnia.baseUrl ) !== 0 )
    {
        // console.log ( sender );
        // console.log ( message );
        if ( typeof message.data == 'object' )
        {
            if ( typeof message.data.cmd != 'undefined' && typeof _agnia.public_cmds[message.data.cmd] == 'function' )
            {
                _agnia.public_cmds[message.data.cmd] ( message.data.params , sendResponse );
            }
            return true;
        }
        return;
    }
    if ( typeof message.data == 'object' )
    {
        if ( typeof message.data.cmd != 'undefined' && typeof _agnia.internal_cmds[message.data.cmd] == 'function' )
        {
            _agnia.internal_cmds[message.data.cmd] ( message.data.params , sendResponse );
        }
        return true;
    }
    //console.log ( 'Background' );
    //console.log ( 'Mensaje:' );
    //console.log ( message );
    //console.log ( 'Sender:' );
    //console.log ( sender );
    //console.log ( 'SendResponse:' );
    //console.log ( sendResponse );
}

function getMessage ( message , sender , sendResponse )
{
    if ( _agnia.context == null )
    {
        _agnia.initContext ( function(){
            processMessage ( message , sender , sendResponse );
        } );
    }
    else
    {
        processMessage ( message , sender , sendResponse );
    }
    return true;
}

function sendMessage ( data )
{
    browser.runtime.sendMessage ( { data: data } , function ( response )
    {
        console.log ( "Background sendMessage callback" );
        console.log ( response );
    } );
}

browser.runtime.onMessage.addListener ( getMessage );

