<commit_before>// This is the rule definition for demo dice game
// All data structrue are defined in JSON in javascript, and being mapped to variant object in C++, be packed before storing in database
// Validate and parse this script before uploading, tools: http://lisperator.net/uglifyjs/parser
// require("play.js")
// TODO: Add the substitute for FC_CAPTURE_AND_THROW and FC_ASSERT
// TODO: Input: {game_input}, Output: {operation_game_data, wallet_transaction_record, game_result_transaction}

var

PLAY = PLAY || {},

BTS_BLOCKCHAIN_NUM_DELEGATES = 101,

BTS_BLOCKCHAIN_NUM_DICE = BTS_BLOCKCHAIN_NUM_DELEGATES / 10,

BTS_BLOCKCHAIN_DICE_RANGE = 10000,

BTS_BLOCKCHAIN_DICE_HOUSE_EDGE = 0;

PLAY.version = "0.0.2";

// TODO: We should not have the assumption that the asset id equals to game id.
// TODO: The game info and game asset info should be loaded from "outside" when init the game engine instead.
PLAY.game_id = 1;
PLAY.game_asset = {
        asset_id : 1,
        symbol : "DICE"
    };
/*
 * Play this game with input in the context to blockchain and wallet
 * V8_API: wallet::get_transaction_fee [Deprecated]
 * V8_API: blockchain::get_account_record [Deprecated]
 * V8_API: play_account::active_key(deprecated)
 *
 * input is a variant object passed in by v8 api
 * input demo
    {
        "from_account_name": "alice",
        "amount":          	10.2,
        "odds":        		3,
        "guess":        	1
    }
 * provided with PLAY_CODE = [from_account, to_account, amount, memo, PLAY_CODE(optional)]
 * @return PLAY_CODE
 */
PLAY.play = function (blockchain, wallet, input) {
    //try {

    // V8_Vaild
    //FC_ASSERT( input.amount > 0 );
    //FC_ASSERT( input.odds > 0 );

    // V8_API: blockchain::get_asset_record
    var asset_record = blockchain.get_asset_record(PLAY.game_asset.symbol);
    print(asset_record);
    //FC_ASSERT( asset_rec.valid() );

    var amount_to_play = Math.ceil( input.amount * asset_record.precision );
	print( amount_to_play );
    // V8_Valid
    // FC_ASSERT( amount_to_play > 0 );

    // V8_API: constructor for asset, and accessor to id
    var chips_to_play = {
		"amount"  : amount_to_play,
		"asset_id": asset_record.id
	};

	return [input.from_account_name, input.from_account_name, chips_to_play, "play dice"];

    //} FC_CAPTURE_AND_RETHROW( (params) )
};

/*
 * Evaluate the game operation
 *

    // V8_API: eval_state_current_state::store_game_data_record [Deprecated]
    // eval_state_current_state.store_game_data_record(PLAY.game_id, data_index, game_data_rec);
 *
 * @return balances for sub from eval_state and store to pending_state
 * {
	"to_balances": [to_balance],	// will be stored and sub from current eval_state
    "datas" : [game_data]			// if directly return the data_id instead of a object, meaning to remove this data
 * }
 */
PLAY.evaluate = function(eval_state, pending_state, input){
    // V8_Valid
    //if( input.odds < 1 || input.odds < input.guess || input.guess < 1)
    //    FC_CAPTURE_AND_THROW( invalid_dice_odds, (odds) );

    // V8_API: eval_state_current_state::get_asset_record
    var dice_asset_record = pending_state.get_asset_record(PLAY.game_asset.symbol);
	print( dice_asset_record );
    // V8_Valid
    //if( !dice_asset_record )
        //FC_CAPTURE_AND_THROW( unknown_asset_symbol, ( eval_state.trx.id() ) );

	var dice_amount = Math.ceil( input.amount * dice_asset_record.precision );
	print( dice_amount );

	var trx_id = eval_state.get_transaction_id();
	print( trx_id );

	var hash_array = trx_id_to_hash_array(trx_id);
	print ( hash_array );

	var data_index = hash_array[0];
	print ( data_index );

    // For each transaction, there must be only one dice operatiion exist
    // TODO: improve the rule id representation for rule record
    // V8_API: eval_state_current_state::get_game_data_record
    var cur_record = pending_state.get_game_data_record(PLAY.game_id, data_index);
    // V8_Valid
    //if( cur_record )
        //FC_CAPTURE_AND_THROW( duplicate_dice_in_transaction, ( eval_state.trx.id() ) );

	var to_balance = {
		// TODO: Game Logic: this does not means the balance are now stored in balance record, just over pass the api
		// the dice record are not in any balance record, they are over-fly-on-sky.
		// equal to use zero_condition(withdraw_with_signature(), dice_asset_record->id);
      // XTS4Attt64KDdan23RJ1rf98cNPAmAp1YnSN = (convert_to_native_address 1Dice12345612345612345612345XLJ3zy)
		"owner" : "XTS4Attt64KDdan23RJ1rf98cNPAmAp1YnSN",
		"asset" : {
			"amount"  : dice_amount,
			"asset_id": dice_asset_record.id
		}
	};

	// TODO the game data must have a index attr with type uint_32.
    var dice_data = {
        index : data_index,
        amount : dice_amount,
        owner : input.from_account, // self.owner() instead: input.from_account -> active_key -> owner_address -> withdraw_condition -> balance_id
        odds : input.odds,
        guess : input.guess
    };

	return {
		"to_balances" : [to_balance],
		"datas" : [dice_data]
	};
};

// game execute during extain chain and deterministrix transaction apply
PLAY.execute = function (blockchain, block_num, pending_state){
	if (block_num <= BTS_BLOCKCHAIN_NUM_DICE){
   	    return;
	}

	var random_seed = blockchain.get_current_random_seed();
	print(random_seed);

	var hash_array = trx_id_to_hash_array(random_seed);

	var block_random_num = hash_array[0];
	print (block_random_num);

	var range = BTS_BLOCKCHAIN_DICE_RANGE;

	var block_num_of_dice = block_num - BTS_BLOCKCHAIN_NUM_DICE;

	var block_of_dice = blockchain.get_block(block_num_of_dice);
	print(block_of_dice);

	var trxs = block_of_dice.get_transactions();
	print(trxs);

	for (var trx in trxs)
	{
		var id = trx.id();
		// TODO: define the type
		var game_data = blockchain.get_game_data_record(type, trx_id_to_hash_array(id)[0]);

		if (game_data)
		{
			// TODO hash to be defined in V8
			var dice_random_num = trx_id_to_hash_array(id)[0];

			// win condition
            var lucky_number = ( ( ( block_random_num % range ) + ( dice_random_num % range ) ) % range ) * (game_data.odds);
            var guess = game_data.guess;
            var jackpot = 0;
            if ( lucky_number >= (guess - 1) * range && lucky_number < guess * range )
            {
                jackpot = game_data.amount * (game_data.odds) * (100 - BTS_BLOCKCHAIN_DICE_HOUSE_EDGE) / 100;

                // add the jackpot to the accout's balance, give the jackpot from virtul pool to winner

                // TODO: Dice, what should be the slate_id for the withdraw_with_signature, if need, we can set to the jackpot owner?
                var jackpot_balance_address = V8_Global_Get_Balance_ID_For_Owner(game_data.owner, PLAY.game_asset.asset_id);
                var jackpot_payout = pending_state.get_balance_record( jackpot_balance_address );
                if( !jackpot_payout )
                    jackpot_payout = balance_record( game_data.owner, asset(0, PLAY.game_asset.asset_id), PLAY.game_asset.asset_id);
                jackpot_payout.balance += jackpot;
                jackpot_payout.last_update = Date.now();

                pending_state.store_balance_record( jackpot_payout );

                shares_created += jackpot;
            }

            // balance destroyed
            shares_destroyed += game_data.amount;

			// remove the dice_record from pending state after execute the jackpot
            pending_state.store_game_data_record(type, trx_id_to_hash_array(id)[0], null);

            var dice_trx = {
                play_owner : game_data.owner,
                jackpot_owner : game_data.owner,
                play_amount : game_data.amount,
                jackpot_received : jackpot,
                odds : game_data.odds,
                lucky_number : (lucky_number / range) + 1
            };

            // TODO: There is no necessary for game_result_transaction to exsit anymore, dice_trx are directly stored as variant
            game_result_transactions.push(game_result_transaction(dice_trx));
		}
	}

	pending_state.set_game_result_transactions( game_result_transactions );

    // TODO: what is asset_id_type?
	var base_asset_record = pending_state.get_asset_record( asset_id_type(1) );
	// FC_ASSERT( base_asset_record.valid() );
	base_asset_record.current_share_supply += (shares_created - shares_destroyed);
	pending_state.store_asset_record( base_asset_record );
};

