<commit_before>extern crate indy_crypto;
extern crate serde_json;

use errors::common::CommonError;
use errors::did::DidError;
use errors::wallet::WalletError;
use errors::indy::IndyError;
use domain::crypto::key::KeyInfo;
use domain::crypto::did::{MyDidInfo, Did, TheirDidInfo, TheirDid, TemporaryDid, DidWithMeta};
use domain::ledger::response::Reply;
use domain::ledger::nym::{GetNymReplyResult, GetNymResultDataV0};
use domain::ledger::attrib::{GetAttrReplyResult, AttribData, Endpoint};
use services::pool::PoolService;
use services::wallet::{WalletService, RecordOptions, SearchOptions};
use services::crypto::CryptoService;
use services::ledger::LedgerService;

use std::error::Error;
use std::rc::Rc;
use std::str;
use std::cell::RefCell;

use commands::ledger::LedgerCommand;
use commands::{Command, CommandExecutor};
use std::collections::HashMap;
use utils::sequence::SequenceUtils;
use utils::crypto::base58::Base58;
use self::indy_crypto::utils::json::{JsonEncodable, JsonDecodable};

use super::utils::check_wallet_and_pool_handles_consistency;

pub enum DidCommand {
    CreateAndStoreMyDid(
        i32, // wallet handle
        String, // my did info json
        Box<Fn(Result<(String, String), IndyError>) + Send>),
    ReplaceKeysStart(
        i32, // wallet handle
        String, // key info json
        String, // did
        Box<Fn(Result<String, IndyError>) + Send>),
    ReplaceKeysApply(
        i32, // wallet handle
        String, // my did
        Box<Fn(Result<(), IndyError>) + Send>),
    StoreTheirDid(
        i32, // wallet handle
        String, // their did info json
        Box<Fn(Result<(), IndyError>) + Send>),
    GetMyDidWithMeta(
        i32, // wallet handle
        String, // my did
        Box<Fn(Result<String, IndyError>) + Send>),
    ListMyDidsWithMeta(
        i32, // wallet handle
        Box<Fn(Result<String, IndyError>) + Send>),
    KeyForDid(
        i32, // pool handle
        i32, // wallet handle
        String, // did (my or their)
        Box<Fn(Result<String/*key*/, IndyError>) + Send>),
    KeyForLocalDid(
        i32, // wallet handle
        String, // did (my or their)
        Box<Fn(Result<String/*key*/, IndyError>) + Send>),
    SetEndpointForDid(
        i32, // wallet handle
        String, // did
        String, // address
        String, // transport_key
        Box<Fn(Result<(), IndyError>) + Send>),
    GetEndpointForDid(
        i32, // wallet handle
        i32, // pool handle
        String, // did
        Box<Fn(Result<(String, Option<String>), IndyError>) + Send>),
    SetDidMetadata(
        i32, // wallet handle
        String, // did
        String, // metadata
        Box<Fn(Result<(), IndyError>) + Send>),
    GetDidMetadata(
        i32, // wallet handle
        String, // did
        Box<Fn(Result<String, IndyError>) + Send>),
    AbbreviateVerkey(
        String, // did
        String, // verkey
        Box<Fn(Result<String, IndyError>) + Send>),
    // Internal commands
    GetNymAck(
        i32, // wallet_handle
        Result<String, IndyError>, // GetNym Result
        i32, // deferred cmd id
    ),
    // Internal commands
    GetAttribAck(
        i32, // wallet_handle
        Result<String, IndyError>, // GetAttrib Result
        i32, // deferred cmd id
    )
}

macro_rules! ensure_their_did {
    ($self_:ident, $wallet_handle:ident, $pool_handle:ident, $their_did:ident, $deferred_cmd:expr, $cb:ident) => (match $self_._wallet_get_their_did($wallet_handle, &$their_did) {
          Ok(val) => val,
          Err(WalletError::ItemNotFound) => {

              check_wallet_and_pool_handles_consistency!($self_.wallet_service, $self_.pool_service,
                                                         $wallet_handle, $pool_handle, $cb);

              // No their their_did present in the wallet. Defer this command until it is fetched from ledger.
              return $self_._fetch_their_did_from_ledger($wallet_handle, $pool_handle, &$their_did, $deferred_cmd);
            }
            Err(err) => return $cb(Err(IndyError::from(err)))
        });
}

pub struct DidCommandExecutor {
    pool_service: Rc<PoolService>,
    wallet_service: Rc<WalletService>,
    crypto_service: Rc<CryptoService>,
    ledger_service: Rc<LedgerService>,
    deferred_commands: RefCell<HashMap<i32, DidCommand>>,
}

