/*
Copyright (C) 2003-2006 Andrey Nazarov

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.

*/

#include "ui_local.h"

/*
=======================================================================

DEMOS MENU

=======================================================================
*/

#define MAX_MENU_DEMOS	1024

#define FFILE_UP	1
#define FFILE_FOLDER	2
#define FFILE_DEMO	3

#define ID_LIST			105

typedef struct m_demos_s {
	menuFrameWork_t		menu;
	menuList_t		list;
	menuList_t		playerList;
	menuStatic_t	banner;

	int				count;
	char		*names[MAX_MENU_DEMOS];
	int			types[MAX_MENU_DEMOS];
	char		*playerNames[MAX_DEMOINFO_CLIENTS+1];

	// Demo file info
	demoInfo_t	demo;
} m_demos_t;

static m_demos_t	m_demos;
static char			m_demos_browse[MAX_QPATH];
static int			m_demos_selection;

static void Demos_FreeInfo( void ) {
	memset( &m_demos.demo, 0, sizeof( m_demos.demo ) );

	m_demos.playerList.generic.flags |= QMF_HIDDEN;
}

static void Demos_LoadInfo( int index ) {
	char buffer[MAX_QPATH];
	int i, numNames, localPlayerNum;

	if( m_demos.types[index] != FFILE_DEMO ) {
		m_demos.playerList.generic.flags |= QMF_HIDDEN;
		m_demos.menu.statusbar = NULL;
		return;
	}


	Com_sprintf( buffer, sizeof( buffer ), "%s/%s", m_demos_browse + 1, m_demos.names[index] );

	client.GetDemoInfo( buffer, &m_demos.demo );

	if( !m_demos.demo.mapname[0] ) {
	    m_demos.menu.statusbar = "Couldn't read demo info";
		m_demos.playerList.generic.flags |= QMF_HIDDEN;
		return;
	}
    

	localPlayerNum = 0;

	numNames = 0;
	for( i = 0; i < MAX_DEMOINFO_CLIENTS; i++ ) {
		if( !m_demos.demo.clients[i][0] ) {
			continue;
		}

		if( i == m_demos.demo.clientNum ) {
			localPlayerNum = numNames;
		}

		// ( m_demos.demo.mvd || i == m_demos.demo.clientNum ) ? colorYellow : NULL

		m_demos.playerNames[numNames++] = m_demos.demo.clients[i];
	}

	if( numNames ) {
		m_demos.playerList.generic.flags &= ~QMF_HIDDEN;
	} else {
		m_demos.playerList.generic.flags |= QMF_HIDDEN;
	}

	m_demos.playerNames[numNames] = NULL;

    if( m_demos.demo.mvd ) {
    	m_demos.menu.statusbar = "Press Enter to play";
    } else {
    	m_demos.menu.statusbar = "Press Enter to play, "
            "hold Shift to play on server";
    }

	MenuList_Init( &m_demos.playerList );
	MenuList_SetValue( &m_demos.playerList, localPlayerNum );
}

static char *Demos_BuildName( const char *base, const char *extenstion, int fileSize, int fileType ) {
	char *type, *sizeString, *s;

	switch( fileType ) {
	case FFILE_UP:
		sizeString = "";
		type = " UP";
		break;
	case FFILE_FOLDER:
		sizeString = "";
		type = "DIR";
		break;
	case FFILE_DEMO:
		sizeString = va( "%4i", fileSize );
		if( !strncmp( extenstion, ".mvd2", 5 ) ) {
			type = "MVD";
		} else {
			type = "DM2";
		}
		break;
	default:
		type = "";
		sizeString = "";
		break;
	}

	s = UI_FormatColumns( 3, base, sizeString, type );

	return s;

}

static void Demos_Scan( const char *path, const char *extenstion ) {
	int numFiles;
	char **list;
	int i;
	fsFileInfo_t *info;
	
	list = fs.ListFiles( path, extenstion, FS_PATH_GAME|FS_SEARCH_EXTRAINFO, &numFiles );
	if( !list ) {
		return;
	}

	for( i = 0; i < numFiles; i++ ) {
		if( m_demos.count == MAX_MENU_DEMOS - 1 ) {
			break;
		}

		info = ( fsFileInfo_t * )( list[i] + strlen( list[i] ) + 1 );

		m_demos.names[m_demos.count] = Demos_BuildName( list[i], extenstion, info->fileSize >> 10, FFILE_DEMO );
		m_demos.types[m_demos.count] = FFILE_DEMO;
		m_demos.count++;
	}

	fs.FreeFileList( list );
	
}