PLAY.scan_result = function( game_result_trx, block_num, block_time, trx_index, wallet)
{
    //try {
    // auto gtrx = rtrx.as<dice_transaction>(); game_result_trx now is a variant/js_object it self, so no need to convert
    var win = ( game_result_trx.jackpot_received != 0 );
    var play_result = win ? "win" : "lose";

    // TODO: Dice, play owner might be different with jackpot owner
    // TODO: Accessor get_wallet_key_for_address for wallet
    // TODO: Accessor has_private_key for wallet_key
    // TODO: Property account_address for wallet_key
    var okey_jackpot = wallet.get_wallet_key_for_address( game_result_trx.jackpot_owner );
    if( okey_jackpot && okey_jackpot.has_private_key() )
    {
        var jackpot_account_key = wallet.get_wallet_key_for_address( okey_jackpot.account_address );

        // auto bal_id = withdraw_condition(withdraw_with_signature(gtrx.jackpot_owner), 1 ).get_address();
        // auto bal_rec = _blockchain->get_balance_record( bal_id );

        /* What we paid */
        /*
         auto out_entry = ledger_entry();
         out_entry.from_account = jackpot_account_key;
         out_entry.amount = asset( trx.play_amount );
         std::stringstream out_memo_ss;
         out_memo_ss << "play dice with odds: " << trx.odds;
         out_entry.memo = out_memo_ss.str();
         */

        /* What we received */
        var ledger_entries = [];

        ledger_entries.push({
            // TODO Property public_key for wallet_key
            // TODO: Constructor for asset()
            to_account : jackpot_account_key.public_key,
            amount : asset(game_result_trx.jackpot_received, 1),
            memo : play_result + ", jackpot lucky number: " + game_result_trx.lucky_number
        }
        );

        // TODO: Don't blow away memo, etc.
        var wallet_transaction_record = {
            //  Construct a unique record id, TODO: js method for fc::ripemd160::hash, could refer bitshares-js repository
            // TODO: record_id : fc::ripemd160::hash( "" + block_num + game_result_trx.jackpot_owner + trx_index ),
            block_num : block_num,
            is_virtual : true,
            is_confirmed : true,
            is_market : true,
            ledger_entries : ledger_entries,
            // TODO: Constructor for asset()
            // TODO: Dice, do we need fee for claim jackpot? may be later we'll support part to delegates
            fee : asset(0),
            created_time : block_time,
            received_time : received_time
        };

        // TODO: Accessor store_transaction for wallet
        wallet.store_transaction( wallet_transaction_record );
    }

    return true;

    //} FC_CAPTURE_AND_RETHROW((rtrx))
};

PLAY.scan = function( rule, wallet_transaction_record, wallet )
{
    // TODO: Accessor to type, (withdraw_condition_types)
    // TODO: Define withdraw type constants
    switch( rule.condition.type )
    {
        case withdraw_null_type:
        {
            // TODO
            // FC_THROW( "withdraw_null_type not implemented!" );
            break;
        }
        case withdraw_signature_type:
        {
            // TODO: auto condtion = rule.condition.as<withdraw_with_signature>();
            // TODO: lookup if cached key and work with it only
            // if( _wallet_db.has_private_key( deposit.owner ) )
            if( rule.condtion.memo )
            {
                // TODO: TITAN, FC_THROW( "withdraw_option_type not implemented!" );
                break;
            } else
            {

                var opt_key_rec = wallet.get_wallet_key_for_address(rule.condtion.owner);
                if( opt_key_rec.valid() && opt_key_rec.has_private_key() )
                {
                    // TODO: Refactor this
                    for( var entry in trx_rec.ledger_entries )
                    {
                        // TODO: Read Accessor to_account
                        if( !entry.to_account.valid() )
                        {
                            // TODO: Write Accessor to following properties
                            // TODO: Read Accessor to public_key
                            entry.to_account = opt_key_rec.public_key;
                            // TODO: Constructor asset( amount, 1 )
                            entry.amount = asset( self.amount, PLAY.game_asset.asset_id );
                            entry.memo = "play dice";
                            return true;
                        }
                    }
                }
            }
            break;
        }
        case withdraw_multisig_type:
        {
            // TODO: FC_THROW( "withdraw_multi_sig_type not implemented!" );
            break;
        }
        case withdraw_password_type:
        {
            // TODO: FC_THROW( "withdraw_password_type not implemented!" );
            break;
        }
        default:
        {
            // TODO: FC_THROW( "unknown withdraw condition type!" );
            break;
        }
    }

   return false;
};

// Data structures that is need by this game
/******************
    struct dice_transaction
    {
        static const uint8_t    type;

        dice_transaction(){}

        address                                   play_owner;
        address                                   jackpot_owner;
        share_type                                play_amount;
        share_type                                jackpot_received;
        uint32_t                                  odds;
        uint32_t                                  lucky_number;
    };
    const uint8_t dice_rule::type = dice_rule_type;
    const uint8_t dice_transaction::type = dice_rule_type;
**************/

<commit_msg>update execute api<commit_after>// This is the rule definition for demo dice game
// All data structrue are defined in JSON in javascript, and being mapped to variant object in C++, be packed before storing in database
// Validate and parse this script before uploading, tools: http://lisperator.net/uglifyjs/parser
// require("play.js")
// TODO: Add the substitute for FC_CAPTURE_AND_THROW and FC_ASSERT
// TODO: Input: {game_input}, Output: {operation_game_data, wallet_transaction_record, game_result_transaction}

var

PLAY = PLAY || {},

BTS_BLOCKCHAIN_NUM_DELEGATES = 101,

BTS_BLOCKCHAIN_NUM_DICE = Math.floor(BTS_BLOCKCHAIN_NUM_DELEGATES / 10),

BTS_BLOCKCHAIN_DICE_RANGE = 10000,

BTS_BLOCKCHAIN_DICE_HOUSE_EDGE = 0;

PLAY.version = "0.0.2";

// TODO: We should not have the assumption that the asset id equals to game id.
// TODO: The game info and game asset info should be loaded from "outside" when init the game engine instead.
PLAY.game_id = 1;
PLAY.game_asset = {
        asset_id : 1,
        symbol : "DICE"
    };
/*
 * Play this game with input in the context to blockchain and wallet
 * V8_API: wallet::get_transaction_fee [Deprecated]
 * V8_API: blockchain::get_account_record [Deprecated]
 * V8_API: play_account::active_key(deprecated)
 *
 * input is a variant object passed in by v8 api
 * input demo
    {
        "from_account_name": "alice",
        "amount":             10.2,
        "odds":            3,
        "guess":           1
    }
 * provided with PLAY_CODE = [from_account, to_account, amount, memo, PLAY_CODE(optional)]
 * @return PLAY_CODE
 */
PLAY.play = function (blockchain, wallet, input) {
    //try {

    // V8_Vaild
    //FC_ASSERT( input.amount > 0 );
    //FC_ASSERT( input.odds > 0 );

    // V8_API: blockchain::get_asset_record
    var asset_record = blockchain.get_asset_record(PLAY.game_asset.symbol);
    print(asset_record);
    //FC_ASSERT( asset_rec.valid() );

    var amount_to_play = Math.ceil( input.amount * asset_record.precision );
   print( amount_to_play );
    // V8_Valid
    // FC_ASSERT( amount_to_play > 0 );

    // V8_API: constructor for asset, and accessor to id
    var chips_to_play = {
      "amount"  : amount_to_play,
      "asset_id": asset_record.id
   };

   return [input.from_account_name, input.from_account_name, chips_to_play, "play dice"];

    //} FC_CAPTURE_AND_RETHROW( (params) )
};

/*
 * Evaluate the game operation
 *

    // V8_API: eval_state_current_state::store_game_data_record [Deprecated]
    // eval_state_current_state.store_game_data_record(PLAY.game_id, data_index, game_data_rec);
 *
 * @return balances for sub from eval_state and store to pending_state
 * {
   "to_balances": [to_balance],  // will be stored and sub from current eval_state
    "datas" : [game_data]        // if directly return the data_id instead of a object, meaning to remove this data
 * }
 */
PLAY.evaluate = function(eval_state, pending_state, input){
    // V8_Valid
    //if( input.odds < 1 || input.odds < input.guess || input.guess < 1)
    //    FC_CAPTURE_AND_THROW( invalid_dice_odds, (odds) );

    // V8_API: eval_state_current_state::get_asset_record
    var dice_asset_record = pending_state.get_asset_record(PLAY.game_asset.symbol);
   print( dice_asset_record );
    // V8_Valid
    //if( !dice_asset_record )
        //FC_CAPTURE_AND_THROW( unknown_asset_symbol, ( eval_state.trx.id() ) );

   var dice_amount = Math.ceil( input.amount * dice_asset_record.precision );
   print( dice_amount );

   var trx_id = eval_state.get_transaction_id();
   print( trx_id );

   var hash_array = trx_id_to_hash_array(trx_id);
   print ( hash_array );

   var data_index = hash_array[0];
   print ( data_index );

    // For each transaction, there must be only one dice operatiion exist
    // TODO: improve the rule id representation for rule record
    // V8_API: eval_state_current_state::get_game_data_record
    var cur_record = pending_state.get_game_data_record(PLAY.game_id, data_index);
    // V8_Valid
    //if( cur_record )
        //FC_CAPTURE_AND_THROW( duplicate_dice_in_transaction, ( eval_state.trx.id() ) );

   var to_balance = {
      // TODO: Game Logic: this does not means the balance are now stored in balance record, just over pass the api
      // the dice record are not in any balance record, they are over-fly-on-sky.
      // equal to use zero_condition(withdraw_with_signature(), dice_asset_record->id);
      // XTS4Attt64KDdan23RJ1rf98cNPAmAp1YnSN = (convert_to_native_address 1Dice12345612345612345612345XLJ3zy)
      "owner" : "XTS4Attt64KDdan23RJ1rf98cNPAmAp1YnSN",
      "asset" : {
         "amount"  : dice_amount,
         "asset_id": dice_asset_record.id
      }
   };

   // TODO the game data must have a index attr with type uint_32.
    var dice_data = {
        index : data_index,
        amount : dice_amount,
        owner : input.from_account, // self.owner() instead: input.from_account -> active_key -> owner_address -> withdraw_condition -> balance_id
        odds : input.odds,
        guess : input.guess
    };

   return {
      "to_balances" : [to_balance],
      "datas" : [dice_data]
   };
};

