/*++

  Copyright (c) 1999 Intel Corporation

  Module Name:
    libFileBuffer.c

  Abstract:
    Defines FileBuffer - the view of the file that is visible at any point, 
    as well as the event handlers for editing the file
--*/


#ifndef _LIB_FILE_BUFFER
#define _LIB_FILE_BUFFER

#include "libMisc.h"

extern  EFI_EDITOR_LINE*    FileImageCreateNode  (VOID);


#define ABSOLUTE_MAX_COLUMNS    132
STATIC  CHAR16  BlankLine[ABSOLUTE_MAX_COLUMNS];

STATIC  EFI_STATUS  FileBufferScrollUp (VOID);
STATIC  EFI_STATUS  FileBufferScrollDown (VOID);
STATIC  EFI_STATUS  FileBufferScrollLeft (VOID);
STATIC  EFI_STATUS  FileBufferScrollRight (VOID);
STATIC  EFI_STATUS  FileBufferPageUp (VOID);
STATIC  EFI_STATUS  FileBufferPageDown (VOID);
STATIC  EFI_STATUS  FileBufferHome  (VOID);
STATIC  EFI_STATUS  FileBufferEnd   (VOID);
STATIC  EFI_STATUS  FileBufferChangeMode    (VOID);

STATIC  EFI_STATUS  FileBufferDoDelete (VOID);
STATIC  EFI_STATUS  FileBufferDoBackspace (VOID);
STATIC  EFI_STATUS  FileBufferDoCharInput (CHAR16);
STATIC  EFI_STATUS  FileBufferDoReturn (VOID);


STATIC  EFI_STATUS  FileBufferRefreshCurrentLine(VOID);
STATIC  EFI_STATUS  FileBufferRefreshDown(VOID);

STATIC  EFI_STATUS  FileBufferInit (VOID);
STATIC  EFI_STATUS  FileBufferCleanup (VOID);
STATIC  EFI_STATUS  FileBufferRefresh (VOID);
STATIC  EFI_STATUS  FileBufferHide (VOID);
STATIC  EFI_STATUS  FileBufferHandleInput (EFI_INPUT_KEY*);

STATIC  EFI_STATUS  FileBufferClearLine (UINTN);
STATIC  EFI_STATUS  FileBufferSetPosition (UINTN,UINTN);
STATIC  EFI_STATUS  FileBufferRestorePosition (VOID);

EFI_EDITOR_FILE_BUFFER  FileBuffer = {
    {0,0},
    {0,0},
    {0,0},
    {0,0},
    0,
    0,
    TRUE,
    NULL,
    FileBufferInit,
    FileBufferCleanup,
    FileBufferRefresh,
    FileBufferHide,
    FileBufferHandleInput,
    FileBufferClearLine,
    FileBufferSetPosition,
    FileBufferRestorePosition,
    FileBufferRefreshCurrentLine
};

EFI_EDITOR_FILE_BUFFER  FileBufferConst = {
    {0,0},
    {0,0},
    {0,0},
    {0,0},
    0,
    0,
    TRUE,
    NULL,
    FileBufferInit,
    FileBufferCleanup,
    FileBufferRefresh,
    FileBufferHide,
    FileBufferHandleInput,
    FileBufferClearLine,
    FileBufferSetPosition,
    FileBufferRestorePosition,
    FileBufferRefreshCurrentLine
};


