/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.

This file is part of Quake III Arena source code.

Quake III Arena source code 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.

Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
//
#include "ui_local.h"

/*
===================
MField_Draw

Handles horizontal scrolling and cursor blinking
x, y, are in pixels
===================
*/
void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ) {
        int                len;
        int                charw;
        int                drawLen;
        int                prestep;
        int                cursorChar;
        char        str[MAX_STRING_CHARS];

        drawLen = edit->widthInChars;
        len = strlen( edit->buffer ) + 1;

        // guarantee that cursor will be visible
        if ( len <= drawLen ) {
                prestep = 0;
        } else {
                if ( edit->scroll + drawLen > len ) {
                        edit->scroll = len - drawLen;
                        if ( edit->scroll < 0 ) {
                                edit->scroll = 0;
                        }
                }
                prestep = edit->scroll;
        }

        if ( prestep + drawLen > len ) {
                drawLen = len - prestep;
        }

        // extract <drawLen> characters from the field at <prestep>
        if ( drawLen >= MAX_STRING_CHARS ) {
                trap_Error( "drawLen >= MAX_STRING_CHARS" );
        }
        memcpy( str, edit->buffer + prestep, drawLen );
        str[ drawLen ] = 0;

        UI_DrawString( x, y, str, style, color );

        // draw the cursor
        if (!(style & UI_PULSE)) {
                return;
        }

        if ( trap_Key_GetOverstrikeMode() ) {
                cursorChar = 11;
        } else {
                cursorChar = 10;
        }

        style &= ~UI_PULSE;
        style |= UI_BLINK;

        if (style & UI_SMALLFONT)
        {
                charw =        SMALLCHAR_WIDTH;
        }
        else if (style & UI_GIANTFONT)
        {
                charw =        GIANTCHAR_WIDTH;
        }
        else
        {
                charw =        BIGCHAR_WIDTH;
        }

        if (style & UI_CENTER)
        {
                len = strlen(str);
                x = x - len*charw/2;
        }
        else if (style & UI_RIGHT)
        {
                len = strlen(str);
                x = x - len*charw;
        }
        
        UI_DrawChar( x + ( edit->cursor - prestep ) * charw, y, cursorChar, style & ~(UI_CENTER|UI_RIGHT), color );
}

/*
================
MField_Paste
================
*/
void MField_Paste( mfield_t *edit ) {
        char        pasteBuffer[64];
        int                pasteLen, i;

        trap_GetClipboardData( pasteBuffer, 64 );

        // send as if typed, so insert / overstrike works properly
        pasteLen = strlen( pasteBuffer );
        for ( i = 0 ; i < pasteLen ; i++ ) {
                MField_CharEvent( edit, pasteBuffer[i] );
        }
}

/*
=================
MField_KeyDownEvent

Performs the basic line editing functions for the console,
in-game talk, and menu fields

Key events are used for non-printable characters, others are gotten from char events.
=================
*/
void MField_KeyDownEvent( mfield_t *edit, int key ) {
        int                len;

        // shift-insert is paste
        if ( ( key == K_INS ) && trap_Key_IsDown( K_SHIFT ) ) {
                MField_Paste( edit );
                return;
        }

        len = strlen( edit->buffer );

        if ( key == K_DEL ) {
                if ( edit->cursor < len ) {
                        memmove( edit->buffer + edit->cursor,
                                edit->buffer + edit->cursor + 1, len - edit->cursor );
                }
                return;
        }

        if ( key == K_RIGHTARROW )
        {
                if ( edit->cursor < len ) {
                        edit->cursor++;
                }
                if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
                {
                        edit->scroll++;
                }
                return;
        }

        if ( key == K_LEFTARROW )
        {
                if ( edit->cursor > 0 ) {
                        edit->cursor--;
                }
                if ( edit->cursor < edit->scroll )
                {
                        edit->scroll--;
                }
                return;
        }

        if ( key == K_HOME || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
                edit->cursor = 0;
                edit->scroll = 0;
                return;
        }

        if ( key == K_END || ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
                edit->cursor = len;
                edit->scroll = len - edit->widthInChars + 1;
                if (edit->scroll < 0)
                        edit->scroll = 0;
                return;
        }

        if ( key == K_INS ) {
                trap_Key_SetOverstrikeMode( !trap_Key_GetOverstrikeMode() );
                return;
        }
}

