void EbookController::CloseCurrentDocument()
{
    ctrls->page->SetPage(NULL);
    StopFormattingThread();
    DeletePageShown();
    DeletePages(&pagesFromBeginning);
    DeletePages(&pagesFromPage);
    doc.Delete();
    formattingTemp.reparseIdx = 0; // mark as being laid out from the beginning
    pageSize = SizeI(0, 0);
}
void EbookController::TriggerBookFormatting()
{
    Size s = ctrls->page->GetDrawableSize();
    SizeI size(s.Width, s.Height);
    if (size.IsEmpty()) {
        // we haven't been sized yet
        return;
    }
    CrashIf(size.dx < 100 || size.dy < 40);
    if (!doc.IsEbook())
        return;

    if (pageSize == size) {
        //lf("EbookController::TriggerBookFormatting() - skipping layout because same as last size");
        return;
    }

    //lf("(%3d,%3d) EbookController::TriggerBookFormatting", dx, dy);
    pageSize = size; // set it early to prevent re-doing layout at the same size
    HtmlPage *newPage = PreserveTempPageShown();
    if (newPage) {
        CrashIf((formattingTemp.reparseIdx != 0) &&
                (formattingTemp.reparseIdx != newPage->reparseIdx));
    } else {
        CrashIf(formattingTemp.reparseIdx != 0);
    }

    StopFormattingThread();

    DeletePages(&pagesFromBeginning);
    DeletePages(&pagesFromPage);

    CrashIf(formattingTemp.pagesFromBeginning.Count() > 0);
    CrashIf(formattingTemp.pagesFromPage.Count() > 0);

    ShowPage(newPage, newPage != NULL);
    HtmlFormatterArgs *args = CreateFormatterArgsDoc(doc, size.dx, size.dy, &textAllocator);
    formattingThread = new EbookFormattingThread(doc, args, this);
    formattingThreadNo = formattingThread->GetNo();
    CrashIf(formattingTemp.reparseIdx < 0);
    CrashIf(formattingTemp.reparseIdx > (int)args->htmlStrLen);
    formattingThread->reparseIdx = formattingTemp.reparseIdx;
    formattingThread->Start();
    UpdateStatus();
}
void EbookController::CloseCurrentDocument()
{
    ctrls->pagesLayout->GetPage1()->SetPage(nullptr);
    ctrls->pagesLayout->GetPage2()->SetPage(nullptr);
    StopFormattingThread();
    DeletePages(&pages);
    doc.Delete();
    pageSize = SizeI(0, 0);
}
// stop layout thread (if we're closing a document we'll delete
// the ebook data, so we can't have the thread keep using it)
void EbookController::StopFormattingThread()
{
    if (!formattingThread)
        return;
    formattingThread->RequestCancel();
    bool ok = formattingThread->Join();
    CrashIf(!ok);
    delete formattingThread;
    formattingThread = nullptr;
    formattingThreadNo = -1;
    DeletePages(&incomingPages);
}
void EbookController::GoToPage(int newPageNo)
{
    if ((newPageNo < 1) || (newPageNo == currPageNo))
        return;
    if (!GetPagesFromBeginning())
        return;
    if ((size_t)newPageNo > GetPagesFromBeginning()->Count())
        return;
    ShowPage(GetPagesFromBeginning()->At(newPageNo - 1), false);
    // even if we were showing a page from pagesFromPage before, we've
    // transitioned to using pagesFromBeginning so we no longer need pagesFromPage
    DeletePages(&pagesFromPage);
    //UpdateStatus();
}
void EbookController::HandlePagesFromEbookLayout(EbookFormattingData *ft)
{
    if (formattingThreadNo != ft->threadNo) {
        // this is a message from cancelled thread, we can disregard
        lf("EbookController::HandlePagesFromEbookLayout() thread msg discarded, curr thread: %d, sending thread: %d", formattingThreadNo, ft->threadNo);
        DeleteEbookFormattingData(ft);
        return;
    }
    //lf("EbookController::HandlePagesFromEbookLayout() %d pages, ft=0x%x", ft->pageCount, (int)ft);
    if (incomingPages) {
        for (size_t i = 0; i < ft->pageCount; i++) {
            incomingPages->Append(ft->pages[i]);
        }
        int pageNo = PageForReparsePoint(incomingPages, currPageReparseIdx);
        if (pageNo > 0) {
            Vec<HtmlPage*> *toDelete = pages;
            pages = incomingPages;
            incomingPages = nullptr;
            DeletePages(&toDelete);
            GoToPage(pageNo, false);
        }
    } else {
        CrashIf(!pages);
        for (size_t i = 0; i < ft->pageCount; i++) {
            pages->Append(ft->pages[i]);
        }
    }

    if (ft->finished) {
        CrashIf(!pages);
        StopFormattingThread();
    }
    UpdateStatus();
    // don't call DeleteEbookFormattingData since
    // ft->pages are now owned by incomingPages or pages
    delete ft;
}