impl DidCommandExecutor {
    pub fn new(pool_service: Rc<PoolService>,
               wallet_service: Rc<WalletService>,
               crypto_service: Rc<CryptoService>,
               ledger_service: Rc<LedgerService>) -> DidCommandExecutor {
        DidCommandExecutor {
            pool_service,
            wallet_service,
            crypto_service,
            ledger_service,
            deferred_commands: RefCell::new(HashMap::new()),
        }
    }

    pub fn execute(&self, command: DidCommand) {
        match command {
            DidCommand::CreateAndStoreMyDid(wallet_handle, my_did_info_json, cb) => {
                info!("CreateAndStoreMyDid command received");
                cb(self.create_and_store_my_did(wallet_handle, &my_did_info_json));
            }
            DidCommand::ReplaceKeysStart(wallet_handle, key_info_json, did, cb) => {
                info!("ReplaceKeysStart command received");
                cb(self.replace_keys_start(wallet_handle, &key_info_json, &did));
            }
            DidCommand::ReplaceKeysApply(wallet_handle, did, cb) => {
                info!("ReplaceKeysApply command received");
                cb(self.replace_keys_apply(wallet_handle, &did));
            }
            DidCommand::StoreTheirDid(wallet_handle, identity_json, cb) => {
                info!("StoreTheirDid command received");
                cb(self.store_their_did(wallet_handle, &identity_json));
            }
            DidCommand::GetMyDidWithMeta(wallet_handle, my_did, cb) => {
                info!("GetMyDidWithMeta command received");
                cb(self.get_my_did_with_meta(wallet_handle, my_did))
            }
            DidCommand::ListMyDidsWithMeta(wallet_handle, cb) => {
                info!("ListMyDidsWithMeta command received");
                cb(self.list_my_dids_with_meta(wallet_handle));
            }
            DidCommand::KeyForDid(pool_handle, wallet_handle, did, cb) => {
                info!("KeyForDid command received");
                self.key_for_did(pool_handle, wallet_handle, did, cb);
            }
            DidCommand::KeyForLocalDid(wallet_handle, did, cb) => {
                info!("KeyForLocalDid command received");
                cb(self.key_for_local_did(wallet_handle, did));
            }
            DidCommand::SetEndpointForDid(wallet_handle, did, address, transport_key, cb) => {
                info!("SetEndpointForDid command received");
                cb(self.set_endpoint_for_did(wallet_handle, did, address, transport_key));
            }
            DidCommand::GetEndpointForDid(wallet_handle, pool_handle, did, cb) => {
                info!("GetEndpointForDid command received");
                self.get_endpoint_for_did(wallet_handle, pool_handle, did, cb);
            }
            DidCommand::SetDidMetadata(wallet_handle, did, metadata, cb) => {
                info!("SetDidMetadata command received");
                cb(self.set_did_metadata(wallet_handle, did, metadata));
            }
            DidCommand::GetDidMetadata(wallet_handle, did, cb) => {
                info!("GetDidMetadata command received");
                cb(self.get_did_metadata(wallet_handle, did));
            }
            DidCommand::AbbreviateVerkey(did, verkey, cb) => {
                info!("AbbreviateVerkey command received");
                cb(self.abbreviate_verkey(did, verkey));
            }
            DidCommand::GetNymAck(wallet_handle, result, deferred_cmd_id) => {
                info!("GetNymAck command received");
                self.get_nym_ack(wallet_handle, result, deferred_cmd_id);
            }
            DidCommand::GetAttribAck(wallet_handle, result, deferred_cmd_id) => {
                info!("GetAttribAck command received");
                self.get_attrib_ack(wallet_handle, result, deferred_cmd_id);
            }
        };
    }

