content: /*
   * Copyright (C) 2015 Actor LLC. <https://actor.im>
   */
  
  package im.actor.core.js;
  
  import com.google.gwt.core.client.JavaScriptObject;
  import com.google.gwt.core.client.JsArray;
  import com.google.gwt.user.client.Event;
  
  import im.actor.core.Configuration;
  import im.actor.core.Messenger;
  import im.actor.core.api.rpc.ResponseLoadArchived;
  import im.actor.core.entity.Avatar;
  import im.actor.core.entity.Contact;
  import im.actor.core.entity.Dialog;
  import im.actor.core.entity.FileReference;
  import im.actor.core.entity.Message;
  import im.actor.core.entity.Peer;
  import im.actor.core.entity.PeerType;
  import im.actor.core.entity.SearchEntity;
  import im.actor.core.entity.content.FastThumb;
  import im.actor.core.js.entity.JsBlockedUser;
  import im.actor.core.js.entity.JsCall;
  import im.actor.core.js.entity.JsCounter;
  import im.actor.core.js.entity.JsDialogGroup;
  import im.actor.core.js.entity.JsEventBusCallback;
  import im.actor.core.js.entity.JsOnlineGroup;
  import im.actor.core.js.entity.JsOnlineUser;
  import im.actor.core.js.entity.JsSearchEntity;
  import im.actor.core.js.entity.JsSticker;
  import im.actor.core.js.modules.JsFilesModule;
  import im.actor.core.js.modules.JsBindingModule;
  import im.actor.core.js.modules.JsBindedValue;
  import im.actor.core.js.entity.JsContact;
  import im.actor.core.js.entity.JsDialog;
  import im.actor.core.js.entity.JsGroup;
  import im.actor.core.js.entity.JsMessage;
  import im.actor.core.js.entity.JsPeer;
  import im.actor.core.js.entity.JsPeerInfo;
  import im.actor.core.js.entity.JsTyping;
  import im.actor.core.js.entity.JsUser;
  import im.actor.core.js.entity.Placeholders;
  import im.actor.core.js.images.JsImageResize;
  import im.actor.core.js.images.JsResizeListener;
  import im.actor.core.js.modules.JsIdleModule;
  import im.actor.core.js.providers.electron.JsElectronApp;
  import im.actor.core.js.providers.electron.JsElectronListener;
  import im.actor.core.js.providers.notification.JsChromePush;
  import im.actor.core.js.providers.notification.JsSafariPush;
  import im.actor.core.js.providers.notification.PushSubscribeResult;
  import im.actor.core.network.RpcCallback;
  import im.actor.core.viewmodel.ConversationVM;
  import im.actor.core.viewmodel.GroupVM;
  import im.actor.core.viewmodel.UserVM;
  import im.actor.runtime.Log;
  import im.actor.runtime.Runtime;
  import im.actor.runtime.Storage;
  import im.actor.runtime.crypto.Base64Utils;
  import im.actor.runtime.js.JsFileSystemProvider;
  import im.actor.runtime.js.fs.JsBlob;
  import im.actor.runtime.js.fs.JsFile;
  import im.actor.runtime.js.mvvm.JsDisplayList;
  import im.actor.runtime.mvvm.Value;
  import im.actor.runtime.mvvm.ValueChangedListener;
  import im.actor.runtime.threading.ThreadDispatcher;
  
  public class JsMessenger extends Messenger {
  
      private static final String TAG = "JsMessenger";
      private static JsMessenger instance = null;
  
      public static JsMessenger getInstance() {
          return instance;
      }
  
      private JsIdleModule jsIdleModule;
      private JsBindingModule jsBindingModule;
      private JsFilesModule filesModule;
      private JsFileSystemProvider fileSystemProvider;
      private boolean isElectron;
  
      public JsMessenger(Configuration configuration) {
          super(configuration);
          fileSystemProvider = (JsFileSystemProvider) Storage.getFileSystemRuntime();
          filesModule = new JsFilesModule(modules);
          jsBindingModule = new JsBindingModule(this, filesModule, modules);
          isElectron = JsElectronApp.isElectron();
  
          ThreadDispatcher.pushDispatcher(Runtime::postToMainThread);
  
          jsIdleModule = new JsIdleModule(this, modules);
  
          if (isElectron()) {
              Log.d(TAG, "Init Electron IPC");
              JsElectronApp.subscribe("window", new JsElectronListener() {
                  @Override
                  public void onEvent(String content) {
                      Log.d(TAG, "On Window " + content);
                      if ("focus".equals(content)) {
                          jsIdleModule.onVisible();
                      } else if ("blur".equals(content)) {
                          jsIdleModule.onHidden();
                      }
                  }
              });
          }
  
          if (isElectron) {
              getGlobalState().getGlobalTempCounter().subscribe(new ValueChangedListener<Integer>() {
                  @Override
                  public void onChanged(Integer val, Value<Integer> valueModel) {
                      if (val == null || val == 0) {
                          JsElectronApp.hideNewMessages();
                      } else {
                          JsElectronApp.updateBadge(val);
                      }
                  }
              });
          }
  
          JsMessenger.instance = this;
      }
  
      public JsIdleModule getJsIdleModule() {
          return jsIdleModule;
      }
  
      public boolean isElectron() {
          return isElectron;
      }
  
      public void sendPhoto(final Peer peer, final String fileName, final JsBlob blob) {
          Log.d(TAG, "Resizing photo");
          JsImageResize.resize(blob, new JsResizeListener() {
              @Override
              public void onResized(String thumb, int thumbW, int thumbH, int fullW, int fullH) {
  
                  Log.d(TAG, "Photo resized");
  
                  int index = thumb.indexOf("base64,");
                  if (index < 0) {
                      Log.d(TAG, "Unable to find base64");
                      return;
                  }
                  String rawData = thumb.substring(index + "base64,".length());
  
                  byte[] thumbData = Base64Utils.fromBase64(rawData);
  
                  String descriptor = fileSystemProvider.registerUploadFile(blob);
                  sendPhoto(peer, fileName, fullW, fullH,
                          new FastThumb(thumbW, thumbH, thumbData),
                          descriptor);
              }
          });
      }
  
      public void sendPhoto(final Peer peer, final JsFile file) {
          sendPhoto(peer, file.getName(), file);
      }
  
      public void sendAnimation(final Peer peer, final JsFile file) {
          Log.d(TAG, "Resizing animation");
          JsImageResize.resize(file, new JsResizeListener() {
              @Override
              public void onResized(String thumb, int thumbW, int thumbH, int fullW, int fullH) {
  
                  Log.d(TAG, "Animation resized");
  
                  int index = thumb.indexOf("base64,");
                  if (index < 0) {
                      Log.d(TAG, "Unable to find base64");
                      return;
                  }
                  String rawData = thumb.substring(index + "base64,".length());
  
                  byte[] thumbData = Base64Utils.fromBase64(rawData);
  
                  String descriptor = fileSystemProvider.registerUploadFile(file);
                  sendAnimation(peer, file.getName(), fullW, fullH,
                          new FastThumb(thumbW, thumbH, thumbData),
                          descriptor);
              }
          });
      }
  
      public void sendClipboardPhoto(final Peer peer, final JsBlob file) {
          sendPhoto(peer, "clipboard.jpg", file);
      }
  
      public void loadMoreDialogs() {
          modules.getMessagesModule().loadMoreDialogs();
      }
  
      public void loadArchivedDialogs(boolean init, RpcCallback<ResponseLoadArchived> callback) {
          modules.getMessagesModule().loadMoreArchivedDialogs(init, callback);
      }
  
      public void loadMoreHistory(Peer peer) {
          modules.getMessagesModule().loadMoreHistory(peer);
      }
  
      public JsBindedValue<JsUser> getJsUser(int uid) {
          return jsBindingModule.getUser(uid);
      }
  
      public JsBindedValue<JsOnlineUser> getJsUserOnline(int gid) {
          return jsBindingModule.getUserOnline(gid);
      }
  
      public JsBindedValue<JsBlockedUser> getJsUserBlocked(int uid) {
          return jsBindingModule.getUserBlocked(uid);
      }
  
      public JsBindedValue<JsGroup> getJsGroup(int gid) {
          return jsBindingModule.getGroup(gid);
      }
  
      public JsBindedValue<JsOnlineGroup> getJsGroupOnline(int gid) {
          return jsBindingModule.getGroupOnline(gid);
      }
  
      public JsBindedValue<JsCall> getJsCall(String id) {
          return jsBindingModule.getCall(id);
      }
  
      public JsBindedValue<JsTyping> getTyping(Peer peer) {
          return jsBindingModule.getTyping(peer);
      }
  
      public JsBindedValue<String> getOnlineStatus() {
          return jsBindingModule.getOnlineStatus();
      }
  
      public JsBindedValue<JsCounter> getGlobalCounter() {
          return jsBindingModule.getGlobalCounter();
      }
  
      public JsBindedValue<JsCounter> getTempGlobalCounter() {
          return jsBindingModule.getTempGlobalCounter();
      }
  
      public JsPeerInfo buildPeerInfo(Peer peer) {
          if (peer.getPeerType() == PeerType.PRIVATE) {
              UserVM userVM = getUsers().get(peer.getPeerId());
              return JsPeerInfo.create(
                      JsPeer.create(peer),
                      userVM.getName().get(),
                      userVM.getNick().get(),
                      getSmallAvatarUrl(userVM.getAvatar().get()),
                      Placeholders.getPlaceholder(peer.getPeerId()),
                      userVM.getIsVerified().get());
          } else if (peer.getPeerType() == PeerType.GROUP) {
              GroupVM groupVM = getGroups().get(peer.getPeerId());
              return JsPeerInfo.create(
                      JsPeer.create(peer),
                      groupVM.getName().get(),
                      null,
                      getSmallAvatarUrl(groupVM.getAvatar().get()),
                      Placeholders.getPlaceholder(peer.getPeerId()),
                      false);
          } else {
              throw new RuntimeException();
          }
      }
  
      public JsDisplayList<JsDialog, Dialog> getSharedDialogList() {
          return jsBindingModule.getSharedDialogList();
      }
  
  
      public JsDisplayList<JsContact, Contact> getSharedContactList() {
          return jsBindingModule.getSharedContactList();
      }
  
      public JsDisplayList<JsSearchEntity, SearchEntity> getSharedSearchList() {
          return jsBindingModule.getSharedSearchList();
      }
  
      public JsDisplayList<JsMessage, Message> getSharedChatList(Peer peer) {
          return jsBindingModule.getSharedMessageList(peer);
      }
  
      public JsBindedValue<JsArray<JsDialogGroup>> getDialogsGroupedList() {
          return jsBindingModule.getDialogsGroupedList();
      }
  
      public JsBindedValue<JsArray<JsSticker>> getStickers() {
          return jsBindingModule.getStickers();
      }
  
      public void broadcastEvent(String tag, JavaScriptObject obj) {
          jsBindingModule.broadcastEvent(tag, obj);
      }
  
      public void subscribeEventBus(JsEventBusCallback callback) {
          jsBindingModule.subscribeEventBus(callback);
      }
  
      public void unsubscribeEventBus(JsEventBusCallback callback) {
          jsBindingModule.unsubscribeEventBus(callback);
      }
  
      private String getSmallAvatarUrl(Avatar avatar) {
          if (avatar != null && avatar.getSmallImage() != null) {
              return getFileUrl(avatar.getSmallImage().getFileReference());
          }
          return null;
      }
  
      public String getFileUrl(FileReference fileReference) {
          return filesModule.getFileUrl(fileReference.getFileId(), fileReference.getAccessHash());
      }
  }