text: /* (c) 2018 CYVA. For details refer to LICENSE */
  /*
   * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
   *
   * The MIT License
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   * THE SOFTWARE.
   */
  #include <graphene/chain/account_object.hpp>
  #include <graphene/chain/asset_object.hpp>
  #include <graphene/chain/database.hpp>
  #include <graphene/chain/hardfork.hpp>
  #include <fc/uint128.hpp>
  
  namespace graphene { namespace chain {
  
  share_type cut_fee(share_type a, uint16_t p)
  {
     if( a == 0 || p == 0 )
        return 0;
     if( p == GRAPHENE_100_PERCENT )
        return a;
  
     fc::uint128 r(a.value);
     r *= p;
     r /= GRAPHENE_100_PERCENT;
     return r.to_uint64();
  }
  
  void account_balance_object::adjust_balance(const asset& delta)
  {
     assert(delta.asset_id == asset_type);
     balance += delta.amount;
  }
  
  set<account_id_type> account_member_index::get_account_members(const account_object& a)const
  {
     set<account_id_type> result;
     for( auto auth : a.owner.account_auths )
        result.insert(auth.first);
     return result;
  }
  set<public_key_type> account_member_index::get_key_members(const account_object& a)const
  {
     set<public_key_type> result;
     for( auto auth : a.owner.key_auths )
        result.insert(auth.first);
     return result;
  }
  
  void account_member_index::object_inserted(const object& obj)
  {
      assert( dynamic_cast<const account_object*>(&obj) ); // for debug only
      const account_object& a = static_cast<const account_object&>(obj);
  
      auto account_members = get_account_members(a);
      for( auto item : account_members )
         account_to_account_memberships[item].insert(obj.id);
  
      auto key_members = get_key_members(a);
      for( auto item : key_members )
         account_to_key_memberships[item].insert(obj.id);
  }
  
  void account_member_index::object_removed(const object& obj)
  {
      assert( dynamic_cast<const account_object*>(&obj) ); // for debug only
      const account_object& a = static_cast<const account_object&>(obj);
  
      auto key_members = get_key_members(a);
      for( auto item : key_members )
         account_to_key_memberships[item].erase( obj.id );
  
      auto account_members = get_account_members(a);
      for( auto item : account_members )
         account_to_account_memberships[item].erase( obj.id );
  }
  
  void account_member_index::about_to_modify(const object& before)
  {
     before_key_members.clear();
     before_account_members.clear();
     assert( dynamic_cast<const account_object*>(&before) ); // for debug only
     const account_object& a = static_cast<const account_object&>(before);
     before_key_members     = get_key_members(a);
     before_account_members = get_account_members(a);
  }
  
  void account_member_index::object_modified(const object& after)
  {
      assert( dynamic_cast<const account_object*>(&after) ); // for debug only
      const account_object& a = static_cast<const account_object&>(after);
  
      {
         set<account_id_type> after_account_members = get_account_members(a);
         vector<account_id_type> removed; removed.reserve(before_account_members.size());
         std::set_difference(before_account_members.begin(), before_account_members.end(),
                             after_account_members.begin(), after_account_members.end(),
                             std::inserter(removed, removed.end()));
  
         for( auto itr = removed.begin(); itr != removed.end(); ++itr )
            account_to_account_memberships[*itr].erase(after.id);
  
         vector<object_id_type> added; added.reserve(after_account_members.size());
         std::set_difference(after_account_members.begin(), after_account_members.end(),
                             before_account_members.begin(), before_account_members.end(),
                             std::inserter(added, added.end()));
  
         for( auto itr = added.begin(); itr != added.end(); ++itr )
            account_to_account_memberships[*itr].insert(after.id);
      }
  
  
      {
         set<public_key_type> after_key_members = get_key_members(a);
  
         vector<public_key_type> removed; removed.reserve(before_key_members.size());
         std::set_difference(before_key_members.begin(), before_key_members.end(),
                             after_key_members.begin(), after_key_members.end(),
                             std::inserter(removed, removed.end()));
  
         for( auto itr = removed.begin(); itr != removed.end(); ++itr )
            account_to_key_memberships[*itr].erase(after.id);
  
         vector<public_key_type> added; added.reserve(after_key_members.size());
         std::set_difference(after_key_members.begin(), after_key_members.end(),
                             before_key_members.begin(), before_key_members.end(),
                             std::inserter(added, added.end()));
  
         for( auto itr = added.begin(); itr != added.end(); ++itr )
            account_to_key_memberships[*itr].insert(after.id);
      }
  }
  
  
  } } // graphene::chain
  