
//  ------------------------------------------------------------------
//  GoldED+
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 1999-2000 Alexander S. Aganichev
//  ------------------------------------------------------------------
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License as
//  published by the Free Software Foundation; either version 2 of the
//  License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307 USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  Global utility functions.
//  ------------------------------------------------------------------

#include <golded.h>
#include <gwinput.h>

extern bool akamatchreply;


//  ------------------------------------------------------------------

int edit_string(char* buf, int buf_size, char* title, int helpcat)
{

    gwindow window;

    window.openxy(inforow,((MAXCOL-63)/2)-1,3,63,W_BASK,C_ASKB,C_ASKW);
    window.title(title, C_ASKT);
    if(CFG->switches.get(screenshadows))
        window.shadow(C_SHADOW);

    gwinput2 iform(window);

    std::string buf2 = buf;
    iform.setup(C_ASKW, C_ASKW, C_ASKQ, _box_table(W_BASK, 13), true);
    iform.add_field(0, 0, 1, 59, buf2, buf_size, gwinput::cvt_none, fieldupd);
    vcurshow();
    iform.run(helpcat);
    vcurhide();

    window.close();

    if(iform.dropped)
        return false;

    size_t len = buf2.length();
    while(len and ('!' > buf2[--len]))
        buf2.erase(len, 1);
    strcpy(buf, buf2.c_str());
    return make_bool(*buf);
}


//  ------------------------------------------------------------------

bool edit_pathname(char* buf, int buf_size, char* title, int helpcat)
{

    if(not edit_string(buf, buf_size, title, helpcat))
        return false;

    std::vector<FileAlias>::iterator z;
    for(z = CFG->filealias.begin(); z != CFG->filealias.end(); z++)
    {
        if(strieql(buf, z->alias))
        {
            strcpy(buf, z->file);
            break;
        }
    }

    strschg_environ(buf, buf_size);
    return true;
}


//  ------------------------------------------------------------------

bool PopupLocked(long tries, int isopen, const char* file)
{

    // Close popup window if requested
    if(tries == 0)
    {
        w_info(NULL);
        return true;
    }

    // Tell the world
    char buf[200];
    if((uint) strlen(file) > (uint) (MAXCOL-25))
        sprintf(buf, "[..]%*.*s", MAXCOL-30, MAXCOL-30, file);
    else
        strcpy(buf, file);
    w_infof(LNG->WaitLocked, buf);
    update_statuslinef(LNG->RetryOrESC, "ST_RETRYORESC", isopen ? LNG->RetryLock : LNG->RetryOpen, tries);

    // Check for keypress
    if(kbxhit())
    {

        // Return fail value if Escape was pressed
        gkey keyval = kbxget();
        if(keyval == Key_Esc)
        {
            GMenuLockLoop MenuLockLoop;
            if(MenuLockLoop.Run())
            {
                w_info(NULL);
                return false;
            }
        }
    }

    // Pause approx 1 second before trying again
#ifndef __BEOS__
    usleep(1000);
#else
    sleep(1);
#endif
    // Try again
    return true;
}


//  ------------------------------------------------------------------
//  Build zonegate address from orig/dest address

void ZonegateIt(ftn_addr& gate, ftn_addr& orig, ftn_addr& dest)
{

    gate.zone  = orig.zone;  // Send to the local zoneGate
    gate.net   = orig.zone;
    gate.node  = dest.zone;
    gate.point = 0;
}


//  ------------------------------------------------------------------

int GetAkaNo(const ftn_addr& aka)
{

    int akano = 0;
    while(akano < CFG->aka.size())
    {
        if(CFG->aka[akano].addr.equals(aka))
            return akano;
        akano++;
    }
    return -1;
}


//  ------------------------------------------------------------------

bool doinvalidate(std::string& text, const std::string& find, const std::string& replace, bool is_tearline)
{

    const size_t n = find.size();
    if(strieql(text.c_str(), find.c_str()) and (not is_tearline or (text.size() == n) or isspace(text[n])))
    {
        text.replace(0, n, replace);
        return true;
    }
    return false;
}


//  ------------------------------------------------------------------

int AkaMatchOne(const ftn_addr* mask, const ftn_addr* addr)
{

    int match = 0;

    // Count matching parts
    if((mask->zone == 0) or (addr->zone == 0) or (mask->zone == GFTN_ALL) or (mask->zone == addr->zone))
    {
        match++;
        if((mask->net == GFTN_ALL) or (mask->net == addr->net))
        {
            match++;
            if((mask->node == GFTN_ALL) or (mask->node == addr->node))
            {
                match++;
                if((mask->point == GFTN_ALL) or (mask->point == addr->point))
                {
                    match++;
                }
            }
        }
    }

    return match;
}


//  ------------------------------------------------------------------

