content: package im.actor.core.modules.conductor;
  
  import java.util.ArrayList;
  
  import im.actor.core.AutoJoinType;
  import im.actor.core.api.rpc.RequestNotifyAboutDeviceInfo;
  import im.actor.core.api.rpc.ResponseVoid;
  import im.actor.core.modules.ModuleActor;
  import im.actor.core.modules.ModuleContext;
  import im.actor.core.util.JavaUtil;
  import im.actor.core.viewmodel.AppStateVM;
  import im.actor.runtime.Log;
  
  /**
   * Launching App in stages
   * 1. Download existing Contacts and Dialogs
   * 2. Start Phone Book uploading
   * 3. When app is fully loaded (at least one contact or message in dialogs) then invoke
   * initialization actions such as joining channel
   */
  public class ConductorActor extends ModuleActor {
  
      public static final String TAG = "Conductor";
      private static final ResponseVoid DUMB = null;
      private static final Integer DUMB2 = null;
  
      private AppStateVM appStateVM;
      private boolean isStarted = false;
  
      public ConductorActor(ModuleContext context) {
          super(context);
      }
  
      @Override
      public void preStart() {
          super.preStart();
  
          updateDeviceInfoIfNeeded();
  
          appStateVM = context().getConductor().getAppStateVM();
      }
  
      public void onFinishLaunching() {
          if (isStarted) {
              return;
          }
          isStarted = true;
          unstashAll();
          
          if (appStateVM.isDialogsLoaded() && appStateVM.isContactsLoaded() && appStateVM.isSettingsLoaded()) {
              onInitialDataDownloaded();
          }
  
          if (appStateVM.getIsAppLoaded().get() || !appStateVM.getIsAppEmpty().get()) {
              onAppReady();
          }
      }
  
      //
      // Initial Loading
      //
  
      public void onDialogsLoaded() {
          Log.d(TAG, "Dialogs Loaded");
          if (!appStateVM.isDialogsLoaded()) {
              appStateVM.onDialogsLoaded();
              if (appStateVM.isContactsLoaded() && appStateVM.isSettingsLoaded()) {
                  onInitialDataDownloaded();
              }
          }
      }
  
      public void onContactsLoaded() {
          Log.d(TAG, "Contacts Loaded");
          if (!appStateVM.isContactsLoaded()) {
              appStateVM.onContactsLoaded();
              if (appStateVM.isDialogsLoaded() && appStateVM.isSettingsLoaded()) {
                  onInitialDataDownloaded();
              }
          }
      }
  
      public void onSettingsLoaded() {
          Log.d(TAG, "Settings Loaded");
          if (!appStateVM.isSettingsLoaded()) {
              appStateVM.onSettingsLoaded();
              if (appStateVM.isDialogsLoaded() && appStateVM.isContactsLoaded()) {
                  onInitialDataDownloaded();
              }
          }
      }
  
      /**
       * Called after dialogs, contacts and settings are downloaded from server
       */
      public void onInitialDataDownloaded() {
          Log.d(TAG, "Initial Data Loaded");
          context().getContactsModule().startImport();
          if (appStateVM.isBookImported()) {
              onAppLoaded();
          }
      }
  
      public void onBookImported() {
          Log.d(TAG, "Book Uploaded");
          if (!appStateVM.isBookImported()) {
              appStateVM.onPhoneImported();
              onAppLoaded();
          }
      }
  
      //
      // Data Sync
      //
  
      public void onDialogsChanged(boolean isEmpty) {
          boolean wasEmpty = appStateVM.getIsAppEmpty().get();
          appStateVM.onDialogsChanged(isEmpty);
          if (wasEmpty && !appStateVM.getIsAppEmpty().get()) {
              onAppReady();
          }
      }
  
      public void onContactsChanged(boolean isEmpty) {
          boolean wasEmpty = appStateVM.getIsAppEmpty().get();
          appStateVM.onContactsChanged(isEmpty);
          if (wasEmpty && !appStateVM.getIsAppEmpty().get()) {
              onAppReady();
          }
      }
  
      /**
       * Called after dialogs, contacts and settings are downloaded from server and
       * phone book is imported to server
       */
      public void onAppLoaded() {
          Log.d(TAG, "App Loaded");
  
          // Joining Groups
          if (config().getAutoJoinType() == AutoJoinType.IMMEDIATELY) {
              joinGroups();
          }
      }
  
      /**
       * Called after at least one message or contact is in user's phone book
       */
      public void onAppReady() {
          Log.d(TAG, "App Ready");
  
          // Joining Groups
          if (config().getAutoJoinType() == AutoJoinType.AFTER_INIT) {
              joinGroups();
          }
      }
  
      private void joinGroups() {
          for (String s : config().getAutoJoinGroups()) {
              if (!context().getSettingsModule().getBooleanValue("auto_join." + s, false)) {
                  context().getGroupsModule().joinGroupByToken(s).then(r -> {
                      context().getSettingsModule().setBooleanValue("auto_join." + s, true);
                  });
              }
          }
      }
  
      //
      // Tools
      //
  
      public void updateDeviceInfoIfNeeded() {
  
          //
          // Loading Information
          //
          ArrayList<String> langs = new ArrayList<>();
          for (String s : context().getConfiguration().getPreferredLanguages()) {
              langs.add(s);
          }
          final String timeZone = context().getConfiguration().getTimeZone();
  
          //
          // Checking if information changed
          //
          String expectedLangs = "";
          for (String s : langs) {
              if (!"".equals(expectedLangs)) {
                  expectedLangs += ",";
              }
              expectedLangs += s.toLowerCase();
          }
  
          if (expectedLangs.equals(preferences().getString("device_info_langs")) &&
                  JavaUtil.equalsE(timeZone, preferences().getString("device_info_timezone"))) {
              // Already sent
              return;
          }
  
          //
          // Performing Notification
          //
          final String finalExpectedLangs = expectedLangs;
          api(new RequestNotifyAboutDeviceInfo(langs, timeZone)).then(r -> {
              preferences().putString("device_info_langs", finalExpectedLangs);
              preferences().putString("device_info_timezone", timeZone);
          });
      }
  
  
      //
      // Messages
      //
  
      @Override
      public void onReceive(Object message) {
          if (message instanceof DialogsLoaded) {
              if (!isStarted) {
                  stash();
                  return;
              }
              onDialogsLoaded();
          } else if (message instanceof ContactsLoaded) {
              if (!isStarted) {
                  stash();
                  return;
              }
              onContactsLoaded();
          } else if (message instanceof SettingsLoaded) {
              if (!isStarted) {
                  stash();
                  return;
              }
              onSettingsLoaded();
          } else if (message instanceof BookImported) {
              if (!isStarted) {
                  stash();
                  return;
              }
              onBookImported();
          } else if (message instanceof ContactsChanged) {
              if (!isStarted) {
                  stash();
                  return;
              }
              onContactsChanged(((ContactsChanged) message).isEmpty());
          } else if (message instanceof DialogsChanged) {
              if (!isStarted) {
                  stash();
                  return;
              }
              onDialogsChanged(((DialogsChanged) message).isEmpty());
          } else if (message instanceof FinishLaunching) {
              onFinishLaunching();
          } else {
              super.onReceive(message);
          }
      }
  
      public static class DialogsLoaded {
  
      }
  
      public static class ContactsLoaded {
  
      }
  
      public static class BookImported {
  
      }
  
      public static class SettingsLoaded {
  
      }
  
      public static class ContactsChanged {
          private boolean isEmpty;
  
          public ContactsChanged(boolean isEmpty) {
              this.isEmpty = isEmpty;
          }
  
          public boolean isEmpty() {
              return isEmpty;
          }
      }
  
      public static class DialogsChanged {
          private boolean isEmpty;
  
          public DialogsChanged(boolean isEmpty) {
              this.isEmpty = isEmpty;
          }
  
          public boolean isEmpty() {
              return isEmpty;
          }
      }
  
      public static class FinishLaunching {
  
      }
  }
  