/**
   * Copy data from passed Bundle to current accumulated data. Does some careful processing of the
   * data.
   *
   * @param bookData Source
   */
  private void accumulateData(int searchId) {
    // See if we got data from this source
    if (!mSearchResults.containsKey(searchId)) return;
    Bundle bookData = mSearchResults.get(searchId);

    // See if we REALLY got data from this source
    if (bookData == null) return;

    for (String k : bookData.keySet()) {
      // If its not there, copy it.
      if (!mBookData.containsKey(k)
          || mBookData.getString(k) == null
          || mBookData.getString(k).trim().length() == 0)
        mBookData.putString(k, bookData.get(k).toString());
      else {
        // Copy, append or update data as appropriate.
        if (k.equals(CatalogueDBAdapter.KEY_AUTHOR_DETAILS)) {
          appendData(k, bookData, mBookData);
        } else if (k.equals(CatalogueDBAdapter.KEY_SERIES_DETAILS)) {
          appendData(k, bookData, mBookData);
        } else if (k.equals(CatalogueDBAdapter.KEY_DATE_PUBLISHED)) {
          // Grab a different date if we can parse it.
          Date newDate = Utils.parseDate(bookData.getString(k));
          if (newDate != null) {
            String curr = mBookData.getString(k);
            if (Utils.parseDate(curr) == null) {
              mBookData.putString(k, Utils.toSqlDateOnly(newDate));
            }
          }
        } else if (k.equals("__thumbnail")) {
          appendData(k, bookData, mBookData);
        }
      }
    }
  }
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
   try {
     super.onCreate(savedInstanceState);
     mDbHelper = new CatalogueDBAdapter(this);
     mDbHelper.open();
     setContentView(R.layout.administration_functions);
     Bundle extras = getIntent().getExtras();
     if (extras != null && extras.containsKey(DOAUTO)) {
       try {
         if (extras.getString(DOAUTO).equals("export")) {
           finish_after = true;
           mExportOnStartup = true;
         } else {
           throw new RuntimeException("Unsupported DOAUTO option");
         }
       } catch (NullPointerException e) {
         Logger.logError(e);
       }
     }
     setupAdmin();
     Utils.initBackground(R.drawable.bc_background_gradient_dim, this, false);
   } catch (Exception e) {
     Logger.logError(e);
   }
 }
  public static void searchGoogle(
      String mIsbn, String author, String title, Bundle bookData, boolean fetchThumbnail) {
    // replace spaces with %20
    author = author.replace(" ", "%20");
    title = title.replace(" ", "%20");

    String path = "http://books.google.com/books/feeds/volumes";
    if (mIsbn.equals("")) {
      path += "?q=" + "intitle:" + title + "+inauthor:" + author + "";
    } else {
      path += "?q=ISBN:" + mIsbn;
    }
    URL url;

    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser parser;
    SearchGoogleBooksHandler handler = new SearchGoogleBooksHandler();
    SearchGoogleBooksEntryHandler entryHandler =
        new SearchGoogleBooksEntryHandler(bookData, fetchThumbnail);

    try {
      url = new URL(path);
      parser = factory.newSAXParser();
      int count = 0;
      // We can't Toast anything from here; it no longer runs in UI thread. So let the caller deal
      // with any exceptions.
      parser.parse(Utils.getInputStream(url), handler);
      count = handler.getCount();
      if (count > 0) {
        String id = handler.getId();
        url = new URL(id);
        parser = factory.newSAXParser();
        parser.parse(Utils.getInputStream(url), entryHandler);
      }
      return;
    } catch (MalformedURLException e) {
      Logger.logError(e);
    } catch (ParserConfigurationException e) {
      Logger.logError(e);
    } catch (SAXException e) {
      Logger.logError(e);
    } catch (Exception e) {
      Logger.logError(e);
    }
    return;
  }
 /**
  * Handle task search results; start another task if necessary.
  *
  * @param t
  */
 private void handleSearchTaskFinished(SearchThread t) {
   SearchThread st = (SearchThread) t;
   mCancelledFlg = st.isCancelled();
   Bundle bookData = st.getBookData();
   mSearchResults.put(st.getSearchId(), bookData);
   if (mCancelledFlg) {
     mWaitingForIsbn = false;
   } else {
     if (mSearchingAsin) {
       // If we searched AMAZON for an Asin, then see what we found
       mSearchingAsin = false;
       // Clear the 'isbn'
       mIsbn = "";
       if (Utils.isNonBlankString(bookData, CatalogueDBAdapter.KEY_ISBN)) {
         // We got an ISBN, so pretend we were searching for an ISBN
         mWaitingForIsbn = true;
       } else {
         // See if we got author/title
         mAuthor = bookData.getString(CatalogueDBAdapter.KEY_AUTHOR_NAME);
         mTitle = bookData.getString(CatalogueDBAdapter.KEY_TITLE);
         if (mAuthor != null && !mAuthor.equals("") && mTitle != null && !mTitle.equals("")) {
           // We got them, so pretend we are searching by author/title now, and waiting for an
           // ASIN...
           mWaitingForIsbn = true;
         }
       }
     }
     if (mWaitingForIsbn) {
       if (Utils.isNonBlankString(bookData, CatalogueDBAdapter.KEY_ISBN)) {
         mWaitingForIsbn = false;
         // Start the other two...even if they have run before
         mIsbn = bookData.getString(CatalogueDBAdapter.KEY_ISBN);
         startSearches(mSearchFlags);
       } else {
         // Start next one that has not run.
         startNext();
       }
     }
   }
 }
  /** Combine all the data and create a book or display an error. */
  private void sendResults() {
    // This list will be the actual order of the result we apply, based on the
    // actual results and the default order.
    ArrayList<Integer> results = new ArrayList<Integer>();

    if (mHasIsbn) {
      // If ISBN was passed, ignore entries with the wrong ISBN, and put entries with no ISBN at the
      // end
      ArrayList<Integer> uncertain = new ArrayList<Integer>();
      for (int i : mDefaultReliabilityOrder) {
        if (mSearchResults.containsKey(i)) {
          Bundle bookData = mSearchResults.get(i);
          if (bookData.containsKey(CatalogueDBAdapter.KEY_ISBN)) {
            String isbn = bookData.getString(CatalogueDBAdapter.KEY_ISBN);
            if (IsbnUtils.matches(mIsbn, isbn)) {
              results.add(i);
            }
          } else {
            uncertain.add(i);
          }
        }
      }
      for (Integer i : uncertain) {
        results.add(i);
      }
      // Add the passed ISBN first; avoid overwriting
      mBookData.putString(CatalogueDBAdapter.KEY_ISBN, mIsbn);
    } else {
      // If ISBN was not passed, then just used the default order
      for (int i : mDefaultReliabilityOrder) results.add(i);
    }

    // Merge the data we have. We do this in a fixed order rather than as the threads finish.
    for (int i : results) accumulateData(i);

    // If there are thumbnails present, pick the biggest, delete others and rename.
    Utils.cleanupThumbnails(mBookData);

    // Try to use/construct authors
    String authors = null;
    try {
      authors = mBookData.getString(CatalogueDBAdapter.KEY_AUTHOR_DETAILS);
    } catch (Exception e) {
    }

    if (authors == null || authors.equals("")) {
      authors = mAuthor;
    }

    if (authors != null && !authors.equals("")) {
      // Decode the collected author names and convert to an ArrayList
      ArrayList<Author> aa = Utils.getAuthorUtils().decodeList(authors, '|', false);
      mBookData.putSerializable(CatalogueDBAdapter.KEY_AUTHOR_ARRAY, aa);
    }

    // Try to use/construct title
    String title = null;
    try {
      title = mBookData.getString(CatalogueDBAdapter.KEY_TITLE);
    } catch (Exception e) {
    }

    if (title == null || title.equals("")) title = mTitle;

    if (title != null && !title.equals("")) {
      mBookData.putString(CatalogueDBAdapter.KEY_TITLE, title);
    }

    // Try to use/construct isbn
    String isbn = null;
    try {
      isbn = mBookData.getString(CatalogueDBAdapter.KEY_ISBN);
    } catch (Exception e) {
    }

    if (isbn == null || isbn.equals("")) isbn = mIsbn;

    if (isbn != null && !isbn.equals("")) {
      mBookData.putString(CatalogueDBAdapter.KEY_ISBN, isbn);
    }

    // Try to use/construct series
    String series = null;
    try {
      series = mBookData.getString(CatalogueDBAdapter.KEY_SERIES_DETAILS);
    } catch (Exception e) {
    }

    if (series != null && !series.equals("")) {
      // Decode the collected series names and convert to an ArrayList
      try {
        ArrayList<Series> sa = Utils.getSeriesUtils().decodeList(series, '|', false);
        mBookData.putSerializable(CatalogueDBAdapter.KEY_SERIES_ARRAY, sa);
      } catch (Exception e) {
        Logger.logError(e);
      }
    } else {
      // add series to stop crashing
      mBookData.putSerializable(CatalogueDBAdapter.KEY_SERIES_ARRAY, new ArrayList<Series>());
    }

    //
    // TODO: this needs to be locale-specific. Currently we probably get good-enough data without
    // forcing a cleanup.
    //
    // Removed 20-Jan-2016 PJW; see Issue 717.
    //
    // Cleanup other fields
    // Utils.doProperCase(mBookData, CatalogueDBAdapter.KEY_TITLE);
    // Utils.doProperCase(mBookData, CatalogueDBAdapter.KEY_PUBLISHER);
    // Utils.doProperCase(mBookData, CatalogueDBAdapter.KEY_DATE_PUBLISHED);
    // Utils.doProperCase(mBookData, CatalogueDBAdapter.KEY_SERIES_NAME);

    // If book is not found or missing required data, warn the user
    if (authors == null || authors.length() == 0 || title == null || title.length() == 0) {
      mTaskManager.doToast(BookCatalogueApp.getResourceString(R.string.book_not_found));
    }
    // Pass the data back
    sendSearchFinished();
  }
 /** Fix background */
 @Override
 public void onResume() {
   super.onResume();
   Utils.initBackground(R.drawable.bc_background_gradient_dim, this, false);
   if (mExportOnStartup) exportData();
 }