"""Interface with Newsbase or compatible news database (eg. MsgServe).

Ensure that message 0x83581 (NewsBase_Reply) was passed to wimp.task().

Functions:

Startup() -- look for a Newsbase compatible server
ShutDown() -- Inform Newsbase that we've finished
ListGroups() -- Get a list of active groups matching the pattern
ListArts() -- Get a list of the articles available for a group
GetArticle() -- Return the filename of an article

Variables:

groups -- List of active groups, available after ListGroups()

"""


import os
import string
import wimp


def init():
    """Look for a Newsbase compatible server.
    
    Set Newsbase.active to indicate if Newsbase is running.
    Report an error if Newsbase returns one.
    
    """
    global active, handle
    active = 0
    # NewsBase_Command NewsBase_Startup
    wimp.send_message(18, 0x83580, 0, (0, 60, 0))
    event, details = wimp.poll(0x3973)
    if event == 18 and details == 0x83580:
        # got our own broadcast
        event, details = wimp.poll(0x3973)
    if event in (17, 18) and details == 0x83581:
        if wimp.b[5] == 0:
            handle = wimp.b[1]
            active = 1
        elif wimp.b[5] % 10 != 0:
            wimp.warning(wimp.b.nullstring(32, wimp.b[0]))


def quit():
    """Inform Newsbase that we've finished."""
    global active
    if active:
        wimp.send_message(17, 0x83580, handle, (10,))
    active = 0


def Reply():
    global active
    if wimp.b[5] == 0:
        init()
    elif wimp.b[5] == 10:
        active = 0


def SetUser(username, password):
    """Set the Newsbase user.
    
    Return None if OK, a string giving error otherwise.
    
    """
    wimp.send_message(17, 0x83580, handle, (20, 0, 0, username + '\0' + password))
    event, details = wimp.poll(0x3973)
    while not (event == 17 and details == 0x83581):
        event, details = wimp.poll(0x3973)
    if wimp.b[5] == 20:
        return None
    elif wimp.b[5] % 10 != 0:
        return wimp.b.nullstring(32, wimp.b[0])
    return 'Unexpected response from Newsbase'


def ListGroups(username):
    """Get a list of active groups for the given user.
    
    Returns a list of strings giving the group names,
    or a string if Newsbase returned it as an error.
    
    """
    global groups, group_ranges
    groups = []
    # NewsBase_Command NewsBase_GetUserInfo (home directory)
    wimp.send_message(17, 0x83580, handle, (440, 5, 0, username))
    event, details = wimp.poll(0x3973)
    while not (event in (17, 18) and details == 0x83581):
        event, details = wimp.poll(0x3973)
    if wimp.b[5] == 440:
        home = wimp.b.nullstring(32 + len(username) + 1, wimp.b[0])
        newsrc = None
        if os.path.isfile(os.path.join(home, 'NewsRC')):
            newsrc = os.path.join(home, 'NewsRC')
        else:
            for dir in os.listdir(home):
                if os.path.isdir(os.path.join(home, dir)):
                    if os.path.isfile(os.path.join(home, dir, 'NewsRC')):
                        newsrc = os.path.join(home, dir, 'NewsRC')
                        break
        if newsrc is None:
            return 'Unable to locate NewsRC'
        file = open(newsrc, 'r')
        groups = file.readlines()
        file.close()
        groups = map(lambda z: z[:-1].split(':')[0], groups)
        if groups[-1] == 'end':
            groups = groups[:-1]
        groups.sort()
        return groups
    elif wimp.b[5] % 10 != 0:
        return wimp.b.nullstring(32, wimp.b[0])
    return 'Unexpected response from Newsbase'


def ListArts(group):
    """Get a list of the articles available for a group.

    Returns a list of tuples of the form
    (article number, size, From:, Subject:, Message-ID:, Date:),
    or a string if Newsbase returned it as an error.
    
    Calls wimp.poll and may call wimp.handle.

    """
    articles = []

    wimp.send_message(17, 0x83580, handle, (100, 0, 0, group))
    event, details = wimp.poll(0x3973)
    while not (event == 17 and details == 0x83581):
        event, details = wimp.poll(0x3973)
    if wimp.b[5] == 100:
        pass
    elif wimp.b[5] % 10 != 0:
        return wimp.b.nullstring(32, wimp.b[0])
    else:
        return 'Unexpected response from Newsbase'

    event, details = wimp.poll(0x3973)
    while not (event == 17 and details == 0x83581):
        event, details = wimp.poll(0x3973)
    if wimp.b[5] == 100:
        pass
    elif wimp.b[5] % 10 != 0:
        return wimp.b.nullstring(32, wimp.b[0])
    else:
        return 'Unexpected response from Newsbase'

    wimp.send_message(17, 0x83580, handle, (200, 0, 0, group))
    while 1:
        event, details = wimp.poll(1)
        while not (event == 17 and details == 0x83581):
            wimp.handle((event, details))
            event, details = wimp.poll(1)
        if wimp.b[5] == 200:
            if wimp.b[6] == 0:
                return articles
            else:
                article_no = wimp.b[6]
                article_size = wimp.b[7]
                data = wimp.b.tostring(32, wimp.b[0])
                article_from, article_subject, article_id, article_date = string.split(data, chr(0))[:4]
                articles.append((article_no, article_size, article_from, article_subject,
                                 article_id, article_date))
#                    if (len(article_numbers) & 7) == 0:
#                        window_status.icon_text(2, str(len(article_numbers)))
        elif wimp.b[5] % 10 != 0:
            return wimp.b.nullstring(32, wimp.b[0])
        else:
            return 'Unexpected response from Newsbase'


def GetArticle(group, article):
    """Return the filename of an article.
    
    If successful, returns (1, filename). Otherwise returns
    (0, error message).
    
    Calls wimp.poll and may call wimp.handle.
    
    """
    wimp.send_message(17, 0x83580, handle, (220, article, 0, group))
    event, details = wimp.poll(0x141)
    while not (event in (17, 18) and details == 0x83581):
        wimp.handle((event, details))
        event, details = wimp.poll(0x141)
    if wimp.b[5] == 220:
        return 1, wimp.b.nullstring(32, wimp.b[0])
    else:
        return 0, wimp.b.nullstring(32, wimp.b[0])
