public static Result parse(@NonNull String body, int mode) throws Exception {
        Result result = new Result();
        Document d;
        try{
           d = Jsoup.parse(body);
        }catch (Exception ignored){
            return result;
        }

        try {
            Element ptt = d.getElementsByClass("ptt").first();
            if (ptt == null) {
                Element searchNav = d.getElementsByClass("searchnav").first();
                result.pages = -1;
                result.nextPage = -1;

                assert searchNav != null;
                Element element = searchNav.getElementById("uFirst");
                if (element!=null){
                    result.firstHref = element.attr("href");
                }else {
                    result.firstHref = "";
                }
                element = searchNav.getElementById("uprev");
                if (element!=null){
                    result.prevHref = element.attr("href");
                }else {
                    result.prevHref = "";
                }
                element = searchNav.getElementById("unext");
                if (element!=null){
                    result.nextHref = element.attr("href");
                }else {
                    result.nextHref = "";
                }
                element = searchNav.getElementById("ulast");
                if (element!=null){
                    result.lastHref = element.attr("href");
                }else {
                    result.lastHref = "";
                }

                element = d.getElementsByClass("searchtext").first();

                if (element!=null){
                    String text = element.text();
                    Matcher matcher = PATTERN_RESULT_COUNT_PAGE.matcher(text);
                    if (matcher.find()){
                        String findString = matcher.group();
                        String[] resultArr = findString.split(" ");
                        if (resultArr.length>3){
                            switch (resultArr[1]){
                                case "thousands":
                                    result.resultCount = "1,000+";
                                    break;
                                case "about":
                                    result.resultCount = resultArr[2]+"+";
                                    break;
                                default:
                                    StringBuilder buffer = new StringBuilder();
                                    for (int i=1;i<resultArr.length-1;i++){
                                        buffer.append(resultArr[i]);
                                    }
                                    result.resultCount = buffer.toString();
                                    break;
                            }
                        }else if(resultArr.length == 3){
                            result.resultCount = resultArr[1];
                        }else{
                            result.resultCount = "";
                        }
                    }
                }else {
                    result.resultCount = "";
                }

            } else {
                Elements es = ptt.child(0).child(0).children();
                result.pages = Integer.parseInt(es.get(es.size() - 2).text().trim());
                Element e = es.get(es.size() - 1);
                if (e != null) {
                    e = e.children().first();
                    if (e != null) {
                        String href = e.attr("href");
                        Matcher matcher = PATTERN_NEXT_PAGE.matcher(href);
                        if (matcher.find()) {
                            result.nextPage = NumberUtils.parseIntSafely(matcher.group(1), 0);
                        }
                    }
                }
            }
        } catch (Throwable e) {
            ExceptionUtils.throwIfFatal(e);
            result.noWatchedTags = body.contains("<p>You do not have any watched tags");
            if (body.contains("No hits found</p>")) {
                result.pages = 0;
                //noinspection unchecked
                result.galleryInfoList = Collections.EMPTY_LIST;
                return result;
            } else if (d.getElementsByClass("ptt").isEmpty()) {
                result.pages = 1;
            } else {
                result.pages = Integer.MAX_VALUE;
            }
        }

        try {
            Element itg = d.getElementsByClass("itg").first();
            Elements es;
            assert itg != null;
            if ("table".equalsIgnoreCase(itg.tagName())) {
                es = itg.child(0).children();
            } else {
                es = itg.children();
            }
            List<GalleryInfo> list = new ArrayList<>(es.size());
            // First one is table header, skip it
            for (int i = 0; i < es.size(); i++) {
                GalleryInfo gi = parseGalleryInfo(es.get(i));
                if (null != gi) {
                    list.add(gi);
                }
            }
            if (list.isEmpty()) {
                try {
                    String pageMessage = d.getElementsByClass("itg gltc").get(0).child(0).child(1).child(0).text();
                    if (pageMessage.isEmpty()) {
                        throw new ParseException("No gallery", body);
                    }
                } catch (IndexOutOfBoundsException e) {
                    throw new ParseException("No gallery", body);
                }
//                throw new ParseException("No gallery", body);
            }
            result.galleryInfoList = list;
        } catch (Throwable e) {
            ExceptionUtils.throwIfFatal(e);
            e.printStackTrace();
            throw new ParseException("Can't parse gallery list", body);
        }

        new GalleryListTagsSyncTask(result.galleryInfoList).execute();

        return result;
    }
@Test
  public void testParse() throws Exception {
    InputStream resource = GalleryPageApiParserTest.class.getResourceAsStream(file);
    BufferedSource source = Okio.buffer(Okio.source(resource));
    String body = source.readUtf8();

    GalleryListParser.Result result = GalleryListParser.parse(body, MODE_NORMAL);

    assertEquals(25, result.galleryInfoList.size());

    result.galleryInfoList.forEach(gi -> {
//      assertNotEquals(0, gi.gid);
//      assertNotEquals(0, gi.token);
      assertNotNull(gi.title);

      //assertNotNull(gi.simpleTags);

//      assertNotEquals(0, gi.category);
//      assertNotEquals(EhUtils.UNKNOWN, gi.category);
//      assertNotEquals(0, gi.thumbWidth);
//      assertNotEquals(0, gi.thumbHeight);
      assertNotNull(gi.thumb);
      assertNotNull(gi.posted);
//      assertNotEquals(0.0, gi.rating);
      if (E_MINIMAL.equals(file) ||
          E_MINIMAL_PLUS.equals(file) ||
          E_COMPAT.equals(file) ||
          E_EXTENDED.equals(file) ||
          EX_MINIMAL.equals(file) ||
          EX_MINIMAL_PLUS.equals(file) ||
          EX_COMPAT.equals(file) ||
          EX_EXTENDED.equals(file)) {
        assertNotNull(gi.uploader);
      } else {
        assertNull(gi.uploader);
      }
//      assertNotEquals(0, gi.pages);
    });
  }