/*
 * MultiMail offline mail reader
 * message list

 Copyright 1996 Kolossvary Tamas <thomas@tvnet.hu>
 Copyright 1997 John Zero <john@graphisoft.hu>
 Copyright 1997-2018 William McBrine <wmcbrine@gmail.com>
 Distributed under the GNU General Public License, version 3 or later. */

#include "interfac.h"

LetterListWindow::LetterListWindow()
{
    lsorttype = mm.resourceObject->getInt(LetterSort);
}

void LetterListWindow::listSave()
{
    static const char *saveopts[] = { "Marked", "All", "This one", "Quit" };

    int marked = !(!mm.areaList->getNoOfMarked());

    int status = ui->WarningWindow("Save which?", saveopts + !marked,
                                   3 + marked);
    if (status) {
        bool saveok = ui->letterwindow.Save(status);
        if ((status == 1) && saveok)
            Move(KEY_DOWN);
    }
}

void LetterListWindow::Next()
{
    do {
        Move(KEY_DOWN);
        mm.letterList->gotoActive(active);
    } while (mm.letterList->getRead() && ((active + 1) < NumOfItems()));
}

void LetterListWindow::FirstUnread()
{
    position = 0;
    active = 0;
}

void LetterListWindow::Prev()
{
    do {
        Move(KEY_UP);
        mm.letterList->gotoActive(active);
    } while (mm.letterList->getRead() && (active > 0));
}

int LetterListWindow::NumOfItems()
{
    return mm.letterList->noOfActive();
}

void LetterListWindow::oneLine(int i)
{
    mm.letterList->gotoActive(position + i);

    int st = mm.letterList->getStatus();

    char *p = list->lineBuf;
    p += sprintf(p, format, (st & MS_MARKED) ? 'M' :
                 (st & MS_SAVED) ? 's' : ' ', (st & MS_REPLIED) ? '~' : ' ',
                 (st & MS_READ) ? '*' : ' ', mm.letterList->getMsgNum(),
                 mm.letterList->getFrom(), mm.letterList->getTo(),
                 stripre(mm.letterList->getSubject()));

    if (mm.areaList->isCollection()) {
        const char *origArea = mm.letterList->getNewsgrps();
        if (!origArea)
            origArea = mm.areaList->getDescription(mm.letterList->getAreaID());
        if (origArea)
            sprintf(p - 15, " %-13.13s ", origArea);
    }

    coltype linecol = mm.letterList->isPersonal() ? C_LLPERSONAL : C_LISTWIN;

    letterconv_in(list->lineBuf);
    DrawOne(i, (st & MS_READ) ? noemph(linecol) : emph(linecol));
}

searchret LetterListWindow::oneSearch(int x, const char *item, int mode)
{
    searchret retval;

    mm.letterList->gotoActive(x);
    retval = mm.letterList->filterCheck(item) ? True : False;

    if (!retval && (mode == s_fulltext)) {
        ui->changestate(letter);
        ui->letterwindow.setPos(-1);
        retval = ui->letterwindow.search(item);
        if (retval != True)
            ui->changestate(letterlist);
    }

    return retval;
}

void LetterListWindow::setFormat()
{
    char topformat[50];
    unsigned char tot, maxFromLen, maxToLen, maxSubjLen;

    tot = COLS - 19;
    maxSubjLen = tot / 2;
    tot -= maxSubjLen;
    maxToLen = tot / 2;
    maxFromLen = tot - maxToLen;

    if (!mm.areaList->hasTo() || (mm.areaList->isCollection() &&
        !mm.areaList->isReplyArea())) {

        maxSubjLen += maxToLen;
        maxToLen = 0;
    }

    if (mm.areaList->isReplyArea()) {
        maxSubjLen += maxFromLen;
        maxFromLen = 0;
    }

    sprintf(format, "%%c%%c%%c%%6ld  %%-%d.%ds %%-%d.%ds %%-%d.%ds",
            maxFromLen, maxFromLen, maxToLen, maxToLen, maxSubjLen,
            maxSubjLen);

    sprintf(topformat, "   Msg#%s", format + 10);
    sprintf(topline, topformat, "From", "To", "Subject");
}