// game execute during extain chain and deterministrix transaction apply
// @return
// 	0: if nothing need to done
//  {"execute_results": [game_result_transactions], "game_datas": [], "diff_balances": [balances_to_update], "diff_supply": [assets]}
PLAY.execute = function (blockchain, block_num, pending_state){
   print("block number is" + block_num);
   if (block_num <= BTS_BLOCKCHAIN_NUM_DICE){
          return 0;
   }

   var random_seed = blockchain.get_current_random_seed();
   print(random_seed);

   var hash_array = trx_id_to_hash_array(random_seed);

   var block_random_num = hash_array[0];
   print (block_random_num);

   var range = BTS_BLOCKCHAIN_DICE_RANGE;

   var block_num_of_dice = block_num - BTS_BLOCKCHAIN_NUM_DICE;
   print(block_num_of_dice);

   var block_digest_of_dice = blockchain.get_block_digest(block_num_of_dice);
   print(block_digest_of_dice);

   var shares_destroyed = 0;
   var shares_created = 0;
   var result = {"execute_results": [], "game_datas": [], "diff_balances": [], "diff_supply": []};
   for (var trx_id in block_digest_of_dice.user_transaction_ids)
   {
      var id = user_transaction_ids;
	  var data_id = trx_id_to_hash_array(id)[0];

      var game_data = blockchain.get_game_data_record(PLAY.game_id, data_id);
	  print(game_data);

      if (game_data)
      {
         // TODO hash to be defined in V8
         var dice_random_num = trx_id_to_hash_array(id)[0];

         // win condition
            var lucky_number = ( ( ( block_random_num % range ) + ( dice_random_num % range ) ) % range ) * (game_data.odds);
            var guess = game_data.guess;
            var jackpot = 0;
            if ( lucky_number >= (guess - 1) * range && lucky_number < guess * range )
            {
                jackpot = game_data.amount * (game_data.odds) * (100 - BTS_BLOCKCHAIN_DICE_HOUSE_EDGE) / 100;

                // add the jackpot to the accout's balance, give the jackpot from virtul pool to winner
                result["diff_balances"].push(
						{
					      "owner" : game_data.owner,
					      "asset" : {
					         "amount"  : jackpot,
					         "asset_id": PLAY.game_asset.asset_id
					      }
					   }
                );

                shares_created += jackpot;
            }

            // balance destroyed
            shares_destroyed += game_data.amount;

         	// remove the dice_record from pending state after execute the jackpot
			result["game_datas"].push(data_id);	// meaning to remove it if directly return the data_id itself

            var dice_trx = {
                play_owner : game_data.owner,
                jackpot_owner : game_data.owner,
                play_amount : game_data.amount,
                jackpot_received : jackpot,
                odds : game_data.odds,
                lucky_number : (lucky_number / range) + 1
            };

            result["execute_results"].push( dice_trx ); // game_result_transaction.data = dice_trx;
      }
   }

   result["diff_balances"].push({
      // TODO: Game Logic: this does not means the balance are now stored in balance record, just over pass the api
      // the dice record are not in any balance record, they are over-fly-on-sky.
      // equal to use zero_condition(withdraw_with_signature(), dice_asset_record->id);
      // XTS4Attt64KDdan23RJ1rf98cNPAmAp1YnSN = (convert_to_native_address 1Dice12345612345612345612345XLJ3zy)
      "owner" : "XTS4Attt64KDdan23RJ1rf98cNPAmAp1YnSN",
      "asset" : {
         "amount"  : -shares_destroyed,
         "asset_id": PLAY.game_asset.asset_id
      }
   });

   result["diff_supply"].push(
	   {
		   "amount"  : (shares_created - shares_destroyed),	// base_asset_record.current_share_supply += (shares_created - shares_destroyed);
		   "asset_id": PLAY.game_asset.asset_id
	   }
   );

   return result;
};

PLAY.scan_result = function( game_result_trx, block_num, block_time, trx_index, wallet)
{
    //try {
    // auto gtrx = rtrx.as<dice_transaction>(); game_result_trx now is a variant/js_object it self, so no need to convert
    var win = ( game_result_trx.jackpot_received != 0 );
    var play_result = win ? "win" : "lose";

    // TODO: Dice, play owner might be different with jackpot owner
    // TODO: Accessor get_wallet_key_for_address for wallet
    // TODO: Accessor has_private_key for wallet_key
    // TODO: Property account_address for wallet_key
    var okey_jackpot = wallet.get_wallet_key_for_address( game_result_trx.jackpot_owner );
    if( okey_jackpot && okey_jackpot.has_private_key() )
    {
        var jackpot_account_key = wallet.get_wallet_key_for_address( okey_jackpot.account_address );

        // auto bal_id = withdraw_condition(withdraw_with_signature(gtrx.jackpot_owner), 1 ).get_address();
        // auto bal_rec = _blockchain->get_balance_record( bal_id );

        /* What we paid */
        /*
         auto out_entry = ledger_entry();
         out_entry.from_account = jackpot_account_key;
         out_entry.amount = asset( trx.play_amount );
         std::stringstream out_memo_ss;
         out_memo_ss << "play dice with odds: " << trx.odds;
         out_entry.memo = out_memo_ss.str();
         */

        /* What we received */
        var ledger_entries = [];

        ledger_entries.push({
            // TODO Property public_key for wallet_key
            // TODO: Constructor for asset()
            to_account : jackpot_account_key.public_key,
            amount : asset(game_result_trx.jackpot_received, 1),
            memo : play_result + ", jackpot lucky number: " + game_result_trx.lucky_number
        }
        );

        // TODO: Don't blow away memo, etc.
        var wallet_transaction_record = {
            //  Construct a unique record id, TODO: js method for fc::ripemd160::hash, could refer bitshares-js repository
            // TODO: record_id : fc::ripemd160::hash( "" + block_num + game_result_trx.jackpot_owner + trx_index ),
            block_num : block_num,
            is_virtual : true,
            is_confirmed : true,
            is_market : true,
            ledger_entries : ledger_entries,
            // TODO: Constructor for asset()
            // TODO: Dice, do we need fee for claim jackpot? may be later we'll support part to delegates
            fee : asset(0),
            created_time : block_time,
            received_time : received_time
        };

        // TODO: Accessor store_transaction for wallet
        wallet.store_transaction( wallet_transaction_record );
    }

    return true;

    //} FC_CAPTURE_AND_RETHROW((rtrx))
};

PLAY.scan = function( rule, wallet_transaction_record, wallet )
{
    // TODO: Accessor to type, (withdraw_condition_types)
    // TODO: Define withdraw type constants
    switch( rule.condition.type )
    {
        case withdraw_null_type:
        {
            // TODO
            // FC_THROW( "withdraw_null_type not implemented!" );
            break;
        }
        case withdraw_signature_type:
        {
            // TODO: auto condtion = rule.condition.as<withdraw_with_signature>();
            // TODO: lookup if cached key and work with it only
            // if( _wallet_db.has_private_key( deposit.owner ) )
            if( rule.condtion.memo )
            {
                // TODO: TITAN, FC_THROW( "withdraw_option_type not implemented!" );
                break;
            } else
            {

                var opt_key_rec = wallet.get_wallet_key_for_address(rule.condtion.owner);
                if( opt_key_rec.valid() && opt_key_rec.has_private_key() )
                {
                    // TODO: Refactor this
                    for( var entry in trx_rec.ledger_entries )
                    {
                        // TODO: Read Accessor to_account
                        if( !entry.to_account.valid() )
                        {
                            // TODO: Write Accessor to following properties
                            // TODO: Read Accessor to public_key
                            entry.to_account = opt_key_rec.public_key;
                            // TODO: Constructor asset( amount, 1 )
                            entry.amount = asset( self.amount, PLAY.game_asset.asset_id );
                            entry.memo = "play dice";
                            return true;
                        }
                    }
                }
            }
            break;
        }
        case withdraw_multisig_type:
        {
            // TODO: FC_THROW( "withdraw_multi_sig_type not implemented!" );
            break;
        }
        case withdraw_password_type:
        {
            // TODO: FC_THROW( "withdraw_password_type not implemented!" );
            break;
        }
        default:
        {
            // TODO: FC_THROW( "unknown withdraw condition type!" );
            break;
        }
    }

   return false;
};

<|endoftext|>


<commit_before>/**
 * @fileoverview Externs for backbone-0.9.1.js
 *
 * built with http://www.dotnetwise.com/Code/Externs/index.html
 * see also: http://blog.dotnetwise.com/2009/11/closure-compiler-externs-extractor.html
 * via: http://code.google.com/p/closure-compiler/wiki/FAQ#How_do_I_write_an_externs_file?
 *
 * Note: when building via that page, you first need to load in underscrore.js, as that's a dependency.
 *       also, after running the extern for Backbone, you need to manually run it for:
 *       Backbone.Model.prototype, Backbone.Collection.prototype, Backbone.Router.prototype,
 *       Backbone.History.prototype, and Backbone.View.prototype
 *       because these objects are modified using _.extend(Backbone.Model.prototype ...)
 * @see http://documentcloud.github.com/backbone/
 * @externs
 */

var Backbone = {
    "VERSION": {},
    "setDomLibrary": function () {},
    "noConflict": function () {},
    "emulateHTTP": {},
    "emulateJSON": {},
    "Events": {
        "on": function () {},
        "off": function () {},
        "trigger": function () {},
        "bind": function () {},
        "unbind": function () {}
    },
    "Collection": function () {},
    "Router": function () {},
    "History": function () {},
    "View": function () {},
    "sync": function () {},
    "wrapError": function () {}
};
/**
 * @constructor
 * @param {Object=} config
 */