/*
==================
MField_CharEvent
==================
*/
void MField_CharEvent( mfield_t *edit, int ch ) {
        int                len;

        if ( ch == 'v' - 'a' + 1 ) {        // ctrl-v is paste
                MField_Paste( edit );
                return;
        }

        if ( ch == 'c' - 'a' + 1 ) {        // ctrl-c clears the field
                MField_Clear( edit );
                return;
        }

        len = strlen( edit->buffer );

        if ( ch == 'h' - 'a' + 1 )        {        // ctrl-h is backspace
                if ( edit->cursor > 0 ) {
                        memmove( edit->buffer + edit->cursor - 1,
                                edit->buffer + edit->cursor, len + 1 - edit->cursor );
                        edit->cursor--;
                        if ( edit->cursor < edit->scroll )
                        {
                                edit->scroll--;
                        }
                }
                return;
        }

        if ( ch == 'a' - 'a' + 1 ) {        // ctrl-a is home
                edit->cursor = 0;
                edit->scroll = 0;
                return;
        }

        if ( ch == 'e' - 'a' + 1 ) {        // ctrl-e is end
                edit->cursor = len;
                edit->scroll = edit->cursor - edit->widthInChars + 1;
                if (edit->scroll < 0)
                        edit->scroll = 0;
                return;
        }

        //
        // ignore any other non printable chars
        //
        if ( ch < 32 ) {
                return;
        }

        if ( !trap_Key_GetOverstrikeMode() ) {        
                if ((edit->cursor == MAX_EDIT_LINE - 1) || (edit->maxchars && edit->cursor >= edit->maxchars))
                        return;
        } else {
                // insert mode
                if (( len == MAX_EDIT_LINE - 1 ) || (edit->maxchars && len >= edit->maxchars))
                        return;
                memmove( edit->buffer + edit->cursor + 1, edit->buffer + edit->cursor, len + 1 - edit->cursor );
        }

        edit->buffer[edit->cursor] = ch;
        if (!edit->maxchars || edit->cursor < edit->maxchars-1)
                edit->cursor++;

        if ( edit->cursor >= edit->widthInChars )
        {
                edit->scroll++;
        }

        if ( edit->cursor == len + 1) {
                edit->buffer[edit->cursor] = 0;
        }
}

/*
==================
MField_Clear
==================
*/
void MField_Clear( mfield_t *edit ) {
        edit->buffer[0] = 0;
        edit->cursor = 0;
        edit->scroll = 0;
}

/*
==================
MenuField_Init
==================
*/
void MenuField_Init( menufield_s* m ) {
        int        l;
        int        w;
        int        h;

        MField_Clear( &m->field );

        if (m->generic.flags & QMF_SMALLFONT)
        {
                w = SMALLCHAR_WIDTH;
                h = SMALLCHAR_HEIGHT;
        }
        else
        {
                w = BIGCHAR_WIDTH;
                h = BIGCHAR_HEIGHT;
        }        

        if (m->generic.name) {
                l = (strlen( m->generic.name )+1) * w;                
        }
        else {
                l = 0;
        }

        m->generic.left = m->generic.x - l;
        m->generic.top = m->generic.y;
        m->generic.right = m->generic.x + w + m->field.widthInChars*w;
        m->generic.bottom = m->generic.y + h;
}

/*
==================
MenuField_Draw
==================
*/
void MenuField_Draw( menufield_s *f )
{
        int                x;
        int                y;
        int                w;
        int                h;
        int                style;
        bool focus;
        float        *color;

        x =        f->generic.x;
        y =        f->generic.y;

        if (f->generic.flags & QMF_SMALLFONT)
        {
                w = SMALLCHAR_WIDTH;
                h = SMALLCHAR_HEIGHT;
                style = UI_SMALLFONT;
        }
        else
        {
                w = BIGCHAR_WIDTH;
                h = BIGCHAR_HEIGHT;
                style = UI_BIGFONT;
        }        

        if (Menu_ItemAtCursor( f->generic.parent ) == f) {
                focus = true;
                style |= UI_PULSE;
        }
        else {
                focus = false;
        }

        if (f->generic.flags & QMF_GRAYED)
                color = text_color_disabled;
        else if (focus)
                color = text_color_highlight;
        else
                color = text_color_normal;

        if ( focus )
        {
                // draw cursor
                UI_FillRect( f->generic.left, f->generic.top, f->generic.right-f->generic.left+1, f->generic.bottom-f->generic.top+1, listbar_color );
                UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|style, color);
        }

        if ( f->generic.name ) {
                UI_DrawString( x - w, y, f->generic.name, style|UI_RIGHT, color );
        }

        MField_Draw( &f->field, x + w, y, style, color );
}

/*
==================
MenuField_Key
==================
*/
sfxHandle_t MenuField_Key( menufield_s* m, int* key )
{
        int keycode;
        static int lastKeypress = 0;

        keycode = *key;

        switch ( keycode )
        {
                case K_KP_ENTER:
                case K_ENTER:
                case K_MOUSE1:
                 /*       if (uis.realtime > lastKeypress + 300 || keycode != K_ENTER) // Prevent text input window re-appearing on Ouya
                        {
                                trap_ScreenKeyboardTextInput( m->field.buffer );
                                MField_Clear( &m->field );
                        }
                        break;*/
                case K_JOY1:
                case K_JOY2:
                case K_JOY3:
                case K_JOY4:
                        // have enter go to next cursor point
                        *key = K_TAB;
                        break;

                case K_TAB:
                case K_DOWNARROW:
                case K_UPARROW:
                        break;

                default:
                        if ( keycode & K_CHAR_FLAG )
                        {
                                keycode &= ~K_CHAR_FLAG;

                                if ((m->generic.flags & QMF_UPPERCASE) && Q_islower( keycode ))
                                        keycode -= 'a' - 'A';
                                else if ((m->generic.flags & QMF_LOWERCASE) && Q_isupper( keycode ))
                                        keycode -= 'A' - 'a';
                                else if ((m->generic.flags & QMF_NUMBERSONLY) && Q_isalpha( keycode ))
                                        return (menu_buzz_sound);

                                MField_CharEvent( &m->field, keycode);
                        }
                        else
                                MField_KeyDownEvent( &m->field, keycode );
                        break;
        }
        lastKeypress = uis.realtime;

        return (0);
}