//  This may look like C code, but it is really -*- C++ -*-

//  ------------------------------------------------------------------
//  The Goldware Library
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 1999-2000 Alexander S. Aganichev
//  ------------------------------------------------------------------
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library 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$
//  ------------------------------------------------------------------
//  GCUI: Golded+ Character-oriented User Interface.
//  Functions for line drawing.
//  Based on CXL by Mike Smedley.
//  ------------------------------------------------------------------
//  whline() draws a horizontal text line in active window
//  wvline() draws a vertical text line in active window
//  ------------------------------------------------------------------

#include <gwinall.h>


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

#define HORZ  0
#define VERT  1


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

#define ULC   _box_table(bt, 0)    // upper left corner
#define UHL   _box_table(bt, 1)    // upper horizontal line
#define URC   _box_table(bt, 2)    // upper right corner
#define LVL   _box_table(bt, 3)    // left vertical line
#define RVL   _box_table(bt, 4)    // right vertical line
#define LLC   _box_table(bt, 5)    // lower left corner
#define LHL   _box_table(bt, 6)    // lower horizontal line
#define LRC   _box_table(bt, 7)    // lower right corner
#define MJ    _box_table(bt, 8)    // middle junction
#define LVJ   _box_table(bt, 9)    // left vertical junction
#define RVJ   _box_table(bt, 10)   // right vertical junction
#define UHJ   _box_table(bt, 11)   // upper horizontal junction
#define LHJ   _box_table(bt, 12)   // lower horizontal junction


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

static int disp_char(int wrow,int wcol, vattr attr,int btype,vchar ch,int direc)
{

    attr = attr|ACSET;

    // see if next to a border, if so, connect to it
    if(gwin.active->border)
    {

        // abbreviate pointer
        const int bt = btype;

        // calculate effective row and column
        int row = gwin.active->srow+gwin.active->border+wrow;
        int col = gwin.active->scol+gwin.active->border+wcol;

        // see if this is a horizontal or vertical line
        if(direc==HORZ)
        {

            // make sure that the box type characters match
            if(LVL==_box_table(gwin.active->btype, 3))
            {

                // check left border
                if(col==(gwin.active->scol+1))
                {
                    vputc(row,gwin.active->scol,attr,LVJ);
                    ch=UHL;
                }

                // check right border
                if(col==(gwin.active->ecol-1))
                {
                    vputc(row,gwin.active->ecol,attr,RVJ);
                    ch=UHL;
                }
            }
        }
        else
        {

            // make sure that the box type characters match
            if(UHL==_box_table(gwin.active->btype, 1))
            {

                // check top border
                if(row==(gwin.active->srow+1))
                {
                    vputc(gwin.active->srow,col,attr,UHJ);
                    ch=LVL;
                }

                // check bottom border
                if(row==(gwin.active->erow-1))
                {
                    vputc(gwin.active->erow,col,attr,LHJ);
                    ch=LVL;
                }
            }
        }
    }

    // display character
    if(wprintc(wrow,wcol,attr,ch))
        return gwin.werrno;

    // return normally
    return 0;
} /* disp_char() */


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

static inline int isupvert(int btype, vchar ch)
{

    const int bt = btype;
    return (ch==LVL or ch==UHJ or ch==ULC or ch==URC or ch==LVJ or ch==RVJ or ch==MJ) ? YES : NO;
}


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

static inline int isdownvert(int btype, vchar ch)
{

    const int bt = btype;
    return (ch==LVL or ch==LHJ or ch==LLC or ch==LRC or ch==LVJ or ch==RVJ or ch==MJ) ? YES : NO;
}


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

static inline int islefthorz(int btype, vchar ch)
{

    const int bt = btype;
    return (ch==UHL or ch==LVJ or ch==LLC or ch==ULC or ch==UHJ or ch==LHJ or ch==MJ) ? YES : NO;
}


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

static inline int isrighthorz(int btype, vchar ch)
{

    const int bt = btype;
    return (ch==UHL or ch==RVJ or ch==LRC or ch==URC or ch==UHJ or ch==LHJ or ch==MJ) ? YES : NO;
}


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

int whline(int wsrow, int wscol, int count, int btype, vattr attr)
{

    int bt;
    int row,col,up,down;
    vchar ch;

    row=wsrow;
    col=wscol;

    // abbreviate pointer
    bt = btype;

    if(count)
    {

        // see if a left junction or corner is needed
        up   = isupvert  (btype,wgetc(row-1,col));
        down = isdownvert(btype,wgetc(row+1,col));
        if(up and down)
            ch=LVJ;
        else if(up)
            ch=LLC;
        else if(down)
            ch=ULC;
        else
            ch=UHL;

        // display leftmost character
        if(disp_char(row,col,attr,btype,ch,HORZ))
            return gwin.werrno;
        col++;
        count--;
    }

    // do while not last character
    while(count>1)
    {

        // see if a middle junction is needed
        up   = isupvert  (btype,wgetc(row-1,col));
        down = isdownvert(btype,wgetc(row+1,col));
        if(up and down)
            ch=MJ;
        else if(up)
            ch=LHJ;
        else if(down)
            ch=UHJ;
        else
            ch=UHL;

        // display middle character
        if(disp_char(row,col,attr,btype,ch,HORZ))
            return gwin.werrno;
        col++;
        count--;
    }

    if(count)
    {

        // see if a right junction or corner is needed
        up   = isupvert  (btype,wgetc(row-1,col));
        down = isdownvert(btype,wgetc(row+1,col));
        if(up and down)
            ch=RVJ;
        else if(up)
            ch=LRC;
        else if(down)
            ch=URC;
        else
            ch=UHL;

        // display rightmost character
        if(disp_char(row,col,attr,btype,ch,HORZ))
            return gwin.werrno;
    }

    // return normally
    return gwin.werrno=W_NOERROR;
} /* whline() */


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

int wvline(int wsrow, int wscol, int count, int btype, vattr attr)
{

    int bt;
    int row,col,left,right;
    vchar ch;

    row=wsrow;
    col=wscol;

    // abbreviate pointer
    bt = btype;

    if(count)
    {

        // see if a top junction or corner is needed
        left  = islefthorz (btype,wgetc(row,col-1));
        right = isrighthorz(btype,wgetc(row,col+1));
        if(left and right)
            ch=UHJ;
        else if(left)
            ch=URC;
        else if(right)
            ch=ULC;
        else
            ch=LVL;

        // display uppermost character
        if(disp_char(row,col,attr,btype,ch,VERT))
            return gwin.werrno;
        row++;
        count--;
    }

    // do while not last character
    while(count>1)
    {
        left  = islefthorz (btype,wgetc(row,col-1));
        right = isrighthorz(btype,wgetc(row,col+1));
        if(left and right)
            ch=MJ;
        else if(left)
            ch=RVJ;
        else if(right)
            ch=LVJ;
        else
            ch=LVL;

        // display middle character
        if(disp_char(row,col,attr,btype,ch,VERT))
            return gwin.werrno;
        row++;
        count--;
    }

    if(count)
    {

        // see if a bottom junction or corner is needed
        left  = islefthorz (btype,wgetc(row,col-1));
        right = isrighthorz(btype,wgetc(row,col+1));
        if(left and right)
            ch=LHJ;
        else if(left)
            ch=LRC;
        else if(right)
            ch=LLC;
        else
            ch=LVL;

        // display bottommost character
        if(disp_char(row,col,attr,btype,ch,VERT))
            return gwin.werrno;
    }

    // return normally
    return gwin.werrno=W_NOERROR;
} /* wvline() */

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