Backbone.Model = function(config) {};
Backbone.Model.prototype = {
    "on": function () {},
    "off": function () {},
    "trigger": function () {},
    "bind": function () {},
    "unbind": function () {},
    "idAttribute": {},
    "initialize": function () {},
    "toJSON": function () {},
    "get": function () {},
    "escape": function () {},
    "has": function () {},
    "set": function () {},
    "unset": function () {},
    "clear": function () {},
    "fetch": function () {},
    "save": function () {},
    "destroy": function () {},
    "url": function () {},
    "parse": function () {},
    "clone": function () {},
    "isNew": function () {},
    "change": function () {},
    "hasChanged": function () {},
    "changedAttributes": function () {},
    "previous": function () {},
    "previousAttributes": function () {},
    "isValid": function () {},
    "_validate": function () {}
};
/**
 * @constructor
 */
Backbone.Collection = function() {};
/** @type {Array} */
Backbone.Collection.prototype.models;
Backbone.Collection.prototype = {
    "on": function () {},
    "off": function () {},
    "trigger": function () {},
    "bind": function () {},
    "unbind": function () {},
    "model": function () {},
    "initialize": function () {},
    "toJSON": function () {},
    "add": function () {},
    "remove": function () {},
    "get": function () {},
    "getByCid": function () {},
    "at": function () {},
    "sort": function () {},
    "pluck": function () {},
    "reset": function () {},
    "fetch": function () {},
    "create": function () {},
    "parse": function () {},
    "chain": function () {},
    "_reset": function () {},
    "_prepareModel": function () {},
    "_removeReference": function () {},
    "_onModelEvent": function () {},
    "forEach": function () {},
    "each": function () {},
    "map": function () {},
    "reduce": function () {},
    "reduceRight": function () {},
    "find": function () {},
    "detect": function () {},
    "filter": function () {},
    "select": function () {},
    "reject": function () {},
    "every": function () {},
    "all": function () {},
    "some": function () {},
    "any": function () {},
    "include": function () {},
    "contains": function () {},
    "invoke": function () {},
    "max": function () {},
    "min": function () {},
    "sortBy": function () {},
    "sortedIndex": function () {},
    "toArray": function () {},
    "size": function () {},
    "first": function () {},
    "initial": function () {},
    "rest": function () {},
    "last": function () {},
    "without": function () {},
    "indexOf": function () {},
    "shuffle": function () {},
    "lastIndexOf": function () {},
    "isEmpty": function () {},
    "groupBy": function () {}
};
Backbone.Router.prototype = {
    "on": function () {},
    "off": function () {},
    "trigger": function () {},
    "bind": function () {},
    "unbind": function () {},
    "initialize": function () {},
    "route": function () {},
    "navigate": function () {},
    "_bindRoutes": function () {},
    "_routeToRegExp": function () {},
    "_extractParameters": function () {}
};
Backbone.History.prototype = {
    "on": function () {},
    "off": function () {},
    "trigger": function () {},
    "bind": function () {},
    "unbind": function () {},
    "interval": {},
    "getFragment": function () {},
    "start": function () {},
    "stop": function () {},
    "route": function () {},
    "checkUrl": function () {},
    "loadUrl": function () {},
    "navigate": function () {},
    "_updateHash": function () {}
};
/**
 * @param {...*} args
 * @constructor
 */
Backbone.View = function(args){};
/** @type {string} */
Backbone.View.prototype.tagName;
/**
 * @param {...*} args
 */
Backbone.View.prototype.initialize = function(args) {};
/**
 * @return {Backbone.View}
 */
Backbone.View.prototype.render = function(){};
/** @type {Element} */
Backbone.View.prototype.el;
/** @type {jQuery} */
Backbone.View.prototype.$el;
Backbone.View.prototype.remove = function(){};
/**
 * @param {string} tagName
 * @param {Object=} attributes
 * @param {string=} content
 */
Backbone.View.prototype.make = function(tagName, attributes, content){};
Backbone.View.prototype.remove = function(){};
/**
 * @param {Object=} events
 */
Backbone.View.prototype.delegateEvents = function(events){};
/**
 * @param {Object=} events
 */
Backbone.View.prototype.undelegateEvents = function(events){};
<commit_msg>Work in progress on backbone externs. Externs for Backbone.Model and Backbone.Events completed.<commit_after>/**
 * @fileoverview Externs for backbone-0.9.1.js
 *
 * built with http://www.dotnetwise.com/Code/Externs/index.html
 * see also: http://blog.dotnetwise.com/2009/11/closure-compiler-externs-extractor.html
 * via: http://code.google.com/p/closure-compiler/wiki/FAQ#How_do_I_write_an_externs_file?
 *
 * Note: when building via that page, you first need to load in underscrore.js, as that's a dependency.
 *       also, after running the extern for Backbone, you need to manually run it for:
 *       Backbone.Model.prototype, Backbone.Collection.prototype, Backbone.Router.prototype,
 *       Backbone.History.prototype, and Backbone.View.prototype
 *       because these objects are modified using _.extend(Backbone.Model.prototype ...)
 * @see http://documentcloud.github.com/backbone/
 * @externs
 */

var Backbone = {
    "VERSION": {},
    "setDomLibrary": function () {},
    "noConflict": function () {},
    "emulateHTTP": {},
    "emulateJSON": {},
    "Collection": function () {},
    "Router": function () {},
    "History": function () {},
    "View": function () {},
    "sync": function () {},
    "wrapError": function () {}
};

/**
 * @typedef {Object}
 */
Backbone.Events = {};

/**
 * @param {string} event
 * @param {Function} callback
 * @param {Object=} context
 */
Backbone.Events.on = function(event, callback, context) {};
Backbone.Events.bind = Backbone.Events.on;

/**
 * @param {string=} event
 * @param {Function=} callback
 * @param {Object=} context
 */
Backbone.Events.off = function(event, callback, context) {};
Backbone.Events.unbind = Backbone.Events.off;

/**
 * @param {string} event
 * @param {...*} args
 */
Backbone.Events.trigger = function(event, args) {};

/**
 * @extends {Backbone.Events}
 * @constructor
 * @param {Object=} config
 */
Backbone.Model = function(config) {};

/**
 * @param {Object} properties
 * @param {Object=} classProperties
 */
Backbone.Model.prototype.extend = function(properties, classProperties) {};

/**
 * @param {...*} config
 */
Backbone.Model.prototype.initialize = function(config) {};

/**
 * @param {string} attribute
 * @return {*}
 */
Backbone.Model.prototype.get = function(attribute) {};

/**
 * @param {string|Object} key
 * @param {*} value
 * @param {Object=} options
 * @return {Backbone.Model}
 */
Backbone.Model.prototype.set = function(key, value, options) {};

/**
 * @param {string} attribute
 * @return {string}
 */
Backbone.Model.prototype.escape = function(attribute) {};

/**
 * @param {string} attribute
 * @return {boolean}
 */
Backbone.Model.prototype.has = function(attribute) {};

/**
 * @param {string} attribute
 * @param {Object=} options
 * @return {Backbone.Model}
 */
Backbone.Model.prototype.unset = function(attribute, options) {};

/**
 * @param {Object=} options
 */
Backbone.Model.prototype.clear = function(options) {};

/** @type {number} */
Backbone.Model.id;

/** @type {string} */
Backbone.Model.prototype.idAttribute;

/** @type {number} */
Backbone.Model.cid;

/** @type {Object} */
Backbone.Model.attributes;

/** @type {Object} */
Backbone.Model.changed;

/** @type {Object|Function} */
Backbone.Model.defaults;

/**
 * @return {Object}
 */
Backbone.Model.toJSON();

/**
 * @param {Object} options
 * @return {Object} returns jQuery xhr
 */
Backbone.Model.prototype.fetch = function(options) {};

/**
 * @param {string|Object} key
 * @param {*} value
 * @param {Object=} options
 * @return {boolean|Object}
 */
Backbone.Model.prototype.save = function(key, value, options) {};

/**
 * @param {Object} options
 * @return {boolean|Object}
 */
Backbone.Model.prototype.destroy = function(options) {};

/**
 * @param {Object} attributes
 */
Backbone.Model.prototype.validate = function(attributes) {};

/**
 * @return {boolean}
 */
Backbone.Model.prototype.isValid = function() {};

/**
 * @return {string}
 */
Backbone.Model.prototype.url = function() {};

/** @type {string|Function} */
Backbone.Model.urlRoot;

/**
 * @param {Object} resp
 * @param {Object} xhr
 * @return {Object}
 */
Backbone.Model.prototype.parse = function(resp, xhr) {};

/**
 * @return {Backbone.Model}
 */
Backbone.Model.prototype.clone = function() {};

/**
 * @return {boolean}
 */
Backbone.Model.prototype.isNew = function() {};

/**
 * @return {Backbone.Model}
 */
Backbone.Model.prototype.change = function() {};

/**
 * @param {Object} attributes
 * @return {boolean}
 */
Backbone.Model.prototype.hasChanged = function(attributes) {};

/**
 * @param {Object} attributes
 * @return {Object}
 */
Backbone.Model.prototype.changedAttributes = function(attributes) {};

/**
 * @param {string} attribute
 * @return {*}
 */
Backbone.Model.prototype.previous = function(attribute) {};

/**
 * @return {Object}
 */
Backbone.Model.prototype.previousAttributes = function() {};

/**
 * @constructor
 */
