content: package im.actor.sdk.controllers.conversation.messages;
  
  import android.content.Context;
  import android.view.ViewGroup;
  
  import java.util.HashMap;
  
  import im.actor.core.entity.Message;
  import im.actor.core.entity.Peer;
  import im.actor.core.entity.content.AbsContent;
  import im.actor.core.viewmodel.ConversationVM;
  import im.actor.runtime.generic.mvvm.BindedDisplayList;
  import im.actor.runtime.mvvm.Value;
  import im.actor.runtime.mvvm.ValueChangedListener;
  import im.actor.sdk.ActorSDK;
  import im.actor.runtime.android.view.BindedListAdapter;
  import im.actor.sdk.controllers.conversation.messages.content.AudioHolder;
  import im.actor.sdk.controllers.conversation.messages.content.ContactHolder;
  import im.actor.sdk.controllers.conversation.messages.content.DocHolder;
  import im.actor.sdk.controllers.conversation.messages.content.LocationHolder;
  import im.actor.sdk.controllers.conversation.messages.content.AbsMessageViewHolder;
  import im.actor.sdk.controllers.conversation.messages.content.PhotoHolder;
  import im.actor.sdk.controllers.conversation.messages.content.preprocessor.PreprocessedList;
  import im.actor.sdk.controllers.conversation.messages.content.ServiceHolder;
  import im.actor.sdk.controllers.conversation.messages.content.StickerHolder;
  import im.actor.sdk.controllers.conversation.messages.content.TextHolder;
  import im.actor.sdk.controllers.ActorBinder;
  
  import static im.actor.sdk.util.ActorSDKMessenger.messenger;
  
  public class MessagesAdapter extends BindedListAdapter<Message, AbsMessageViewHolder> {
  
      private MessagesFragment messagesFragment;
      private ActorBinder BINDER = new ActorBinder();
  
      private Context context;
      private long firstUnread = -DefaultLayouter.SERVICE_HOLDER;
      private long readDate;
      private long receiveDate;
      private Peer peer;
      private ViewHolderMatcher matcher;
  
      private HashMap<Long, Message> selected = new HashMap<>();
  
  
  
      public MessagesAdapter(final BindedDisplayList<Message> displayList,
                             MessagesFragment messagesFragment, Context context) {
          super(displayList);
  
          matcher = new ViewHolderMatcher();
  
          matcher.add(new DefaultLayouter(DefaultLayouter.TEXT_HOLDER, TextHolder::new));
          matcher.add(new DefaultLayouter(DefaultLayouter.SERVICE_HOLDER, ServiceHolder::new));
          matcher.add(new DefaultLayouter(DefaultLayouter.PHOTO_HOLDER, PhotoHolder::new));
          matcher.add(new DefaultLayouter(DefaultLayouter.VOICE_HOLDER, AudioHolder::new));
          matcher.add(new DefaultLayouter(DefaultLayouter.DOCUMENT_HOLDER, DocHolder::new));
          matcher.add(new DefaultLayouter(DefaultLayouter.CONTACT_HOLDER, ContactHolder::new));
          matcher.add(new DefaultLayouter(DefaultLayouter.LOCATION_HOLDER, LocationHolder::new));
          matcher.add(new DefaultLayouter(DefaultLayouter.STICKER_HOLDER, StickerHolder::new));
  
          ActorSDK.sharedActor().getDelegate().configureChatViewHolders(matcher.getLayouters());
  
  
          this.messagesFragment = messagesFragment;
          this.context = context;
          ConversationVM conversationVM = messenger().getConversationVM(messagesFragment.getPeer());
  
          peer = messagesFragment.getPeer();
  
          readDate = conversationVM.getReadDate().get();
          receiveDate = conversationVM.getReceiveDate().get();
  
          BINDER.bind(conversationVM.getReadDate(), new ValueChangedListener<Long>() {
              @Override
              public void onChanged(Long val, Value<Long> valueModel) {
                  if (val != readDate) {
                      for (int i = 0; i < displayList.getSize(); i++) {
                          long date = displayList.getItem(i).getSortDate();
                          if (date > readDate && date <= val) {
                              notifyItemChanged(i);
                          }
                          if (date <= readDate) {
                              break;
                          }
                      }
                      readDate = val;
                  }
              }
          });
          BINDER.bind(conversationVM.getReceiveDate(), new ValueChangedListener<Long>() {
              @Override
              public void onChanged(Long val, Value<Long> valueModel) {
                  if (val != receiveDate) {
                      for (int i = 0; i < displayList.getSize(); i++) {
                          long date = displayList.getItem(i).getSortDate();
                          if (date > receiveDate && date <= val) {
                              notifyItemChanged(i);
                          }
                          if (date <= receiveDate) {
                              break;
                          }
                      }
                      receiveDate = val;
                  }
              }
          });
      }
  
      public Message[] getSelected() {
          return selected.values().toArray(new Message[selected.size()]);
      }
  
      public boolean isSelected(Message msg) {
          return selected.containsKey(msg.getRid());
      }
  
      public void setSelected(Message msg, boolean isSelected) {
          if (isSelected) {
              selected.put(msg.getRid(), msg);
          } else {
              selected.remove(msg.getRid());
          }
          notifyDataSetChanged();
      }
  
      public int getSelectedCount() {
          return selected.size();
      }
  
      public void clearSelection() {
          selected.clear();
          notifyDataSetChanged();
      }
  
      public MessagesFragment getMessagesFragment() {
          return messagesFragment;
      }
  
      public long getFirstUnread() {
          return firstUnread;
      }
  
      public long getReadDate() {
          return readDate;
      }
  
      public long getReceiveDate() {
          return receiveDate;
      }
  
      public void setFirstUnread(long firstUnread) {
          this.firstUnread = firstUnread;
      }
  
      @Override
      public int getItemViewType(int position) {
          AbsContent content = getItem(position).getContent();
          return matcher.getMatchId(content);
  
      }
  
  
      @Override
      public AbsMessageViewHolder onCreateViewHolder(final ViewGroup viewGroup, int viewType) {
          return matcher.onCreateViewHolder(viewType, this, viewGroup, peer);
      }
  
      @Override
      public void onBindViewHolder(AbsMessageViewHolder dialogHolder, int index, Message item) {
          Message prev = null;
          Message next = null;
          if (index > 1) {
              next = getItem(index - 1);
          }
          if (index < getItemCount() - 1) {
              prev = getItem(index + 1);
          }
          PreprocessedList list = ((PreprocessedList) getPreprocessedList());
          dialogHolder.bindData(item, prev, next, readDate, receiveDate, list.getPreprocessedData()[index]);
      }
  
      @Override
      public void onViewRecycled(AbsMessageViewHolder holder) {
          holder.unbind();
      }
  
      public ActorBinder getBinder() {
          return BINDER;
      }
  
  }