static void Demos_BuildList( const char *path ) {
	int numFiles;
	char **list;
	int pos;
	int i;

	if( *path == '/' ) {
		path++;
	}
	
	if( *path ) {
		m_demos.names[m_demos.count] = Demos_BuildName( "..", NULL, -1, FFILE_UP );
		m_demos.types[m_demos.count] = FFILE_UP;
		m_demos.count++;
	}

	// List directories first
	list = fs.ListFiles( path, NULL, FS_PATH_GAME|FS_SEARCHDIRS_ONLY, &numFiles );
	if( list ) {
		for( i = 0; i < numFiles; i++ ) {
			if( m_demos.count == MAX_MENU_DEMOS - 1 ) {
				break;
			}
			m_demos.names[m_demos.count] = Demos_BuildName( list[i], NULL, -1, FFILE_FOLDER );
			m_demos.types[m_demos.count] = FFILE_FOLDER;
			m_demos.count++;
		}

		fs.FreeFileList( list );
	}	

	pos = m_demos.count;

	Demos_Scan( path, ".dm2" );
	Demos_Scan( path, ".dm2.gz" );
	Demos_Scan( path, ".dm_35" );
	Demos_Scan( path, ".dm_35.gz" );
	Demos_Scan( path, ".dm_36" );
	Demos_Scan( path, ".dm_36.gz" );
	Demos_Scan( path, ".mvd2" );
	Demos_Scan( path, ".mvd2.gz" );

	// Sort demos, not directories
	if( m_demos.count - pos > 1 ) {
		qsort( m_demos.names + pos, m_demos.count - pos, sizeof( m_demos.names[0] ), SortStrcmp );
	}

	m_demos.names[m_demos.count] = NULL;
}

static void Demos_Free( void ) {
	int i;

	Demos_FreeInfo();

	for( i = 0; i < m_demos.count; i++ ) {
		com.Free( m_demos.names[i] );
		m_demos.names[i] = NULL;
		m_demos.types[i] = 0;
	}

	m_demos.count = 0;
	m_demos.list.curvalue = 0;
}

static void Demos_LeaveDirectory( void ) {
	char buffer[MAX_QPATH];
	char *s;
	int i;

	s = strrchr( m_demos_browse, '/' );
	if( s ) {
		*s = 0;
		strcpy( buffer, s + 1 );
	} else {
		buffer[0] = 0;
	}

	// rebuild list
	Demos_Free();
	Demos_BuildList( m_demos_browse );
	MenuList_Init( &m_demos.list );

	if( s == m_demos_browse ) {
		m_demos_browse[0] = '/';
		m_demos_browse[1] = 0;
	}

	// move cursor to the previous directory
	if( buffer[0] ) {
		for( i = 0; i < m_demos.count; i++ ) {
			if( !strcmp( m_demos.names[i], buffer ) ) {
				MenuList_SetValue( &m_demos.list, i );
				return;
			}
		}
	}

	MenuList_SetValue( &m_demos.list, 0 );

}

static int Demos_Action( void ) {
	char buffer[MAX_QPATH];
	int length, baseLength;
    char *c;

	switch( m_demos.types[m_demos.list.curvalue] ) {
	case FFILE_UP:
		Demos_LeaveDirectory();
		return QMS_OUT;

	case FFILE_FOLDER:
		baseLength = strlen( m_demos_browse );
		length = strlen( m_demos.names[m_demos.list.curvalue] );
		if( baseLength + length > sizeof( m_demos_browse ) - 2 ) {
			return QMS_BEEP;
		}
		if( m_demos_browse[ baseLength - 1 ] != '/' ) {
			m_demos_browse[ baseLength++ ] = '/';
		}

		strcpy( m_demos_browse + baseLength, m_demos.names[m_demos.list.curvalue] );
		
		// rebuild list
		Demos_Free();
		Demos_BuildList( m_demos_browse );
		MenuList_Init( &m_demos.list );
		return QMS_IN;

	case FFILE_DEMO:
	    if( !m_demos.demo.mapname[0] ) {
            return QMS_BEEP;
        }
        c = m_demos.demo.mvd || keys.IsDown( K_SHIFT ) ? "mvdplay" : "demo";
		Com_sprintf( buffer, sizeof( buffer ), "%s \"%s/%s\"\n", c,
			m_demos_browse, m_demos.names[m_demos.list.curvalue] );
		cmd.ExecuteText( EXEC_APPEND, buffer );
		//UI_ForceMenuOff();
		return QMS_SILENT;
	}

	return QMS_NOTHANDLED;
}