Backbone.Collection = function() {};
/** @type {Array} */
Backbone.Collection.prototype.models;
Backbone.Collection.prototype = {
    "on": function () {},
    "off": function () {},
    "trigger": function () {},
    "bind": function () {},
    "unbind": function () {},
    "model": function () {},
    "initialize": function () {},
    "toJSON": function () {},
    "add": function () {},
    "remove": function () {},
    "get": function () {},
    "getByCid": function () {},
    "at": function () {},
    "sort": function () {},
    "pluck": function () {},
    "reset": function () {},
    "fetch": function () {},
    "create": function () {},
    "parse": function () {},
    "chain": function () {},
    "_reset": function () {},
    "_prepareModel": function () {},
    "_removeReference": function () {},
    "_onModelEvent": function () {},
    "forEach": function () {},
    "each": function () {},
    "map": function () {},
    "reduce": function () {},
    "reduceRight": function () {},
    "find": function () {},
    "detect": function () {},
    "filter": function () {},
    "select": function () {},
    "reject": function () {},
    "every": function () {},
    "all": function () {},
    "some": function () {},
    "any": function () {},
    "include": function () {},
    "contains": function () {},
    "invoke": function () {},
    "max": function () {},
    "min": function () {},
    "sortBy": function () {},
    "sortedIndex": function () {},
    "toArray": function () {},
    "size": function () {},
    "first": function () {},
    "initial": function () {},
    "rest": function () {},
    "last": function () {},
    "without": function () {},
    "indexOf": function () {},
    "shuffle": function () {},
    "lastIndexOf": function () {},
    "isEmpty": function () {},
    "groupBy": function () {}
};
Backbone.Router.prototype = {
    "on": function () {},
    "off": function () {},
    "trigger": function () {},
    "bind": function () {},
    "unbind": function () {},
    "initialize": function () {},
    "route": function () {},
    "navigate": function () {},
    "_bindRoutes": function () {},
    "_routeToRegExp": function () {},
    "_extractParameters": function () {}
};
Backbone.History.prototype = {
    "on": function () {},
    "off": function () {},
    "trigger": function () {},
    "bind": function () {},
    "unbind": function () {},
    "interval": {},
    "getFragment": function () {},
    "start": function () {},
    "stop": function () {},
    "route": function () {},
    "checkUrl": function () {},
    "loadUrl": function () {},
    "navigate": function () {},
    "_updateHash": function () {}
};
/**
 * @param {...*} args
 * @constructor
 */
Backbone.View = function(args){};
/** @type {string} */
Backbone.View.prototype.tagName;
/**
 * @param {...*} args
 */
Backbone.View.prototype.initialize = function(args) {};
/**
 * @return {Backbone.View}
 */
Backbone.View.prototype.render = function(){};
/** @type {Element} */
Backbone.View.prototype.el;
/** @type {jQuery} */
Backbone.View.prototype.$el;
Backbone.View.prototype.remove = function(){};
/**
 * @param {string} tagName
 * @param {Object=} attributes
 * @param {string=} content
 */
Backbone.View.prototype.make = function(tagName, attributes, content){};
Backbone.View.prototype.remove = function(){};
/**
 * @param {Object=} events
 */
Backbone.View.prototype.delegateEvents = function(events){};
/**
 * @param {Object=} events
 */
Backbone.View.prototype.undelegateEvents = function(events){};
<|endoftext|>


<commit_before>/*
 * hbSlider -- HighBridge Slider
 *
 */

(function($)
{
    /*************************
     *
     *  Helper functions
     *
     ************************/

    // Initialize slider
    function init(slider)
    {
        // Ensure a pane is set as current on load
        if($(slider).find('.slide-pane.current').length == 0)
            $(slider).find('.slide-pane').eq(0).addClass('current active');

        var offset = $(slider).find('.slide-pane').eq(0).outerWidth(true);

        // Determine visible panes
        for(var i = 1, l = slider.options.display; i < l; i++)
        {
            var pane = $(slider).find('.slide-pane').eq(i);

            TweenLite.set(pane[0], {x: offset+'px'});
            offset += pane.outerWidth(true);

            pane.addClass('active');
        }
    }

    function calculate_duration(slider, distance, duration)
    {
        return distance * duration / $(slider).width();
    }

    function animate(slide)
    {
        var slider = this;
        slider.animating = true;

        // Where are we now?
        var from = $(slider).find('.slide-pane.current');

        // Where are we moving to?
        var to = $(slider).find('.slide-pane').eq(slide.index);

        // Add a class on the slide we're moving to
        to.addClass('sliding-to');

        // Find the difference between the index of current pane and the index of where we're sliding to
        var difference;

        // If the index we're moving to is less than the current index and we're moving left
        if(to.index() < from.index() && slide.direction == 'left')
            difference = (to.index() + $(slider).find('.slide-pane').length) - from.index();

        // If the index we're moving to is greater than the current index and we're moving right
        else if(to.index() > from.index() && slide.direction == 'right')
            difference = (from.index() + $(slider).find('.slide-pane').length) - to.index();

        // Else...
        else
            difference = Math.abs(from.index() - to.index());

        var queue = {};
        var offset_to = (slide.direction == 'right') ? $(slider).width() : 0;

        if(slide.direction == 'right')
        {
            if(difference < slider.options.display)
            {
                for(var i = from.index() + slider.options.display, l = from.index(); i > l; i--)
                {
                    var index = i - 1;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                    offset_to += pane.outerWidth(true);
                }
            }
            else
            {
                // Start at current index
                for(var i = from.index(), l = from.index() + slider.options.display; i < l; i++)
                {
                    var index = i;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                    offset_to += pane.outerWidth(true);
                }
            }
        }
        else
        {
            if(difference < slider.options.display)
            {
                for(var i = from.index(), l = from.index() + slider.options.display; i < l; i++)
                {
                    var index = i;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    offset_to -= pane.outerWidth(true);
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                }
            }
            else
            {
                for(var i = from.index() + slider.options.display, l = from.index(); i > l; i--)
                {
                    var index = i - 1;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    offset_to -= pane.outerWidth(true);
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                }
            }
        }

        var offset_from = (slide.direction == 'right') ? 0 : $(slider).width();
        var offset_to = (slide.direction == 'right') ? $(slider).width() : 0;

        if(slide.direction == 'right')
        {
            for(var i = slide.index + slider.options.display, l = slide.index; i > l; i--)
            {
                var index = i - 1;

                if(index >= $(slider).find('.slide-pane').length)
                    index -= $(slider).find('.slide-pane').length;

                var pane = $(slider).find('.slide-pane').eq(index);

                if(!pane.hasClass('active'))
                {
                    pane.addClass('active');

                    offset_from -= pane.outerWidth(true);
                    offset_to -= pane.outerWidth(true);

                    queue[index] = {from: offset_from, to: offset_to, status: 'active'};
                }
                else
                {
                    offset_to -= pane.outerWidth(true);
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'active'};
                }
            }
        }
        else
        {
            // Start at slide.index, until index + slider.options.display
            for(var i = slide.index, l = slide.index + slider.options.display; i < l; i++)
            {
                var index = i;

                if(index >= $(slider).find('.slide-pane').length)
                    index -= $(slider).find('.slide-pane').length;

                var pane = $(slider).find('.slide-pane').eq(index);

                if(!pane.hasClass('active'))
                {
                    pane.addClass('active');
                    queue[index] = {from: offset_from, to: offset_to, status: 'active'};

                    offset_from += pane.outerWidth(true);
                    offset_to += pane.outerWidth(true);
                }
                else
                {
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'active'};
                    offset_to += pane.outerWidth(true);
                }
            }
        }

        // Trigger resize if this is a dynamic height slider
        if(slider.options.dynamicHeight)
        {
            $(window).trigger('resize', {animation: true});
        }

        for(var i = 0, keys = Object.keys(queue), l = keys.length; i < l; ++i)
        {
            var index = keys[i];
            var data = queue[keys[i]];
            var pane = $(slider).find('.slide-pane').eq(index);
            var duration = calculate_duration(slider, Math.abs(data.from - data.to), slider.options.duration);

            pane.addClass('animating');
            TweenLite.fromTo(pane[0], duration, {x: data.from}, {x: data.to, onComplete: animated, onCompleteParams: [slider, slide, data.status]});
        }
    }

    function animated(slider, slide, status)
    {
        var pane = $(this.target);

        $(slider).find('.slide-pane.current').removeClass('current');
        $(slider).find('.slide-pane').eq(slide.index).addClass('current').removeClass('sliding-to');

        if(status == 'active')
            pane.addClass('active');
        else
            pane.removeClass('active');

        pane.removeClass('animating');

        if($(slider).find('.animating').length == 0)
        {
            slider.animating = false;
            if(typeof slider.options.slideEnd == "function") slider.options.slideEnd.call(slider);
        }
    }

    /*************************
     *
     *  Main slider code
     *
     ************************/

    var Slider = function(input)
    {
        var slider = this;

        // Define default slider.options
        slider.options = {display: 1, duration: 0.5, dynamicHeight: false};
        slider.options = $.extend(slider.options, input);

        init(slider);

        // When resize is triggered
        $(window).on('resize', function(event, params)
        {
            // First clear any previous styles set on the slider
            $(slider).removeAttr('style');

            // If the slider isn't disabled
            if(!$(slider).hasClass('disabled'))
            {
                // Animate slider to use the height of the slide we're sliding to
                if(slider.options.dynamicHeight)
                {
                    var pane = $(slider).find('.sliding-to');
                    var parent = $(slider);

                    pane.css('height', 'auto');
                    parent.height(pane.outerHeight(true));
                    pane.css('height', '100%');
                }
                // Else, if this is a static height slider
                else
                {
                    // Loop through all panes and set the container height to the maximum pane height
                    $(slider).find('.slide-pane').each(function()
                    {
                        $(this).css('height', 'auto');
                        var parent = $(slider);

                        if($(this).outerHeight(true) > parent.height())
                        {
                            parent.height($(this).outerHeight(true));
                        }

                        $(this).css('height', '100%');
                    });
                }

                // Only trigger slide resize if this event wasn't triggered by animation
                if(params === undefined || !params.animation)
                {
                    $(slider).trigger('slide-resize');
                }
            }
        });

        // Trigger resize now to try to position everything
        $(window).trigger('resize');

        // Trigger resize again once the window is fully loaded
        $(window).load(function()
        {
            $(window).trigger('resize');
        });

        // Convenience event for going to the next pane
        $(slider).on('slide-next', function()
        {
            var current = $(slider).find('.slide-pane.current');
            var index = current.index();

            var next = index + 1;

            if(next >= $(slider).find('.slide-pane').length)
                next = 0;

            $(slider).trigger('slide-to', next);
        });

        // Convenience event for going to the previous pane
        $(slider).on('slide-prev', function()
        {
            var current = $(slider).find('.slide-pane.current');
            var index = current.index();

            var prev = index - 1;

            if(prev < 0)
                prev = $(slider).find('.slide-pane').length - 1;

            $(slider).trigger('slide-to', prev);
        });

        $(slider).on('slide-resize', function()
        {
            // Find the current pane
            var current = $(slider).find('.slide-pane.current').index();

            // Trigger slide to current, fixing any potential difference in positioning
            $(slider).trigger('slide-to', current);
        });

        // Allows sliding to any pane based on its index
        $(slider).on('slide-to', function(event, input)
        {
            var slide = {index: 0, direction: 'left'};

            // If our request is an object
            if(typeof input == "object") $.extend(slide, input);
            // Else if the request is simply a number
            if(input == parseInt(input))   slide.index = input;

            var from = $(slider).find('.slide-pane.current');
            var to = $(slider).find('.slide-pane').eq(slide.index);
            var last = $(slider).find('.slide-pane').length - 1;

            // If the pane we're moving to comes before the current, move right
            if(from.index() > to.index())
                slide.direction = 'right';

            // If the pane we're moving to comes after the current, move left
            if(from.index() < to.index())
                slide.direction = 'left';

            // If we're moving to the last pane from the first
            if(from.index() == 0 && to.index() == last)
                slide.direction = 'right';

            // If we're moving to the first pane from the last
            if(from.index() == last && to.index() == 0)
                slide.direction = 'left';

            if(!slider.animating && !$(slider).hasClass('disabled'))
            {
                animate.call(slider, slide);
                if(typeof slider.options != "undefined" && typeof slider.options.slideStart == "function") slider.options.slideStart.call(slider);
            }
        });
    };

    /*************************
     *
     *  Bind to jQuery
     *
     ************************/

    $.fn.hbSlider = function(options)
    {
        for(var i = 0, l = this.length; i < l; i++)
        {
            Slider.call(this[i], options);
        }
    };
})(jQuery);
<commit_msg>Added checks to only resize slider when panes are sliding<commit_after>/*
 * hbSlider -- HighBridge Slider
 *
 */