    fn create_and_store_my_did(&self,
                               wallet_handle: i32,
                               my_did_info_json: &str) -> Result<(String, String), IndyError> {
        debug!("create_and_store_my_did >>> wallet_handle: {:?}, my_did_info_json: {:?}", wallet_handle, my_did_info_json);

        let my_did_info = MyDidInfo::from_json(&my_did_info_json)
            .map_err(map_err_trace!())
            .map_err(|err|
                CommonError::InvalidStructure(
                    format!("Invalid MyDidInfo json: {:?}", err)))?;

        let (did, key) = self.crypto_service.create_my_did(&my_did_info)?;

        if self.wallet_service.record_exists::<Did>(wallet_handle, &did.did)? {
            return Err(IndyError::DidError(DidError::AlreadyExistsError("Did already exists".to_string())));
        };

        self.wallet_service.add_indy_object(wallet_handle, &did.did, &did, &HashMap::new())?;
        self.wallet_service.add_indy_object(wallet_handle, &key.verkey, &key, &HashMap::new())?;<commit_msg>put the failing did into the error<commit_after>extern crate indy_crypto;
extern crate serde_json;

use errors::common::CommonError;
use errors::did::DidError;
use errors::wallet::WalletError;
use errors::indy::IndyError;
use domain::crypto::key::KeyInfo;
use domain::crypto::did::{MyDidInfo, Did, TheirDidInfo, TheirDid, TemporaryDid, DidWithMeta};
use domain::ledger::response::Reply;
use domain::ledger::nym::{GetNymReplyResult, GetNymResultDataV0};
use domain::ledger::attrib::{GetAttrReplyResult, AttribData, Endpoint};
use services::pool::PoolService;
use services::wallet::{WalletService, RecordOptions, SearchOptions};
use services::crypto::CryptoService;
use services::ledger::LedgerService;

use std::error::Error;
use std::rc::Rc;
use std::str;
use std::cell::RefCell;

use commands::ledger::LedgerCommand;
use commands::{Command, CommandExecutor};
use std::collections::HashMap;
use utils::sequence::SequenceUtils;
use utils::crypto::base58::Base58;
use self::indy_crypto::utils::json::{JsonEncodable, JsonDecodable};

use super::utils::check_wallet_and_pool_handles_consistency;

pub enum DidCommand {
    CreateAndStoreMyDid(
        i32, // wallet handle
        String, // my did info json
        Box<Fn(Result<(String, String), IndyError>) + Send>),
    ReplaceKeysStart(
        i32, // wallet handle
        String, // key info json
        String, // did
        Box<Fn(Result<String, IndyError>) + Send>),
    ReplaceKeysApply(
        i32, // wallet handle
        String, // my did
        Box<Fn(Result<(), IndyError>) + Send>),
    StoreTheirDid(
        i32, // wallet handle
        String, // their did info json
        Box<Fn(Result<(), IndyError>) + Send>),
    GetMyDidWithMeta(
        i32, // wallet handle
        String, // my did
        Box<Fn(Result<String, IndyError>) + Send>),
    ListMyDidsWithMeta(
        i32, // wallet handle
        Box<Fn(Result<String, IndyError>) + Send>),
    KeyForDid(
        i32, // pool handle
        i32, // wallet handle
        String, // did (my or their)
        Box<Fn(Result<String/*key*/, IndyError>) + Send>),
    KeyForLocalDid(
        i32, // wallet handle
        String, // did (my or their)
        Box<Fn(Result<String/*key*/, IndyError>) + Send>),
    SetEndpointForDid(
        i32, // wallet handle
        String, // did
        String, // address
        String, // transport_key
        Box<Fn(Result<(), IndyError>) + Send>),
    GetEndpointForDid(
        i32, // wallet handle
        i32, // pool handle
        String, // did
        Box<Fn(Result<(String, Option<String>), IndyError>) + Send>),
    SetDidMetadata(
        i32, // wallet handle
        String, // did
        String, // metadata
        Box<Fn(Result<(), IndyError>) + Send>),
    GetDidMetadata(
        i32, // wallet handle
        String, // did
        Box<Fn(Result<String, IndyError>) + Send>),
    AbbreviateVerkey(
        String, // did
        String, // verkey
        Box<Fn(Result<String, IndyError>) + Send>),
    // Internal commands
    GetNymAck(
        i32, // wallet_handle
        Result<String, IndyError>, // GetNym Result
        i32, // deferred cmd id
    ),
    // Internal commands
    GetAttribAck(
        i32, // wallet_handle
        Result<String, IndyError>, // GetAttrib Result
        i32, // deferred cmd id
    )
}

macro_rules! ensure_their_did {
    ($self_:ident, $wallet_handle:ident, $pool_handle:ident, $their_did:ident, $deferred_cmd:expr, $cb:ident) => (match $self_._wallet_get_their_did($wallet_handle, &$their_did) {
          Ok(val) => val,
          Err(WalletError::ItemNotFound) => {

              check_wallet_and_pool_handles_consistency!($self_.wallet_service, $self_.pool_service,
                                                         $wallet_handle, $pool_handle, $cb);

              // No their their_did present in the wallet. Defer this command until it is fetched from ledger.
              return $self_._fetch_their_did_from_ledger($wallet_handle, $pool_handle, &$their_did, $deferred_cmd);
            }
            Err(err) => return $cb(Err(IndyError::from(err)))
        });
}

pub struct DidCommandExecutor {
    pool_service: Rc<PoolService>,
    wallet_service: Rc<WalletService>,
    crypto_service: Rc<CryptoService>,
    ledger_service: Rc<LedgerService>,
    deferred_commands: RefCell<HashMap<i32, DidCommand>>,
}

impl DidCommandExecutor {
    pub fn new(pool_service: Rc<PoolService>,
               wallet_service: Rc<WalletService>,
               crypto_service: Rc<CryptoService>,
               ledger_service: Rc<LedgerService>) -> DidCommandExecutor {
        DidCommandExecutor {
            pool_service,
            wallet_service,
            crypto_service,
            ledger_service,
            deferred_commands: RefCell::new(HashMap::new()),
        }
    }

    pub fn execute(&self, command: DidCommand) {
        match command {
            DidCommand::CreateAndStoreMyDid(wallet_handle, my_did_info_json, cb) => {
                info!("CreateAndStoreMyDid command received");
                cb(self.create_and_store_my_did(wallet_handle, &my_did_info_json));
            }
            DidCommand::ReplaceKeysStart(wallet_handle, key_info_json, did, cb) => {
                info!("ReplaceKeysStart command received");
                cb(self.replace_keys_start(wallet_handle, &key_info_json, &did));
            }
            DidCommand::ReplaceKeysApply(wallet_handle, did, cb) => {
                info!("ReplaceKeysApply command received");
                cb(self.replace_keys_apply(wallet_handle, &did));
            }
            DidCommand::StoreTheirDid(wallet_handle, identity_json, cb) => {
                info!("StoreTheirDid command received");
                cb(self.store_their_did(wallet_handle, &identity_json));
            }
            DidCommand::GetMyDidWithMeta(wallet_handle, my_did, cb) => {
                info!("GetMyDidWithMeta command received");
                cb(self.get_my_did_with_meta(wallet_handle, my_did))
            }
            DidCommand::ListMyDidsWithMeta(wallet_handle, cb) => {
                info!("ListMyDidsWithMeta command received");
                cb(self.list_my_dids_with_meta(wallet_handle));
            }
            DidCommand::KeyForDid(pool_handle, wallet_handle, did, cb) => {
                info!("KeyForDid command received");
                self.key_for_did(pool_handle, wallet_handle, did, cb);
            }
            DidCommand::KeyForLocalDid(wallet_handle, did, cb) => {
                info!("KeyForLocalDid command received");
                cb(self.key_for_local_did(wallet_handle, did));
            }
            DidCommand::SetEndpointForDid(wallet_handle, did, address, transport_key, cb) => {
                info!("SetEndpointForDid command received");
                cb(self.set_endpoint_for_did(wallet_handle, did, address, transport_key));
            }
            DidCommand::GetEndpointForDid(wallet_handle, pool_handle, did, cb) => {
                info!("GetEndpointForDid command received");
                self.get_endpoint_for_did(wallet_handle, pool_handle, did, cb);
            }
            DidCommand::SetDidMetadata(wallet_handle, did, metadata, cb) => {
                info!("SetDidMetadata command received");
                cb(self.set_did_metadata(wallet_handle, did, metadata));
            }
            DidCommand::GetDidMetadata(wallet_handle, did, cb) => {
                info!("GetDidMetadata command received");
                cb(self.get_did_metadata(wallet_handle, did));
            }
            DidCommand::AbbreviateVerkey(did, verkey, cb) => {
                info!("AbbreviateVerkey command received");
                cb(self.abbreviate_verkey(did, verkey));
            }
            DidCommand::GetNymAck(wallet_handle, result, deferred_cmd_id) => {
                info!("GetNymAck command received");
                self.get_nym_ack(wallet_handle, result, deferred_cmd_id);
            }
            DidCommand::GetAttribAck(wallet_handle, result, deferred_cmd_id) => {
                info!("GetAttribAck command received");
                self.get_attrib_ack(wallet_handle, result, deferred_cmd_id);
            }
        };
    }

    fn create_and_store_my_did(&self,
                               wallet_handle: i32,
                               my_did_info_json: &str) -> Result<(String, String), IndyError> {
        debug!("create_and_store_my_did >>> wallet_handle: {:?}, my_did_info_json: {:?}", wallet_handle, my_did_info_json);

        let my_did_info = MyDidInfo::from_json(&my_did_info_json)
            .map_err(map_err_trace!())
            .map_err(|err|
                CommonError::InvalidStructure(
                    format!("Invalid MyDidInfo json: {:?}", err)))?;

        let (did, key) = self.crypto_service.create_my_did(&my_did_info)?;

        if self.wallet_service.record_exists::<Did>(wallet_handle, &did.did)? {
            return Err(IndyError::DidError(DidError::AlreadyExistsError(did.to_string())));
        };

        self.wallet_service.add_indy_object(wallet_handle, &did.did, &did, &HashMap::new())?;
        self.wallet_service.add_indy_object(wallet_handle, &key.verkey, &key, &HashMap::new())?;
{'fraction_non_alphanumeric': 0.12215142023976672, 'fraction_numerical': 0.004860136083810347, 'mean_word_length': 2.544306220095694, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 133, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '745700', 'n_tokens_mistral': 5543, 'n_tokens_neox': 5489, 'n_words': 1007}