static int Demos_MenuCallback( int id, int msg, int param ) {
	switch( msg ) {
	case QM_ACTIVATE:
		switch( id ) {
		case ID_LIST:
			return Demos_Action();
		}
		return QMS_IN;

	case QM_CHANGE:
		switch( id ) {
		case ID_LIST:
			Demos_LoadInfo( m_demos.list.curvalue );
			break;
		default:
			break;
		}
		return QMS_MOVE;

	case QM_KEY:
		switch( id ) {
		case ID_LIST:
			switch( param ) {
			case K_BACKSPACE:
				Demos_LeaveDirectory();
				return QMS_OUT;
			default:
				break;
			}
		default:
			break;
		}
		break;

	case QM_DESTROY:
		m_demos_selection = m_demos.list.curvalue; // save previous position
		Demos_Free();
		break;

	default:
		break;
	}

	return QMS_NOTHANDLED;
}

static void Demos_MenuInit( void ) {
	int w1, w2;

	memset( &m_demos, 0, sizeof( m_demos ) );

	m_demos.menu.callback = Demos_MenuCallback;

	// Point to a nice location at startup
	if( !m_demos_browse[0] ) {
		strcpy( m_demos_browse, "/demos" );
	}

	Demos_BuildList( m_demos_browse );

	w1 = ( uis.glconfig.vidWidth - 30 ) * 0.8f;
	w2 = ( uis.glconfig.vidWidth - 30 ) * 0.2f;

	m_demos.list.generic.type	= MTYPE_LIST;
	m_demos.list.generic.id		= ID_LIST;
	m_demos.list.generic.flags  = QMF_HASFOCUS;
	m_demos.list.generic.x		= 10;
	m_demos.list.generic.y		= 32;
	m_demos.list.generic.width	= 0;
	m_demos.list.generic.height	= uis.glconfig.vidHeight - 64;
	m_demos.list.generic.name	= NULL;
	m_demos.list.itemnames		= ( const char ** )m_demos.names;
	m_demos.list.drawNames		= qtrue;
	m_demos.list.numcolumns	= 3;

	m_demos.list.columns[0].width = w1 - 90;
	m_demos.list.columns[0].name = m_demos_browse;
	m_demos.list.columns[0].uiFlags = UI_LEFT;

	m_demos.list.columns[1].width = 40;
	m_demos.list.columns[1].name = "KB";
	m_demos.list.columns[1].uiFlags = UI_RIGHT;

	m_demos.list.columns[2].width = 50;
	m_demos.list.columns[2].name = "Type";
	m_demos.list.columns[2].uiFlags = UI_CENTER;

	m_demos.playerList.generic.type		= MTYPE_LIST;
	m_demos.playerList.generic.flags	= QMF_HIDDEN|QMF_DISABLED;
	m_demos.playerList.generic.x		= w1 + 20;
	m_demos.playerList.generic.y		= 32;
	m_demos.playerList.generic.height	= uis.glconfig.vidHeight - 64;
	m_demos.playerList.itemnames		= ( const char ** )m_demos.playerNames;
	m_demos.playerList.mlFlags			= MLF_HIDE_SCROLLBAR_EMPTY;
	m_demos.playerList.numcolumns		= 1;
	m_demos.playerList.drawNames		= qtrue;

	m_demos.playerList.columns[0].width = w2;
	m_demos.playerList.columns[0].name = "Players";
	m_demos.playerList.columns[0].uiFlags = UI_CENTER;

	UI_SetupDefaultBanner( &m_demos.banner, "Demos" );

	Menu_AddItem( &m_demos.menu, (void *)&m_demos.list );
	Menu_AddItem( &m_demos.menu, (void *)&m_demos.playerList );
	Menu_AddItem( &m_demos.menu, (void *)&m_demos.banner );

	// move cursor to previous position
	MenuList_SetValue( &m_demos.list, m_demos_selection );
}

void M_Menu_Demos_f( void ) {
	Demos_MenuInit();
	UI_PushMenu( &m_demos.menu );
}