(function($)
{
    /*************************
     *
     *  Helper functions
     *
     ************************/

    // Initialize slider
    function init(slider)
    {
        // Ensure a pane is set as current on load
        if($(slider).find('.slide-pane.current').length == 0)
            $(slider).find('.slide-pane').eq(0).addClass('current active');

        var offset = $(slider).find('.slide-pane').eq(0).outerWidth(true);

        // Determine visible panes
        for(var i = 1, l = slider.options.display; i < l; i++)
        {
            var pane = $(slider).find('.slide-pane').eq(i);

            TweenLite.set(pane[0], {x: offset+'px'});
            offset += pane.outerWidth(true);

            pane.addClass('active');
        }
    }

    function calculate_duration(slider, distance, duration)
    {
        return distance * duration / $(slider).width();
    }

    function animate(slide)
    {
        var slider = this;
        slider.animating = true;

        // Where are we now?
        var from = $(slider).find('.slide-pane.current');

        // Where are we moving to?
        var to = $(slider).find('.slide-pane').eq(slide.index);

        // Add a class on the slide we're moving to
        to.addClass('sliding-to');

        // Find the difference between the index of current pane and the index of where we're sliding to
        var difference;

        // If the index we're moving to is less than the current index and we're moving left
        if(to.index() < from.index() && slide.direction == 'left')
            difference = (to.index() + $(slider).find('.slide-pane').length) - from.index();

        // If the index we're moving to is greater than the current index and we're moving right
        else if(to.index() > from.index() && slide.direction == 'right')
            difference = (from.index() + $(slider).find('.slide-pane').length) - to.index();

        // Else...
        else
            difference = Math.abs(from.index() - to.index());

        var queue = {};
        var offset_to = (slide.direction == 'right') ? $(slider).width() : 0;

        if(slide.direction == 'right')
        {
            if(difference < slider.options.display)
            {
                for(var i = from.index() + slider.options.display, l = from.index(); i > l; i--)
                {
                    var index = i - 1;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                    offset_to += pane.outerWidth(true);
                }
            }
            else
            {
                // Start at current index
                for(var i = from.index(), l = from.index() + slider.options.display; i < l; i++)
                {
                    var index = i;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                    offset_to += pane.outerWidth(true);
                }
            }
        }
        else
        {
            if(difference < slider.options.display)
            {
                for(var i = from.index(), l = from.index() + slider.options.display; i < l; i++)
                {
                    var index = i;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    offset_to -= pane.outerWidth(true);
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                }
            }
            else
            {
                for(var i = from.index() + slider.options.display, l = from.index(); i > l; i--)
                {
                    var index = i - 1;

                    if(index >= $(slider).find('.slide-pane').length)
                        index -= $(slider).find('.slide-pane').length;

                    var pane = $(slider).find('.slide-pane').eq(index);

                    offset_to -= pane.outerWidth(true);
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'inactive'};
                }
            }
        }

        var offset_from = (slide.direction == 'right') ? 0 : $(slider).width();
        var offset_to = (slide.direction == 'right') ? $(slider).width() : 0;

        if(slide.direction == 'right')
        {
            for(var i = slide.index + slider.options.display, l = slide.index; i > l; i--)
            {
                var index = i - 1;

                if(index >= $(slider).find('.slide-pane').length)
                    index -= $(slider).find('.slide-pane').length;

                var pane = $(slider).find('.slide-pane').eq(index);

                if(!pane.hasClass('active'))
                {
                    pane.addClass('active');

                    offset_from -= pane.outerWidth(true);
                    offset_to -= pane.outerWidth(true);

                    queue[index] = {from: offset_from, to: offset_to, status: 'active'};
                }
                else
                {
                    offset_to -= pane.outerWidth(true);
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'active'};
                }
            }
        }
        else
        {
            // Start at slide.index, until index + slider.options.display
            for(var i = slide.index, l = slide.index + slider.options.display; i < l; i++)
            {
                var index = i;

                if(index >= $(slider).find('.slide-pane').length)
                    index -= $(slider).find('.slide-pane').length;

                var pane = $(slider).find('.slide-pane').eq(index);

                if(!pane.hasClass('active'))
                {
                    pane.addClass('active');
                    queue[index] = {from: offset_from, to: offset_to, status: 'active'};

                    offset_from += pane.outerWidth(true);
                    offset_to += pane.outerWidth(true);
                }
                else
                {
                    queue[index] = {from: pane.position().left, to: offset_to, status: 'active'};
                    offset_to += pane.outerWidth(true);
                }
            }
        }

        // Trigger resize if this is a dynamic height slider
        if(slider.options.dynamicHeight)
        {
            $(window).trigger('resize', {animation: true});
        }

        for(var i = 0, keys = Object.keys(queue), l = keys.length; i < l; ++i)
        {
            var index = keys[i];
            var data = queue[keys[i]];
            var pane = $(slider).find('.slide-pane').eq(index);
            var duration = calculate_duration(slider, Math.abs(data.from - data.to), slider.options.duration);

            pane.addClass('animating');
            TweenLite.fromTo(pane[0], duration, {x: data.from}, {x: data.to, onComplete: animated, onCompleteParams: [slider, slide, data.status]});
        }
    }

    function animated(slider, slide, status)
    {
        var pane = $(this.target);

        $(slider).find('.slide-pane.current').removeClass('current');
        $(slider).find('.slide-pane').eq(slide.index).addClass('current').removeClass('sliding-to');

        if(status == 'active')
            pane.addClass('active');
        else
            pane.removeClass('active');

        pane.removeClass('animating');

        if($(slider).find('.animating').length == 0)
        {
            slider.animating = false;
            if(typeof slider.options.slideEnd == "function") slider.options.slideEnd.call(slider);
        }
    }

    /*************************
     *
     *  Main slider code
     *
     ************************/

    var Slider = function(input)
    {
        var slider = this;

        // Define default slider.options
        slider.options = {display: 1, duration: 0.5, dynamicHeight: false};
        slider.options = $.extend(slider.options, input);

        init(slider);

        // When resize is triggered
        $(window).on('resize', function(event, params)
        {
            // Clear any styles if this slider has become disabled
            if($(slider).hasClass('disabled'))
            {
                $(slider).removeAttr('style');
            }

            // If the slider isn't disabled
            if(!$(slider).hasClass('disabled'))
            {
                // Animate slider to use the height of the slide we're sliding to
                if(slider.options.dynamicHeight)
                {
                    var pane = $(slider).find('.sliding-to');

                    // Only adjust height if we're actually sliding somewhere
                    if(pane.length)
                    {
                        var parent = $(slider);

                        pane.css('height', 'auto');
                        parent.height(pane.outerHeight(true));
                        pane.css('height', '100%');
                    }
                }
                // Else, if this is a static height slider
                else
                {
                    // Clear any styles on the slider
                    $(slider).removeAttr('style');

                    // Loop through all panes and set the container height to the maximum pane height
                    $(slider).find('.slide-pane').each(function()
                    {
                        $(this).css('height', 'auto');
                        var parent = $(slider);

                        if($(this).outerHeight(true) > parent.height())
                        {
                            parent.height($(this).outerHeight(true));
                        }

                        $(this).css('height', '100%');
                    });
                }

                // Only trigger slide resize if this event wasn't triggered by animation
                if(params === undefined || !params.animation)
                {
                    $(slider).trigger('slide-resize');
                }
            }
        });

        // Trigger resize now to try to position everything
        $(window).trigger('resize');

        // Trigger resize again once the window is fully loaded
        $(window).load(function()
        {
            $(window).trigger('resize');
        });

        // Convenience event for going to the next pane
        $(slider).on('slide-next', function()
        {
            var current = $(slider).find('.slide-pane.current');
            var index = current.index();

            var next = index + 1;

            if(next >= $(slider).find('.slide-pane').length)
                next = 0;

            $(slider).trigger('slide-to', next);
        });

        // Convenience event for going to the previous pane
        $(slider).on('slide-prev', function()
        {
            var current = $(slider).find('.slide-pane.current');
            var index = current.index();

            var prev = index - 1;

            if(prev < 0)
                prev = $(slider).find('.slide-pane').length - 1;

            $(slider).trigger('slide-to', prev);
        });

        $(slider).on('slide-resize', function()
        {
            // Find the current pane
            var current = $(slider).find('.slide-pane.current').index();

            // Trigger slide to current, fixing any potential difference in positioning
            $(slider).trigger('slide-to', current);
        });

        // Allows sliding to any pane based on its index
        $(slider).on('slide-to', function(event, input)
        {
            var slide = {index: 0, direction: 'left'};

            // If our request is an object
            if(typeof input == "object") $.extend(slide, input);
            // Else if the request is simply a number
            if(input == parseInt(input))   slide.index = input;

            var from = $(slider).find('.slide-pane.current');
            var to = $(slider).find('.slide-pane').eq(slide.index);
            var last = $(slider).find('.slide-pane').length - 1;

            // If the pane we're moving to comes before the current, move right
            if(from.index() > to.index())
                slide.direction = 'right';

            // If the pane we're moving to comes after the current, move left
            if(from.index() < to.index())
                slide.direction = 'left';

            // If we're moving to the last pane from the first
            if(from.index() == 0 && to.index() == last)
                slide.direction = 'right';

            // If we're moving to the first pane from the last
            if(from.index() == last && to.index() == 0)
                slide.direction = 'left';

            if(!slider.animating && !$(slider).hasClass('disabled'))
            {
                animate.call(slider, slide);
                if(typeof slider.options != "undefined" && typeof slider.options.slideStart == "function") slider.options.slideStart.call(slider);
            }
        });
    };

    /*************************
     *
     *  Bind to jQuery
     *
     ************************/

    $.fn.hbSlider = function(options)
    {
        for(var i = 0, l = this.length; i < l; i++)
        {
            Slider.call(this[i], options);
        }
    };
})(jQuery);<|endoftext|>