void LetterListWindow::MakeActiveCore()
{
    static const char *llmodes[] = {"All", "Unread", "Marked"},
                      *llsorts[] = {"subject", "number", "from", "to"};

    int maxbott = LINES - (mm.resourceObject->getInt(ExpertMode) ? 7 : 11);
    list_max_y = (NumOfItems() < maxbott) ? NumOfItems() : maxbott;

    bool too_many = (NumOfItems() > list_max_y);

    const char *modestr = llmodes[mm.letterList->getMode()];
    const char *sortstr = llsorts[lsorttype];
    const char *pn = mm.resourceObject->get(PacketName);
    const char *filter = mm.letterList->getFilter();

    int pnlen = strlen(pn);
    if (pnlen > 20)
        pnlen = 20;
    int offset = strlen(modestr) + pnlen + 3;
    int flen = filter ? strlen(filter) + 3 : 0;
    if (flen > 20)
        flen = 20;
    int nwidth = COLS - (too_many ? 27 : 19) - offset - flen - strlen(sortstr);

    char *title = new char[COLS + 1];

    char *end = title + sprintf(title, "%.*s | %s in %.*s", pnlen, pn,
        modestr, nwidth, mm.areaList->getDescription());

    char *newend = end + sprintf(end, ", by %s", sortstr);
    if (too_many)
        newend += sprintf(newend, " (%d)", NumOfItems());
    if (flen)
        sprintf(newend, " | %.*s", flen - 3, filter);

    areaconv_in(title);

    borderCol = C_LLBBORD;

    list = new InfoWin(list_max_y + 3, list_max_x + 2, 2, borderCol,
                       title, C_LLTOPTEXT1);

    list->attrib(C_LLTOPTEXT2);

    *end = '\0';
    offset += 3;
    list->put(0, offset + 3, title + offset);

    delete[] title;

    list->attrib(C_LLHEAD);
    list->put(1, 3, topline);

    if (mm.areaList->isCollection())
        list->put(1, COLS - 19, "Area");
    list->touch();

    DrawAll();
    Select();
}

void LetterListWindow::MakeActive()
{
    top_offset = 2;
    list_max_x = COLS - 6;

    topline = new char[COLS + 1];

    setFormat();
    ui->areas.Select();
    MakeActiveCore();
}

void LetterListWindow::Select()
{
    mm.letterList->gotoActive(active);
}

void LetterListWindow::ResetActive()
{
    active = mm.letterList->getActive();
}

void LetterListWindow::Delete()
{
    delete list;
    delete[] topline;
}

bool LetterListWindow::extrakeys(int key)
{
    Select();
    switch (key) {
#ifdef USE_MOUSE
    case MM_MOUSE:
        {
            int begx = list->xstart(), begy = list->ystart();

            if (mm_mouse_event.y == begy) {
                if ((mm_mouse_event.x > (begx + 12)) &&
                    (mm_mouse_event.x < (begx + 27)))

                    extrakeys('L');
                else
                    if ((mm_mouse_event.x > (begx + 27)) &&
                        (mm_mouse_event.x < (begx + list_max_x)))

                        extrakeys('$');
            }
        }
        break;
#endif
    case 'U':
    case 'M':  // Toggle read/unread and marked from letterlist
        mm.letterList->setStatus(mm.letterList->getStatus() ^
                                 ((key == 'U') ? MS_READ : MS_MARKED));
        ui->setAnyRead();
        Move(KEY_DOWN);
        Draw();
        break;
    case 5:
    case 'E':
        if (mm.areaList->isReplyArea())
            ui->letterwindow.KeyHandle('E');
        else
            if (!(mm.areaList->getType() & (COLLECTION | READONLY))) {
                if ((5 == key) || mm.areaList->isEmail())
                    ui->addressbook();
                ui->letterwindow.EnterLetter(mm.areaList->getAreaNo(), 'E');
            } else
                ui->nonFatalError("Cannot reply there");
        break;
    case 2:
    case 6:
    case MM_DEL:
    case 'K':
        if (mm.areaList->isReplyArea())
            ui->letterwindow.KeyHandle(key);
        break;
    case 'L':
        mm.letterList->relist();
        ResetActive();
        ui->redraw();
        break;
    case '$':
        mm.letterList->resort();
        ui->redraw();
        break;
    case 'S':
        listSave();
        ui->redraw();
    }
    return false;
}

void LetterListWindow::setFilter(const char *item)
{
    mm.letterList->setFilter(item);
}