int AkaMatch(ftn_addr* match, const ftn_addr* addr)
{

    int aka;
    std::vector<AkaMatchG>::iterator am;

    for(am = CFG->akamatch.begin(), aka=0; am != CFG->akamatch.end(); am++, aka++)
    {
        if(addr->match(am->mask))
        {
            int akano = GetAkaNo(am->aka);
            if(akano != -1)
            {
                *match = CFG->aka[akano].addr;
                return akano;
            }
        }
    }

    int bestaka = -1;
    int bestmatch = 0;
    int matchaka = 0;
    std::vector<gaka>::iterator a;

    for(a = CFG->aka.begin(), aka = 0; a != CFG->aka.end(); aka++, a++)
    {

        if(match->equals(a->addr))
        {
            if (CFG->akamatchfromto && akamatchreply)
                return aka;
            else
                matchaka = aka;
        }

        // Ignore fakenet addresses
        if(a->addr.net != a->pointnet)
        {

            int match = AkaMatchOne(&a->addr, addr);

            // Note if we found a better match
            if(match > bestmatch)
            {
                bestmatch = match;
                bestaka = aka;
            }
        }
    }

    // If there was no matching aka, use the aka
    if(bestaka == -1)
        bestaka = matchaka;
    else
    {
        // If the current address matches at least as good as the best match, don't change it
        if(bestmatch <= AkaMatchOne(match, addr))
        {
            int akano = GetAkaNo(*match);
            if(akano != -1)
                return akano;
        }
    }

    *match = CFG->aka[bestaka].addr;
    return bestaka;
}


//  ------------------------------------------------------------------

void ScreenBlankIdle()
{

    static int whb = -1;
    static int whh = -1;
    static int wascurhid = false;
    static Clock lastmoved = 0;
    int windowheight = 4;

    IdleCheckSemaphores();

    char blankmsg1[80];
    char blankmsg2[80];

    time32_t t = gtime(NULL);
    struct tm tm;
    glocaltime(&tm, &t);
    sprintf(blankmsg1, " %s %s %s ", __gver_longpid__, __gver_ver__, strftimei(blankmsg2, 40, LNG->StatusLineTimeFmt, &tm));
    sprintf(blankmsg2, " %s ", LNG->BlankMsg);

    if (strblank(blankmsg2))
    {
        *blankmsg2 = NUL;
        windowheight--;
    }

    int b1 = strlen(blankmsg1);
    int b2 = strlen(blankmsg2);
    int blankmsglen = MaxV(b1,b2);
    int ry = rand() % (MAXROW-windowheight);
    int rx = rand() % ((MAXCOL-blankmsglen)-2);

    if(blanked and (whb == -1))
    {
        wascurhid = vcurhidden();
        vcurhide();
        if (C_BACKB != (BLACK_|_BLACK))
            gvid->setoverscan(BLACK_|_BLACK);
        whb = wopen(0,0,MAXROW-1,MAXCOL-1, 5, LGREY_|_BLACK, LGREY_|_BLACK);
        if(CFG->screenblankertype == BLANK_SLIDEWIN)
            whh = wopen_(ry, rx, windowheight, blankmsglen+2, W_BINFO, C_INFOB, C_INFOW);
        lastmoved = gkbd.tickvalue;
    }

    if(not blanked and (whb != -1))
    {
        if(CFG->screenblankertype == BLANK_SLIDEWIN)
        {
            wactiv_(whh);
            wclose();
            whh = -1;
        }
        wactiv_(whb);
        wclose();
        whb = -1;
        if (C_BACKB != (BLACK_|_BLACK))
            gvid->setoverscan(C_BACKB);
        if(wascurhid)
            vcurhide();
        else
            vcurshow();
        return;
    }

    if(gkbd.tickvalue > (lastmoved+50L))
    {
        lastmoved = gkbd.tickvalue;
        if(CFG->screenblankertype == BLANK_SLIDEWIN)
            wslide(ry, rx);
    }

    if(CFG->screenblankertype == BLANK_SLIDEWIN)
    {
        wcenters(0, C_INFOW, blankmsg1);
        if(*blankmsg2)
            wcenters(1, C_INFOW, blankmsg2);
    }

    // If timed out, exit screenblanker
    if (CFG->timeout)
    {
        if (gkbd.tickvalue < gkbd.tickpress)
            gkbd.tickpress = gkbd.tickvalue;
        if (gkbd.tickvalue >= (gkbd.tickpress+(CFG->timeout*10L)))
            kbput(Key_Tick);
    }
}


//  ------------------------------------------------------------------

vattr GetColorName(const char *name, Addr &addr, vattr color)
{
    bool addr_valid = addr.valid();
    bool name_valid = (name != NULL);

    if (!addr_valid && !name_valid)
        return color;

    std::vector< std::pair<Node, vattr> >::iterator it;
    for (it = CFG->colorname.begin(); it != CFG->colorname.end(); it++)
    {
        if (addr_valid && addr.match(it->first.addr))
            return it->second;
        if (name_valid && gwildmat(name, it->first.name))
            return it->second;
    }

    return color;
}


//  ------------------------------------------------------------------