STATIC
EFI_STATUS
FileBufferInit (
    VOID
    )
{ 
    UINTN   i;

    CopyMem (&FileBuffer, &FileBufferConst, sizeof(FileBuffer));

    FileBuffer.DisplayPosition.Row = TEXT_START_ROW;
    FileBuffer.DisplayPosition.Column = TEXT_START_COLUMN;
    FileBuffer.LowVisibleRange.Row = TEXT_START_ROW;
    FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;
    FileBuffer.MaxVisibleRows = MAX_TEXT_ROWS;
    FileBuffer.MaxVisibleColumns = MAX_TEXT_COLUMNS;
    FileBuffer.HighVisibleRange.Row = MAX_TEXT_ROWS;
    FileBuffer.HighVisibleRange.Column = MAX_TEXT_COLUMNS;

    for (i = 0; i < MAX_TEXT_COLUMNS; i++) {
        BlankLine[i] = ' ';
    }
    BlankLine[i-1] = 0;

    FileBuffer.LowVisibleRange.Row = TEXT_START_ROW;
    FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;

    FileBuffer.MaxVisibleRows = MAX_TEXT_ROWS;
    FileBuffer.MaxVisibleColumns = MAX_TEXT_COLUMNS;

    FileBuffer.FilePosition.Row = 1;
    FileBuffer.FilePosition.Column = 1;

    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS
FileBufferCleanup   (
    VOID
    )
{
    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS
FileBufferRefresh (
    VOID
    )
{
    LIST_ENTRY          *Item;
    UINTN               Row;

    Row = FileBuffer.DisplayPosition.Row;
    FileBuffer.DisplayPosition.Row = TEXT_START_ROW;

    Item = FileBuffer.CurrentLine;

    LineRetreat(FileBuffer.FilePosition.Row - FileBuffer.LowVisibleRange.Row);

    FileBufferRefreshDown();

    FileBuffer.CurrentLine = Item;

    FileBuffer.DisplayPosition.Row = Row;
    FileBufferRestorePosition();

    return EFI_SUCCESS; 
}


STATIC
EFI_STATUS
FileBufferRefreshCurrentLine (
    VOID
    )
{
    EFI_EDITOR_LINE *Line;
    UINTN           Where;
    CHAR16          *StrLine;
    UINTN           StartColumn;

    Where = FileBuffer.DisplayPosition.Row;
    StartColumn = FileBuffer.LowVisibleRange.Column;

    FileBufferClearLine(Where);

    Line = LineCurrent();

    if (Line->Link.Blink == MainEditor.FileImage->ListHead && 
        FileBuffer.DisplayPosition.Row > TEXT_START_ROW) {
        return EFI_SUCCESS;
    }

    if (Line->Size < StartColumn) {
        FileBufferRestorePosition();
        return EFI_SUCCESS;
    }

    StrLine = PoolPrint(L"%s",Line->Buffer + StartColumn);
    if ((Line->Size - StartColumn)> FileBuffer.MaxVisibleColumns) {
        StrLine[FileBuffer.MaxVisibleColumns-2] = 0;
    } else {
        StrLine[(Line->Size - StartColumn)] = 0;
    }

/*   PrintAt(0,Where,StrLine); */
    Out->SetCursorPosition(Out,0,Where);
    Out->OutputString(Out,StrLine);

    FreePool(StrLine);

    FileBufferRestorePosition();
    return EFI_SUCCESS;
}

STATIC
EFI_STATUS
FileBufferRefreshDown (
    VOID
    )
{
    LIST_ENTRY  *Item;
    LIST_ENTRY  *Link;
    UINTN       Row;

    Row = FileBuffer.DisplayPosition.Row;

    Item = FileBuffer.CurrentLine;
    Link = FileBuffer.CurrentLine;

    while (FileBuffer.DisplayPosition.Row <= MAX_TEXT_ROWS) {
        if (Link->Flink != MainEditor.FileImage->ListHead) {
            FileBufferRefreshCurrentLine();
            LineNext();
            Link = FileBuffer.CurrentLine;
        } else {
            FileBufferClearLine(FileBuffer.DisplayPosition.Row);
        }
        FileBuffer.DisplayPosition.Row++;
    }

    FileBuffer.CurrentLine = Item;

    FileBuffer.DisplayPosition.Row = Row;
    FileBufferRestorePosition();

    return EFI_SUCCESS;
}

STATIC
EFI_STATUS
FileBufferHandleInput (
    IN  EFI_INPUT_KEY*  Key
    )
{ 

    switch (Key->ScanCode) {
    case    SCAN_CODE_NULL:
        FileBufferDoCharInput (Key->UnicodeChar);
        break;
    case    SCAN_CODE_UP:
        FileBufferScrollUp();
        break;
    case    SCAN_CODE_DOWN:
        FileBufferScrollDown();
        break;
    case    SCAN_CODE_RIGHT:
        FileBufferScrollRight();
        break;
    case    SCAN_CODE_LEFT:
        FileBufferScrollLeft();
        break;
    case    SCAN_CODE_PGUP:
        FileBufferPageUp();
        break;
    case    SCAN_CODE_PGDN:
        FileBufferPageDown();
        break;
    case    SCAN_CODE_DEL:
        FileBufferDoDelete();
        break;
    case    SCAN_CODE_HOME:
        FileBufferHome();
        break;
    case    SCAN_CODE_END:
        FileBufferEnd();
        break;
    case    SCAN_CODE_INS:
        FileBufferChangeMode();
        break;
    default:
        break;
    }

    return EFI_SUCCESS; 
}


STATIC
EFI_STATUS
FileBufferHide (
    VOID
    )
{ 
    UINTN   i;

    for (i = TEXT_START_ROW; i < FileBuffer.MaxVisibleRows; i++ ) {
        FileBufferClearLine(i);
    }

    return EFI_SUCCESS; 
}


STATIC
EFI_STATUS
FileBufferClearLine (
    UINTN Line
    ) 
{
    PrintAt(0,Line,BlankLine);
    return EFI_SUCCESS;
}

STATIC
EFI_STATUS
FileBufferSetPosition (
    IN  UINTN   Row,
    IN  UINTN   Column
    )
{
    FileBuffer.DisplayPosition.Row = Row;
    FileBuffer.DisplayPosition.Column = Column;

    return EFI_SUCCESS;
}

STATIC
EFI_STATUS
FileBufferRestorePosition (
    VOID
    )
{
    Out->SetCursorPosition (Out,FileBuffer.DisplayPosition.Column,FileBuffer.DisplayPosition.Row);

    return EFI_SUCCESS;
}


STATIC
EFI_STATUS
FileBufferScrollDown (
    VOID
)
{
    UINTN               CurrentRow;
    UINTN               CurrentCol;
    UINTN               MaxRows;
    UINTN               HighRow;
    EFI_EDITOR_LINE     *Line;
    BOOLEAN             Refresh = FALSE;
    
    Line = LineCurrent();
    if (Line->Link.Flink == MainEditor.FileImage->ListHead) {
        return EFI_SUCCESS;
    }

    CurrentRow = FileBuffer.DisplayPosition.Row;
    CurrentCol = FileBuffer.DisplayPosition.Column;
    MaxRows = FileBuffer.MaxVisibleRows;
    HighRow = FileBuffer.HighVisibleRange.Row;
    
        /*  Current row is the bottom row, shift only one line, not scroll the whole screen. */
    if (CurrentRow == MaxRows) {
        FileBuffer.LowVisibleRange.Row += 1;
        FileBuffer.HighVisibleRange.Row += 1;
        CurrentRow = MaxRows;
        Refresh = TRUE;
    } else if (CurrentRow == HighRow) {
        return EFI_SUCCESS;
    } else {
        ++CurrentRow;
    }

    Line = LineNext();

    if (FileBuffer.FilePosition.Column > (Line->Size-1)) {
        FileBuffer.FilePosition.Column = Line->Size;
        if (Line->Size < FileBuffer.LowVisibleRange.Column) {
            if (FileBuffer.LowVisibleRange.Column < FileBuffer.MaxVisibleColumns) {
                FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;
            } else {
                FileBuffer.LowVisibleRange.Column = Line->Size - FileBuffer.MaxVisibleColumns + 2;
            }
            FileBuffer.HighVisibleRange.Column = FileBuffer.LowVisibleRange.Column + FileBuffer.MaxVisibleColumns - 1;
            Refresh = TRUE;
        }
        CurrentCol = FileBuffer.FilePosition.Column - FileBuffer.LowVisibleRange.Column - 1;
    }

    if (Refresh) {
        FileBufferRefresh();
    }
    FileBuffer.SetPosition(CurrentRow,CurrentCol);

    ++FileBuffer.FilePosition.Row;

    MainEditor.StatusBar->SetPosition(FileBuffer.FilePosition.Row,FileBuffer.FilePosition.Column);

    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS
FileBufferScrollUp (
    VOID
    )
{ 
    UINTN           CurrentRow;
    UINTN           CurrentCol;
    UINTN           MaxRows;
    UINTN           LowRow;
    EFI_EDITOR_LINE *Line;

    if ( FileBuffer.FilePosition.Row <= TEXT_START_ROW ) {
        return EFI_SUCCESS;
    }

    MaxRows = FileBuffer.MaxVisibleRows;
    LowRow = FileBuffer.LowVisibleRange.Row;

    CurrentRow = FileBuffer.DisplayPosition.Row;
    CurrentCol = FileBuffer.DisplayPosition.Column;

        /*  Current row is the top row, shift only one line, not scroll the whole screen. */
    if (CurrentRow == TEXT_START_ROW) {
        
        FileBuffer.HighVisibleRange.Row -= 1;
        FileBuffer.LowVisibleRange.Row -= 1;
        CurrentRow = TEXT_START_ROW;                
        FileBuffer.Refresh();
    } else {
        CurrentRow--;
    }
        
    Line = LinePrevious ();

    if (FileBuffer.FilePosition.Column > (Line->Size-1)) {

        FileBuffer.FilePosition.Column = Line->Size;

        if (Line->Size < FileBuffer.LowVisibleRange.Column) {
            if ( FileBuffer.LowVisibleRange.Column < FileBuffer.MaxVisibleColumns ) {
                FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;
            } else {
                FileBuffer.LowVisibleRange.Column = Line->Size - FileBuffer.MaxVisibleColumns + 2;
            }
            FileBuffer.HighVisibleRange.Column = FileBuffer.LowVisibleRange.Column + FileBuffer.MaxVisibleColumns - 1;
            FileBuffer.Refresh();
        }
        CurrentCol = FileBuffer.FilePosition.Column - FileBuffer.LowVisibleRange.Column - 1;
    }

    FileBuffer.SetPosition(CurrentRow,CurrentCol);

    --FileBuffer.FilePosition.Row;
    MainEditor.StatusBar->SetPosition(FileBuffer.FilePosition.Row,FileBuffer.FilePosition.Column);

    return EFI_SUCCESS; 
}


STATIC
EFI_STATUS
FileBufferPageUp (
    VOID
    )
{
    UINTN           MaxRows;
    UINTN           LowRow;
    UINTN           FilePos;
    EFI_EDITOR_LINE *Line;

    if ( FileBuffer.FilePosition.Row <= TEXT_START_ROW ) {
        return EFI_SUCCESS;
    }

    MaxRows = FileBuffer.MaxVisibleRows;
    LowRow = FileBuffer.LowVisibleRange.Row;
    FilePos = FileBuffer.FilePosition.Row;

    if (LowRow < MaxRows) {
        FileBuffer.HighVisibleRange.Row = MaxRows;
        FileBuffer.LowVisibleRange.Row = 1;
        if (LowRow > TEXT_START_ROW) {
            if (FilePos > MaxRows){
                FileBuffer.DisplayPosition.Row = FilePos - MaxRows;
            } else {
                FileBuffer.DisplayPosition.Row = 1;
            }
        } else {
            FileBuffer.DisplayPosition.Row = 1;
            FileBuffer.DisplayPosition.Column = TEXT_START_COLUMN;          
        }
        FileBuffer.FilePosition.Row = FileBuffer.DisplayPosition.Row;
    } else {
        FileBuffer.HighVisibleRange.Row = LowRow;
        FileBuffer.LowVisibleRange.Row -= (MaxRows - 1);
        FileBuffer.FilePosition.Row -= (MaxRows - 1);
    }

    LineRetreat(FilePos - FileBuffer.FilePosition.Row);
    Line = LineCurrent ();

    if (FileBuffer.FilePosition.Column > (Line->Size-1)) {

        FileBuffer.FilePosition.Column = Line->Size;

        if (Line->Size < FileBuffer.LowVisibleRange.Column ) {
            if ( FileBuffer.LowVisibleRange.Column < FileBuffer.MaxVisibleColumns ) {
                FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;
            } else {
                FileBuffer.LowVisibleRange.Column = Line->Size - FileBuffer.MaxVisibleColumns + 2;
            }
            FileBuffer.HighVisibleRange.Column = FileBuffer.LowVisibleRange.Column + FileBuffer.MaxVisibleColumns - 1;
        }
        FileBuffer.DisplayPosition.Column = FileBuffer.FilePosition.Column - FileBuffer.LowVisibleRange.Column - 1;
        FileBuffer.Refresh();
    }

    FileBuffer.Refresh();

    MainEditor.StatusBar->SetPosition(FileBuffer.FilePosition.Row,FileBuffer.FilePosition.Column);

    return EFI_SUCCESS;
}


STATIC
EFI_STATUS
FileBufferPageDown (
    VOID
    )
{ 
    UINTN           MaxRows;
    UINTN           HighRow;
    UINTN           FilePos;
    EFI_EDITOR_LINE *Line;
    BOOLEAN         Refresh = FALSE;

    if (FileBuffer.FilePosition.Row == MainEditor.FileImage->NumLines) {
        return EFI_SUCCESS;
    }

    MaxRows = FileBuffer.MaxVisibleRows;
    HighRow = FileBuffer.HighVisibleRange.Row;
    FilePos = FileBuffer.FilePosition.Row;

    FileBuffer.FilePosition.Row = min((FileBuffer.FilePosition.Row+MaxRows-1),MainEditor.FileImage->NumLines);
    if (HighRow < MainEditor.FileImage->NumLines) {
        FileBuffer.LowVisibleRange.Row = HighRow;
        FileBuffer.HighVisibleRange.Row = HighRow + (MaxRows-1);
        Refresh = TRUE;
    }

    FileBuffer.DisplayPosition.Row = TEXT_START_ROW + FileBuffer.FilePosition.Row - FileBuffer.LowVisibleRange.Row;
    
    Line = LineAdvance(FileBuffer.FilePosition.Row - FilePos);

    if (FileBuffer.FilePosition.Column > (Line->Size-1) || !Refresh) {
        FileBuffer.FilePosition.Column = Line->Size;
        if (Line->Size < FileBuffer.LowVisibleRange.Column ) {
            if (FileBuffer.LowVisibleRange.Column < FileBuffer.MaxVisibleColumns) {
                FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;
            } else {
                FileBuffer.LowVisibleRange.Column = Line->Size - FileBuffer.MaxVisibleColumns + 2;
            }
            FileBuffer.HighVisibleRange.Column = FileBuffer.LowVisibleRange.Column + FileBuffer.MaxVisibleColumns - 1;
            Refresh = TRUE;
        }
        FileBuffer.DisplayPosition.Column = FileBuffer.FilePosition.Column - FileBuffer.LowVisibleRange.Column - 1;
    }

    if (Refresh) {
        FileBuffer.Refresh();
    }

    MainEditor.StatusBar->SetPosition(FileBuffer.FilePosition.Row,FileBuffer.FilePosition.Column);

    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS
FileBufferScrollLeft (
    VOID
    )
{
    UINTN   CurrentCol;
    UINTN   CurrentRow;
    UINTN   MaxCols;
    UINTN   HighCol;
    UINTN   LowCol;
    EFI_EDITOR_POSITION FilePos;    
    EFI_EDITOR_LINE *Line;

    CurrentCol = FileBuffer.DisplayPosition.Column;
    CurrentRow = FileBuffer.DisplayPosition.Row;
    MaxCols = FileBuffer.MaxVisibleColumns;
    HighCol = FileBuffer.HighVisibleRange.Column;
    LowCol = FileBuffer.LowVisibleRange.Column;
    FilePos = FileBuffer.FilePosition;
    Line = LineCurrent ();

    if ( FilePos.Row == 1 && FilePos.Column == 1) {
        return EFI_SUCCESS;
    }

    if ( Line->Size == 0 || FilePos.Column == TEXT_START_COLUMN + 1 ) {
        FileBufferScrollUp ();
        Line = LineCurrent (); 
        CurrentCol = Line->Size - 1;

        if ( CurrentCol > HighCol ) {
            if ( CurrentCol  < MaxCols ) {
                FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;
                FileBuffer.HighVisibleRange.Column = MaxCols;
            } else {
                FileBuffer.HighVisibleRange.Column = CurrentCol;
                FileBuffer.LowVisibleRange.Column = CurrentCol - MaxCols + 1;
            }
            FileBuffer.Refresh();
        }
        FileBuffer.FilePosition.Column = CurrentCol + 1;
        FileBuffer.DisplayPosition.Column = CurrentCol - FileBuffer.LowVisibleRange.Column;
    } else if ( FilePos.Column <= LowCol+1 ) {
        if ( LowCol <= MaxCols ) {
            LowCol = TEXT_START_COLUMN;
        } else {
            LowCol -= (MaxCols-1);
        }
        FileBuffer.LowVisibleRange.Column = LowCol;
        FileBuffer.HighVisibleRange.Column = LowCol + MaxCols - 1;
        FileBuffer.DisplayPosition.Column = FilePos.Column - LowCol - 2;
        --FileBuffer.FilePosition.Column;

        FileBuffer.Refresh();
    } else {
        --FileBuffer.DisplayPosition.Column;
        --FileBuffer.FilePosition.Column;
    }
    MainEditor.StatusBar->SetPosition(FileBuffer.FilePosition.Row,FileBuffer.FilePosition.Column);

    return EFI_SUCCESS;
}

STATIC
EFI_STATUS
FileBufferScrollRight (
    VOID
    )
{ 
    EFI_EDITOR_POSITION FilePos;
    EFI_EDITOR_POSITION CurrentPos;
    EFI_EDITOR_LINE     *Line;
    UINTN               LineSize;
    UINTN               MaxCols;
    UINTN               LowCol;
    UINTN               HighCol;

    CurrentPos = FileBuffer.DisplayPosition;
    FilePos = FileBuffer.FilePosition;
    Line = LineCurrent ();
    LineSize = Line->Size;
    MaxCols = FileBuffer.MaxVisibleColumns;
    LowCol = FileBuffer.LowVisibleRange.Column;
    HighCol = FileBuffer.HighVisibleRange.Column;

    if (FilePos.Column >= (Line->Size-1) && FilePos.Row >= MainEditor.FileImage->NumLines) {
        return EFI_SUCCESS;
    }

    if (LineSize == 0 || FilePos.Column >= LineSize) {
        FileBufferScrollDown();

        CurrentPos.Column = TEXT_START_COLUMN;

        if (LowCol > TEXT_START_COLUMN) {
            FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;

            FileBuffer.HighVisibleRange.Column = MaxCols;
            FileBuffer.Refresh ();
        }
        FileBuffer.FilePosition.Column = 1;
        FileBuffer.DisplayPosition.Column = TEXT_START_COLUMN;
    } else if (CurrentPos.Column >= (MaxCols - 1)) {
        FileBuffer.LowVisibleRange.Column = HighCol - 2;
        FileBuffer.HighVisibleRange.Column = HighCol + MaxCols - 2;

        ++FileBuffer.FilePosition.Column;

        FileBuffer.DisplayPosition.Column = TEXT_START_COLUMN + 2;

        FileBuffer.Refresh();
    } else {
        ++FileBuffer.FilePosition.Column;
        ++FileBuffer.DisplayPosition.Column;
    }

    MainEditor.StatusBar->SetPosition(FileBuffer.FilePosition.Row,FileBuffer.FilePosition.Column);
    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS
FileBufferHome  (
    VOID
    )
{
    FileBuffer.DisplayPosition.Column = TEXT_START_COLUMN;
    FileBuffer.FilePosition.Column = TEXT_START_COLUMN + 1;

    if (FileBuffer.LowVisibleRange.Column != TEXT_START_COLUMN) {
        FileBuffer.LowVisibleRange.Column = TEXT_START_COLUMN;
        FileBuffer.HighVisibleRange.Column = FileBuffer.MaxVisibleColumns;
        FileBuffer.Refresh ();
    }

    MainEditor.StatusBar->SetPosition (FileBuffer.FilePosition.Row,TEXT_START_COLUMN+1);

    return EFI_SUCCESS;
}

STATIC
EFI_STATUS
FileBufferEnd   (
    VOID
    )
{
    EFI_EDITOR_LINE *Line;

    Line = LineCurrent ();

    FileBuffer.FilePosition.Column = Line->Size;

    if (FileBuffer.HighVisibleRange.Column < (Line->Size - 1)) {
        FileBuffer.HighVisibleRange.Column = Line->Size - 1;
        FileBuffer.LowVisibleRange.Column = Line->Size - FileBuffer.MaxVisibleColumns;
        FileBuffer.Refresh();
    }
    FileBuffer.DisplayPosition.Column = Line->Size - FileBuffer.LowVisibleRange.Column - 1;

    MainEditor.StatusBar->SetPosition (FileBuffer.FilePosition.Row,Line->Size);

    return EFI_SUCCESS;
}

STATIC
EFI_STATUS
FileBufferDoCharInput (
    IN  CHAR16  Char
    )
{
    switch (Char) {
    case 0:
        break;
    case 0x08:
        FileBufferDoBackspace();
        break;
    case 0x0a:
    case 0x0d:
        FileBufferDoReturn();
        break;
    default:
        {
            EFI_EDITOR_LINE *Line;
            UINTN           FilePos;
            Line = LineCurrent ();
            if (Line->Link.Flink != MainEditor.FileImage->ListHead) {
                FilePos = FileBuffer.FilePosition.Column - 1;
                if (FileBuffer.ModeInsert || FilePos >= Line->Size-1) {
                    StrInsert (&Line->Buffer,Char,FilePos,Line->Size+1);
                    Line->Size++;
                } else {
                    Line->Buffer[FilePos] = Char;
                }
            } else {
                Line->Buffer[0] = Char;
                Line->Size++;
                FileImageCreateNode();
            }
            FileBufferRefreshCurrentLine();
            FileBufferScrollRight();
        }
        if (!MainEditor.FileModified) {
            MainEditor.FileModified = TRUE;
            MainEditor.TitleBar->Refresh();
        }
        break;
    }
    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS
FileBufferDoBackspace (
    VOID
    )
{
    EFI_EDITOR_LINE *Line;
    EFI_EDITOR_LINE *End;
    LIST_ENTRY      *Link;
    UINTN           FileColumn;

    FileColumn = FileBuffer.FilePosition.Column - 1;

    if (FileColumn == TEXT_START_COLUMN) {
        if (FileBuffer.FilePosition.Row == 1) {
            return EFI_SUCCESS;
        }
        FileBufferScrollLeft();
        Line = LineCurrent ();

        Link = Line->Link.Flink;
        End = CR(Link,EFI_EDITOR_LINE,Link,EFI_EDITOR_LINE_LIST);
        LineCat(Line,End);

        RemoveEntryList(&End->Link);
        FreePool(End);

        --MainEditor.FileImage->NumLines;
        FileBufferRefresh();

    } else {
        Line = LineCurrent ();
        LineDeleteAt(Line,FileColumn-1);
        FileBufferRefreshCurrentLine();
        FileBufferScrollLeft();
    }
    if (!MainEditor.FileModified) {
        MainEditor.FileModified = TRUE;
        MainEditor.TitleBar->Refresh();
    }

    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS  
FileBufferDoDelete (
    VOID
    )
{
    EFI_EDITOR_LINE *Line;
    EFI_EDITOR_LINE *Next;
    LIST_ENTRY      *Link;
    UINTN           FileColumn;

    Line = LineCurrent ();
    FileColumn = FileBuffer.FilePosition.Column - 1;

    if (Line->Link.Flink == MainEditor.FileImage->ListHead) {
        return EFI_SUCCESS;
    }

    if (FileColumn >= Line->Size - 1) {
        Link = Line->Link.Flink;
        if (Link->Flink == MainEditor.FileImage->ListHead) {
            return EFI_SUCCESS;
        }
        Next = CR(Link,EFI_EDITOR_LINE,Link,EFI_EDITOR_LINE_LIST);
        LineCat(Line,Next);

        RemoveEntryList(&Next->Link);
        FreePool(Next);
        --MainEditor.FileImage->NumLines;
        FileBufferRefresh();
    } else {
        LineDeleteAt (Line,FileColumn);
        FileBufferRefreshCurrentLine();
    }

    if (!MainEditor.FileModified) {
        MainEditor.FileModified = TRUE;
        MainEditor.TitleBar->Refresh();
    }

    return EFI_SUCCESS; 
}

STATIC
EFI_STATUS
FileBufferDoReturn (
    VOID
    )
{
    EFI_EDITOR_LINE *Line;
    EFI_EDITOR_LINE *NewLine;
    UINTN           FileColumn;

    Line = LineCurrent ();
    FileColumn = FileBuffer.FilePosition.Column - 1;

    NewLine = AllocatePool(sizeof(EFI_EDITOR_LINE));
    NewLine->Signature = EFI_EDITOR_LINE_LIST;
    NewLine->Size = Line->Size - FileColumn;
    if (NewLine->Size > 1) {
        NewLine->Buffer = PoolPrint(L"%s\0",Line->Buffer+FileColumn);
    } else {
        NewLine->Buffer = PoolPrint(L" \0");
    }

    Line->Buffer[FileColumn] = ' ';
    Line->Buffer[FileColumn+1] = 0;
    Line->Size = FileColumn + 1;

    NewLine->Link.Blink = &(Line->Link);
    NewLine->Link.Flink = Line->Link.Flink;
    Line->Link.Flink->Blink = &(NewLine->Link);
    Line->Link.Flink = &(NewLine->Link);

    ++MainEditor.FileImage->NumLines;

    BS->Stall(50);
    FileBufferRefreshDown();
    FileBufferScrollRight();
    if (!MainEditor.FileModified) {
        MainEditor.FileModified = TRUE;
        MainEditor.TitleBar->Refresh();
    }

    return EFI_SUCCESS;
}


STATIC
EFI_STATUS
FileBufferChangeMode    (
    VOID
    )
{

    FileBuffer.ModeInsert = !FileBuffer.ModeInsert;
    MainEditor.StatusBar->SetMode(FileBuffer.ModeInsert);
    MainEditor.StatusBar->Refresh();
    return EFI_SUCCESS;
}


#endif  /*  _LIB_FILE_BUFFER */