<commit_before>import Queries from './Queries'

class ReadQueries extends Queries {

    /**
     * Get one entity
     *
     * @param {Entity}   entity
     * @param {String}   viewType
     * @param {mixed}    identifierValue
     * @param {String}   identifierName
     * @param {String}   url
     *
     * @returns {promise} (list of fields (with their values if set) & the entity name, label & id-
     */
    getOne(entity, viewType, identifierValue, identifierName, url) {
        return this._restWrapper
            .getOne(entity.name(), this._application.getRouteFor(entity, url, viewType, identifierValue, identifierName));
    }

    /**
     * Return the list of all object of entityName type
     * Get all the object from the API
     *
     * @param {ListView} view                the view associated to the entity
     * @param {Number}   page                the page number
     * @param {Object}   filters             searchQuery to filter elements
     * @param {String}   sortField           the field to be sorted ex: entity.fieldName
     * @param {String}   sortDir             the direction of the sort
     *
     * @returns {promise} the entity config & the list of objects
     */
    getAll(view, page, filters, sortField, sortDir) {
        page = page || 1;
        let url = view.getUrl();

        sortField = sortField || view.getSortFieldName();
        sortDir = sortDir || view.sortDir();

        return this.getRawValues(view.entity, view.name(), view.type, page, view.perPage(), filters, view.filters(), sortField, sortDir, url)
            .then((values) => {
                return {
                    data: values.data,
                    totalItems: values.totalCount || values.headers('X-Total-Count') || values.data.length
                };
            });
    };

    /**
     * Return the list of all object of entityName type
     * Get all the object from the API
     *
     * @param {Entity}   entity
     * @param {String}   viewName
     * @param {String}   viewType
     * @param {Number}   page
     * @param {Number}   perPage
     * @param {Object}   filterValues
     * @param {Object}   filterFields
     * @param {String}   sortField
     * @param {String}   sortDir
     * @param {String}   url
     *
     * @returns {promise} the entity config & the list of objects
     */
    getRawValues(entity, viewName, viewType, page, perPage, filterValues, filterFields, sortField, sortDir, url) {
        let params = {};

        // Compute pagination
        if (page !== -1) {
            params._page = (typeof (page) === 'undefined') ? 1 : parseInt(page, 10);
            params._perPage = perPage;
        }

        // Compute sorting
        if (sortField && sortField.split('.')[0] === viewName) {
            params._sortField = sortField.split('.')[1];
            params._sortDir = sortDir;
        }

        // Compute filtering
        if (filterValues && Object.keys(filterValues).length !== 0) {
            params._filters = {};
            let filterName;

            for (filterName in filterValues) {
                if (filterFields.hasOwnProperty(filterName) && filterFields[filterName].hasMaps()) {
                    Object.assign(params._filters, filterFields[filterName].getMappedValue(filterValues[filterName]));

                    continue;
                }

                // It's weird to not map, but why not.
                params._filters[filterName] = filterValues[filterName];
            }
        }

        // Get grid data
        return this._restWrapper
            .getList(params, entity.name(), this._application.getRouteFor(entity, url, viewType));
    };

    /**
     * Returns all References for an entity with associated values [{targetEntity.identifier: targetLabel}, ...]
     * by calling the API for each entries
     *
     * @param {[ReferenceField]} references A hash of Reference and ReferenceMany objects
     * @param {Array} rawValues
     *
     * @returns {Promise}
     */
    getFilteredReferenceData(references, rawValues) {
        if (!references.length) {
            return this._promisesResolver.empty();
        }

        let getOne = this.getOne.bind(this),
            calls = [];

        for (let i in references) {
            let reference = references[i],
                targetEntity = reference.targetEntity(),
                identifiers = reference.getIdentifierValues(rawValues);

            for (let k in identifiers) {
                calls.push(getOne(targetEntity, 'listView', identifiers[k], reference.name()));
            }
        }

        return fillReferencedData(calls, references, rawValues);
    };

    /**
     * Returns all References for an entity with associated values [{targetEntity.identifier: targetLabel}, ...]
     * by calling the API once
     *
     * @param {[ReferenceField]} references A hash of Reference and ReferenceMany objects
     * @param {Array} rawValues
     *
     * @returns {Promise}
     */
    getOptimizedReferencedData(references, rawValues) {
        if (!references.length) {
            return this._promisesResolver.empty();
        }

        let getRawValues = this.getRawValues.bind(this),
            calls = [];

        for (let i in references) {
            let reference = references[i],
                targetEntity = reference.targetEntity(),
                identifiers = reference.getIdentifierValues(rawValues);

            // Check if we should retrieve values with 1 or multiple requests
            let singleCallFilters = reference.getSingleApiCall(identifiers);
            calls.push(getRawValues(targetEntity, targetEntity.name() + '_ListView', 'listView', 1, reference.perPage(), singleCallFilters, {}, reference.sortField(), reference.sortDir()));
        }

        return fillReferencedData(calls, references, rawValues);
    }

    /**
     * Returns all References for an entity with associated values [{targetEntity.identifier: targetLabel}, ...]
     * without filters on an entity
     *
     * @param {[ReferenceField]} references A hash of Reference and ReferenceMany objects
     *
     * @returns {Promise}
     */
    getAllReferencedData(references) {
        if (!references.length) {
            return this._promisesResolver.empty();
        }

        let calls = [];

        for (let i in references) {
            let reference = references[i],
                targetEntity = reference.targetEntity();

            calls.push(getRawValues(targetEntity, targetEntity.name() + '_ListView', 'listView', 1, reference.perPage(), reference.filters(), {}, reference.sortField(), reference.sortDir()));
        }

        return fillReferencedData(calls, references);
    }

    /**
     * Fill all reference entries to return [{targetEntity.identifier: targetLabel}, ...]
     *
     * @param {[Promise]} apiCalls
     * @param {[Reference]} references
     * @returns {Promise}
     */
    fillReferencedData(apiCalls, references, rawValues) {
        // @TODO : Make it general for getReferencedData, getChoicesData & getOptimizedReferencedData
        return this._promisesResolver.allEvenFailed(apiCalls)
            .then((responses) => {
                if (responses.length === 0) {
                    return {};
                }

                let referencedData = {},
                    response,
                    i = 0;

                for (let j in references) {
                    let reference = references[j],
                        singleCallFilters = reference.getSingleApiCall(identifiers);

                    // Retrieve entries depending on 1 or many request was done
                    if (singleCallFilters || !rawValues) {
                        response = responses[i++];
                        if (response.status == 'error') {
                            // the response failed
                            continue;
                        }

                        referencedData[reference.name()] = response.result.data;

                        continue;
                    }

                    let data = [],
                        identifiers = reference.getIdentifierValues(rawValues);

                    for (let k in identifiers) {
                        response = responses[i++];
                        if (response.status == 'error') {
                            // one of the responses failed
                            continue;
                        }
                        data.push(response.result);
                    }

                    if (!data.length) {
                        continue;
                    }

                    referencedData[reference.name()] = data;
                }

                return referencedData;
            });
    }

