/*
   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
   For a list of contributors, see the accompanying CONTRIBUTORS file.

   This file is part of GtkRadiant.

   GtkRadiant 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.

   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "mru.h"

#include <string.h>
#include <stdio.h>
#include <gtk/gtk.h>

#include "os/file.h"
#include "generic/callback.h"
#include "convert.h"

#include "gtkutil/menu.h"
#include "map.h"
#include "qe3.h"

#define MRU_MAX 9
namespace {
GtkMenuItem *MRU_items[MRU_MAX];
std::size_t MRU_used;
typedef CopiedString MRU_filename_t;
MRU_filename_t MRU_filenames[MRU_MAX];
typedef const char* MRU_key_t;
MRU_key_t MRU_keys[MRU_MAX] = { "File0", "File1", "File2", "File3", "File4", "File5", "File6", "File7", "File8" };
}

inline const char* MRU_GetText( std::size_t index ){
	return MRU_filenames[index].c_str();
}

class EscapedMnemonic
{
private:
	std::string m_buffer;

public:
	EscapedMnemonic() : m_buffer(){
	m_buffer.push_back( '_' );
}
const char* c_str() const {
	return m_buffer.c_str();
}
void push_back( char c ){ // not escaped
	m_buffer.push_back( c );
}
std::size_t write( const char* buffer, std::size_t length ){
	for ( const char* end = buffer + length; buffer != end; ++buffer )
	{
		if ( *buffer == '_' ) {
			m_buffer.push_back( '_' );
		}

		m_buffer.push_back( *buffer );
	}
	return length;
}
};

template<typename T>
inline EscapedMnemonic& operator<<( EscapedMnemonic& ostream, const T& t ){
	return ostream_write( ostream, t );
}


void MRU_updateWidget( std::size_t index, const char *filename ){
	EscapedMnemonic mnemonic;
	mnemonic << Unsigned( index + 1 ) << "- " << filename;
	gtk_label_set_text_with_mnemonic( GTK_LABEL( gtk_bin_get_child( GTK_BIN( MRU_items[index] ) ) ), mnemonic.c_str() );
}

void MRU_SetText( std::size_t index, const char *filename ){
	MRU_filenames[index] = filename;
	MRU_updateWidget( index, filename );
}

void MRU_AddFile( const char *str ){
	std::size_t i;
	const char* text;

	// check if file is already in our list
	for ( i = 0; i < MRU_used; i++ )
	{
		text = MRU_GetText( i );

		if ( strcmp( text, str ) == 0 ) {
			// reorder menu
			for (; i > 0; i-- )
				MRU_SetText( i, MRU_GetText( i - 1 ) );

			MRU_SetText( 0, str );

			return;
		}
	}

	if ( MRU_used < MRU_MAX ) {
		MRU_used++;
	}

	// move items down
	for ( i = MRU_used - 1; i > 0; i-- )
		MRU_SetText( i, MRU_GetText( i - 1 ) );

	MRU_SetText( 0, str );
	gtk_widget_set_sensitive( ui::MenuItem::from(MRU_items[0]) , TRUE );
	ui::MenuItem::from(MRU_items[MRU_used - 1] ).show();
}

void MRU_Init(){
	if ( MRU_used > MRU_MAX ) {
		MRU_used = MRU_MAX;
	}
}

void MRU_AddWidget( ui::MenuItem widget, std::size_t pos ){
	if ( pos < MRU_MAX ) {
		MRU_items[pos] = widget;
		if ( pos < MRU_used ) {
			MRU_updateWidget( pos, MRU_GetText( pos ) );
			gtk_widget_set_sensitive( ui::MenuItem::from(MRU_items[0]) , TRUE );
			ui::MenuItem::from(MRU_items[pos]).show();
		}
	}
}

void MRU_Activate( std::size_t index ){
	char text[1024];
	strcpy( text, MRU_GetText( index ) );

	if ( file_readable( text ) ) { //\todo Test 'map load succeeds' instead of 'file is readable'.
		MRU_AddFile( text );
		Map_RegionOff();
		Map_Free();
		Map_LoadFile( text );
	}
	else
	{
		MRU_used--;

		for ( std::size_t i = index; i < MRU_used; i++ )
			MRU_SetText( i, MRU_GetText( i + 1 ) );

		if ( MRU_used == 0 ) {
			auto label = ui::Label::from(gtk_bin_get_child(GTK_BIN(MRU_items[0] )) );
			label.text("Recent Files");
			gtk_widget_set_sensitive( ui::MenuItem::from(MRU_items[0]), FALSE );
		}
		else
		{
			ui::MenuItem::from(MRU_items[MRU_used]).hide();
		}
	}
}


class LoadMRU
{
private:
std::size_t m_number;

public:
LoadMRU( std::size_t number )
	: m_number( number ){
}
void load(){
	if ( ConfirmModified( "Open Map" ) ) {
		MRU_Activate( m_number - 1 );
	}
}
};

typedef MemberCaller<LoadMRU, void(), &LoadMRU::load> LoadMRUCaller;

LoadMRU g_load_mru1( 1 );
LoadMRU g_load_mru2( 2 );
LoadMRU g_load_mru3( 3 );
LoadMRU g_load_mru4( 4 );
LoadMRU g_load_mru5( 5 );
LoadMRU g_load_mru6( 6 );
LoadMRU g_load_mru7( 7 );
LoadMRU g_load_mru8( 8 );
LoadMRU g_load_mru9( 9 );

void MRU_constructMenu( ui::Menu menu ){
	{
		auto item = create_menu_item_with_mnemonic( menu, "_1", LoadMRUCaller( g_load_mru1 ) );
		gtk_widget_set_sensitive( item , FALSE );
		MRU_AddWidget( item, 0 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_2", LoadMRUCaller( g_load_mru2 ) );
		item.hide();
		MRU_AddWidget( item, 1 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_3", LoadMRUCaller( g_load_mru3 ) );
		item.hide();
		MRU_AddWidget( item, 2 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_4", LoadMRUCaller( g_load_mru4 ) );
		item.hide();
		MRU_AddWidget( item, 3 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_5", LoadMRUCaller( g_load_mru5 ) );
		item.hide();
		MRU_AddWidget( item, 4 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_6", LoadMRUCaller( g_load_mru6 ) );
		item.hide();
		MRU_AddWidget( item, 5 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_7", LoadMRUCaller( g_load_mru7 ) );
		item.hide();
		MRU_AddWidget( item, 6 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_8", LoadMRUCaller( g_load_mru8 ) );
		item.hide();
		MRU_AddWidget( item, 7 );
	}
	{
		auto item = create_menu_item_with_mnemonic( menu, "_9", LoadMRUCaller( g_load_mru9 ) );
		item.hide();
		MRU_AddWidget( item, 8 );
	}
}

#include "preferencesystem.h"
#include "stringio.h"

void MRU_Construct(){
	GlobalPreferenceSystem().registerPreference( "Count", make_property_string( MRU_used ) );

	for ( std::size_t i = 0; i != MRU_MAX; ++i )
	{
		GlobalPreferenceSystem().registerPreference( MRU_keys[i], make_property_string( MRU_filenames[i] ) );
	}

	MRU_Init();
}
void MRU_Destroy(){
}