    /**
     * Returns all ReferencedList for an entity for associated values [{targetEntity.identifier: [targetFields, ...]}}
     *
     * @param {View}   referencedLists
     * @param {String} sortField
     * @param {String} sortDir
     * @param {*} entityId
     *
     * @returns {promise}
     */
    getReferencedListData(referencedLists, sortField, sortDir, entityId) {
        let getRawValues = this.getRawValues.bind(this),
            calls = [];

        for (let i in referencedLists) {
            let referencedList = referencedLists[i],
                targetEntity = referencedList.targetEntity(),
                viewName = targetEntity.name() + '_ListView',
                filter = {};

            filter[referencedList.targetReferenceField()] = entityId;
            calls.push(getRawValues(targetEntity, viewName, 'listView', 1, referencedList.perPage(), filter, {}, sortField || referencedList.getSortFieldName(), sortDir || referencedList.sortDir()));
        }

        return this._promisesResolver.allEvenFailed(calls)
            .then((responses) => {
                let j = 0,
                    entries = {};

                for (let i in referencedLists) {
                    let response = responses[j++];
                    if (response.status == 'error') {
                        // If a response fail, skip it
                        continue;
                    }

                    entries[i] = response.result.data;
                }

                return entries;
            });
    };
}

export default ReadQueries
<commit_msg>Call fillFilteredReferencedData & fillOptimizedReferencedData<commit_after>import Queries from './Queries'

class ReadQueries extends Queries {

    /**
     * Get one entity
     *
     * @param {Entity}   entity
     * @param {String}   viewType
     * @param {mixed}    identifierValue
     * @param {String}   identifierName
     * @param {String}   url
     *
     * @returns {promise} (list of fields (with their values if set) & the entity name, label & id-
     */
    getOne(entity, viewType, identifierValue, identifierName, url) {
        return this._restWrapper
            .getOne(entity.name(), this._application.getRouteFor(entity, url, viewType, identifierValue, identifierName));
    }

    /**
     * Return the list of all object of entityName type
     * Get all the object from the API
     *
     * @param {ListView} view                the view associated to the entity
     * @param {Number}   page                the page number
     * @param {Object}   filters             searchQuery to filter elements
     * @param {String}   sortField           the field to be sorted ex: entity.fieldName
     * @param {String}   sortDir             the direction of the sort
     *
     * @returns {promise} the entity config & the list of objects
     */
    getAll(view, page, filters, sortField, sortDir) {
        page = page || 1;
        let url = view.getUrl();

        sortField = sortField || view.getSortFieldName();
        sortDir = sortDir || view.sortDir();

        return this.getRawValues(view.entity, view.name(), view.type, page, view.perPage(), filters, view.filters(), sortField, sortDir, url)
            .then((values) => {
                return {
                    data: values.data,
                    totalItems: values.totalCount || values.headers('X-Total-Count') || values.data.length
                };
            });
    };

    /**
     * Return the list of all object of entityName type
     * Get all the object from the API
     *
     * @param {Entity}   entity
     * @param {String}   viewName
     * @param {String}   viewType
     * @param {Number}   page
     * @param {Number}   perPage
     * @param {Object}   filterValues
     * @param {Object}   filterFields
     * @param {String}   sortField
     * @param {String}   sortDir
     * @param {String}   url
     *
     * @returns {promise} the entity config & the list of objects
     */
    getRawValues(entity, viewName, viewType, page, perPage, filterValues, filterFields, sortField, sortDir, url) {
        let params = {};

        // Compute pagination
        if (page !== -1) {
            params._page = (typeof (page) === 'undefined') ? 1 : parseInt(page, 10);
            params._perPage = perPage;
        }

        // Compute sorting
        if (sortField && sortField.split('.')[0] === viewName) {
            params._sortField = sortField.split('.')[1];
            params._sortDir = sortDir;
        }

        // Compute filtering
        if (filterValues && Object.keys(filterValues).length !== 0) {
            params._filters = {};
            let filterName;

            for (filterName in filterValues) {
                if (filterFields.hasOwnProperty(filterName) && filterFields[filterName].hasMaps()) {
                    Object.assign(params._filters, filterFields[filterName].getMappedValue(filterValues[filterName]));

                    continue;
                }

                // It's weird to not map, but why not.
                params._filters[filterName] = filterValues[filterName];
            }
        }

        // Get grid data
        return this._restWrapper
            .getList(params, entity.name(), this._application.getRouteFor(entity, url, viewType));
    };

    /**
     * Returns all References for an entity with associated values [{targetEntity.identifier: targetLabel}, ...]
     * by calling the API for each entries
     *
     * @param {[ReferenceField]} references A hash of Reference and ReferenceMany objects
     * @param {Array} rawValues
     *
     * @returns {Promise}
     */
    getFilteredReferenceData(references, rawValues) {
        if (!references.length) {
            return this._promisesResolver.empty();
        }

        let getOne = this.getOne.bind(this),
            calls = [];

        for (let i in references) {
            let reference = references[i],
                targetEntity = reference.targetEntity(),
                identifiers = reference.getIdentifierValues(rawValues);

            for (let k in identifiers) {
                calls.push(getOne(targetEntity, 'listView', identifiers[k], reference.name()));
            }
        }

        return fillFilteredReferencedData(calls, references, rawValues);
    };

    /**
     * Returns all References for an entity with associated values [{targetEntity.identifier: targetLabel}, ...]
     * by calling the API once
     *
     * @param {[ReferenceField]} references A hash of Reference and ReferenceMany objects
     * @param {Array} rawValues
     *
     * @returns {Promise}
     */
    getOptimizedReferencedData(references, rawValues) {
        if (!references.length) {
            return this._promisesResolver.empty();
        }

        let getRawValues = this.getRawValues.bind(this),
            calls = [];

        for (let i in references) {
            let reference = references[i],
                targetEntity = reference.targetEntity(),
                identifiers = reference.getIdentifierValues(rawValues);

            // Check if we should retrieve values with 1 or multiple requests
            let singleCallFilters = reference.getSingleApiCall(identifiers);
            calls.push(getRawValues(targetEntity, targetEntity.name() + '_ListView', 'listView', 1, reference.perPage(), singleCallFilters, {}, reference.sortField(), reference.sortDir()));
        }

        return fillOptimizedReferencedData(calls, references);
    }

    /**
     * Returns all References for an entity with associated values [{targetEntity.identifier: targetLabel}, ...]
     * without filters on an entity
     *
     * @param {[ReferenceField]} references A hash of Reference and ReferenceMany objects
     *
     * @returns {Promise}
     */
    getAllReferencedData(references) {
        if (!references.length) {
            return this._promisesResolver.empty();
        }

        let calls = [];

        for (let i in references) {
            let reference = references[i],
                targetEntity = reference.targetEntity();

            calls.push(getRawValues(targetEntity, targetEntity.name() + '_ListView', 'listView', 1, reference.perPage(), reference.filters(), {}, reference.sortField(), reference.sortDir()));
        }

        return fillOptimizedReferencedData(calls, references);
    }

    /**
     * Fill all reference entries to return [{targetEntity.identifier: targetLabel}, ...]
     *
     * @param {[Promise]} apiCalls
     * @param {[Reference]} references
     * @returns {Promise}
     */
    fillOptimizedReferencedData(apiCalls, references) {
        return this._promisesResolver.allEvenFailed(apiCalls)
            .then((responses) => {
                if (responses.length === 0) {
                    return {};
                }

                let referencedData = {},
                    i = 0;

                for (let j in references) {
                    let reference = references[j],
                        response = responses[i++];

                    // Retrieve entries depending on 1 or many request was done
                    if (response.status == 'error') {
                        // the response failed
                        continue;
                    }

                    referencedData[reference.name()] = response.result.data;
                }

                return referencedData;
            });
    }

    /**
     * Fill all reference entries to return [{targetEntity.identifier: targetLabel}, ...]
     *
     * @param {[Promise]} apiCalls
     * @param {[Reference]} references
     * @param {[Object]} rawValues
     * @returns {Promise}
     */
    fillFilteredReferencedData(apiCalls, references, rawValues) {
        return this._promisesResolver.allEvenFailed(apiCalls)
            .then((responses) => {
                if (responses.length === 0) {
                    return {};
                }

                let referencedData = {},
                    response,
                    i = 0;

                for (let j in references) {
                    let data = [],
                        reference = references[j],
                        identifiers = reference.getIdentifierValues(rawValues);

                    for (let k in identifiers) {
                        response = responses[i++];
                        if (response.status == 'error') {
                            // one of the responses failed
                            continue;
                        }
                        data.push(response.result);
                    }

                    if (!data.length) {
                        continue;
                    }

                    referencedData[reference.name()] = data;
                }

                return referencedData;
            });
    }

    /**
     * Returns all ReferencedList for an entity for associated values [{targetEntity.identifier: [targetFields, ...]}}
     *
     * @param {View}   referencedLists
     * @param {String} sortField
     * @param {String} sortDir
     * @param {*} entityId
     *
     * @returns {promise}
     */
    getReferencedListData(referencedLists, sortField, sortDir, entityId) {
        let getRawValues = this.getRawValues.bind(this),
            calls = [];

        for (let i in referencedLists) {
            let referencedList = referencedLists[i],
                targetEntity = referencedList.targetEntity(),
                viewName = targetEntity.name() + '_ListView',
                filter = {};

            filter[referencedList.targetReferenceField()] = entityId;
            calls.push(getRawValues(targetEntity, viewName, 'listView', 1, referencedList.perPage(), filter, {}, sortField || referencedList.getSortFieldName(), sortDir || referencedList.sortDir()));
        }

        return this._promisesResolver.allEvenFailed(calls)
            .then((responses) => {
                let j = 0,
                    entries = {};

                for (let i in referencedLists) {
                    let response = responses[j++];
                    if (response.status == 'error') {
                        // If a response fail, skip it
                        continue;
                    }

                    entries[i] = response.result.data;
                }

                return entries;
            });
    };
}

export default ReadQueries
<|endoftext|>