/*****************************************************************************

        GRAOUMF TRACKER 2
        Author: Laurent de Soras, 1996-2016

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*****************************************************************************/



/*\\\ FICHIERS INCLUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include	"archi.h"
#include	"base.h"
#include	"base_ct.h"
#include	"FileSelector.h"
#include	"file.h"
#include	"fnames.h"
#include	"intrface.h"
#include	"log.h"
#include	"mpannel.h"
#include	"modstruc.h"
#include	"PatEdMenuFilesMain.h"
#include	"Popup.h"
#include	"resource.h"
#include	"rsc01.h"
#include	"String.h"

#include <algorithm>

#include <cassert>
#include	<cstdio>
#include	<cstring>


/*\\\ CONSTANTES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ CONSTANTES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

/* Types de chemins */
enum
{
	PatEdMenuFilesMain_PATH_SYSTEM = 0,
	PatEdMenuFilesMain_PATH_MODULE,
	PatEdMenuFilesMain_PATH_PREFS,
	PatEdMenuFilesMain_PATH_SAMPLE,
	PatEdMenuFilesMain_PATH_INSTR,
	PatEdMenuFilesMain_PATH_AUTOMOD,
	PatEdMenuFilesMain_PATH_AUTOSPL,
	PatEdMenuFilesMain_PATH_MISC,

	PatEdMenuFilesMain_NBR_PATHS
};



/*\\\ TYPES & STRUCTURES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ DEFINITION DES VARIABLES DE CLASSE PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ DEFINITION DES VARIABLES DE CLASSE PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ METHODES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: (constructeur)                                                 */
/*      Description: Initialise                                             */
/*==========================================================================*/

PatEdMenuFilesMain::PatEdMenuFilesMain (void)
{
	_disk_path_type = PatEdMenuFilesMain_PATH_SYSTEM;
}



/*==========================================================================*/
/*      Nom: check_ok                                                       */
/*      Description: Verifie l'intergrite de l'objet.                       */
/*      Retour: 0 si l'objet parait correct.                                */
/*==========================================================================*/

signed int	PatEdMenuFilesMain::check_ok (void) const
{
	if (this == NULL)
	{
		LOG_printf ("PatEdMenuFilesMain::check_ok: Error: \"this\" pointer is NULL.\n");
		return (-1);
	}

	/*** A faire ***/

	return (0);
}



/*==========================================================================*/
/*      Nom: self_display                                                   */
/*      Description: Affiche "textuellement" le contenu courant de l'objet. */
/*==========================================================================*/

void	PatEdMenuFilesMain::self_display (void) const
{

	/*** A faire ***/

}



/*==========================================================================*/
/*      Nom: redraw                                                         */
/*      Description: Affiche la composante d'interface.                     */
/*==========================================================================*/

void	PatEdMenuFilesMain::redraw (void)
{
	RSC_display_object (RSC_OBJ_MP_SUBM);

	refresh ();
}



/*==========================================================================*/
/*      Nom: refresh                                                        */
/*      Description: Rafraichit l'affichage des donnees.                    */
/*==========================================================================*/

void	PatEdMenuFilesMain::refresh (void)
{
/*______________________________________________
 *
 * Chemin choisi
 *______________________________________________
 */

	switch (_disk_path_type)
	{
	case	PatEdMenuFilesMain_PATH_SYSTEM:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME, FILE_program_pathname.c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "System");
		break;

	case	PatEdMenuFilesMain_PATH_MODULE:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME, FILE_module_filename.c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "Module");
		break;

	case	PatEdMenuFilesMain_PATH_PREFS:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME, FILE_prefs_filename.c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "Preferences");
		break;

	case	PatEdMenuFilesMain_PATH_SAMPLE:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME, FILE_sample_filename.c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "Sample");
		break;

	case	PatEdMenuFilesMain_PATH_INSTR:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME, FILE_instrument_filename.c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "Instrument");
		break;

	case	PatEdMenuFilesMain_PATH_AUTOMOD:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME, FILE_auto_module_filename.c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "Autoload (mod)");
		break;

	case	PatEdMenuFilesMain_PATH_AUTOSPL:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME,
		                (FILE_auto_sample_pathname + FILE_auto_sample_maskname).c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "Autoload (spl)");
		break;

	case	PatEdMenuFilesMain_PATH_MISC:
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME, FILE_misc_filename.c_str ());
		RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE, "Miscellaneous");
		break;
	}

	RSC_display_object (RSC_OBJ_MP_SUBM_DISK_MAIN_PATH_NAME);
	RSC_display_object (RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE_TYPE);

/*______________________________________________
 *
 * Extension du module
 *______________________________________________
 */

	RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_EXPORTF_FORMAT,
	                MODS_format_routines [MODS_export_format].name_0);	/*** A voir ***/
	RSC_display_object (RSC_OBJ_MP_SUBM_DISK_MAIN_EXPORTF_FORMAT);

	refresh_dynamic (true);

/*______________________________________________
 *
 * MRU
 *______________________________________________
 */

	const std::vector <std::string>  mru_arr = MODS_get_mru_file_list ();
	RSC_set_string (RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES_LINE, "");
	const int      nbr_disp_lines_max =
		RSC_get_height (RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES) / RSC_CHAR_H;
	const int      nbr_disp_lines     =
		std::min (int (mru_arr.size ()), nbr_disp_lines_max);
	const int      line_maxlen        =
		RSC_get_width (RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES) / RSC_CHAR_W;
	for (int line_cnt = 0; line_cnt < nbr_disp_lines; ++line_cnt)
	{
		RSC_set_relative_object_position (
			RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES_LINE,
			0,
			line_cnt * RSC_CHAR_H
		);
		std::string    content = mru_arr [line_cnt];
		if (content.length () > size_t (line_maxlen))
		{
			// Careful. We should not broke UTF-8 sequences.
			int            pos1 = line_maxlen / 2 - 1;
			while (! BASE_is_utf8_lead_byte (content [pos1]))
			{
				++ pos1;
			}
			int            pos2 =
				content.length () - line_maxlen + pos1 + 3;
			assert (pos2 < int (content.length ()));
			while (! BASE_is_utf8_lead_byte (content [pos2]))
			{
				++ pos2;
			}
			content =
				  content.substr (0, pos1)
				+ "..."
				+ content.substr (pos2, line_maxlen - pos1);
		}
		RSC_set_string (
			RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES_LINE,
			content.c_str ()
		);
		RSC_display_object (RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES_LINE);
	}
}



/*==========================================================================*/
/*      Nom: refresh_dynamic                                                */
/*      Description: Rafraichit l'affichage des donnees dynamiques.         */
/*        - force_flag: true indique qu'on doit forcer le rafraichissement. */
/*==========================================================================*/

void	PatEdMenuFilesMain::refresh_dynamic (bool force_flag)
{
	/* Rien en fait */
}



/*==========================================================================*/
/*      Nom: manage                                                         */
/*      Description: Gere la composante d'interface                         */
/*      Parametres en entree:                                               */
/*        - sel_object: objet detecte par le gestionnaire d'interface       */
/*        - sel_elder: aine de sel_object                                   */
/*==========================================================================*/

void	PatEdMenuFilesMain::manage (int sel_object, int sel_elder)
{
	SLWORD	ret_code;
	signed int	line;
	int		exit_button;
	String	path;
	String	filename;
	String	mask;
	Popup		popup_menu;
	FileSelector	*file_selector_ptr;
	char		text_0 [255+1];
	int		format_cnt;

	switch (sel_object)
	{

	/* Load module */
	case	RSC_OBJ_MP_SUBM_DISK_MAIN_LMOD:
		MODS_load_module (false, NULL);
		MPAN_display_main_pannel ();
		break;

	/* Save module */
	case	RSC_OBJ_MP_SUBM_DISK_MAIN_SMOD:
		MODS_save_module (false);
		refresh ();
		break;

	/* Load song */
	case	RSC_OBJ_MP_SUBM_DISK_MAIN_LSONG:
		MODS_load_module (true, NULL);
		MPAN_display_main_pannel ();
		break;

	/* Save song */
	case	RSC_OBJ_MP_SUBM_DISK_MAIN_SSONG:
		MODS_save_module (true);
		refresh ();
		break;

	/* Export format */
	case	RSC_OBJ_MP_SUBM_DISK_MAIN_EXPORTF:
		format_cnt = 0;
		while (MODS_format_routines [format_cnt].name_0 != NULL)
		{
			if (   MODS_format_routines [format_cnt].save_module_flag
			    || MODS_format_routines [format_cnt].save_song_flag)
			{
				strcpy (text_0, MODS_format_routines [format_cnt].name_0);
				strcat (text_0, " (");
				strcat (text_0, MODS_format_routines [format_cnt].ext_0);
				strcat (text_0, ")");
				popup_menu.add_line (text_0, format_cnt);
			}
			format_cnt ++;
		}
		line = popup_menu.select_radio_by_code (MODS_export_format);
		ret_code = popup_menu.manage (line);
		if (ret_code >= 0)
		{
			MODS_export_format = ret_code;
			refresh ();
		}
		break;

	/* Path type */
	case	RSC_OBJ_MP_SUBM_DISK_MAIN_PTYPE:
		popup_menu.add_line ("System", PatEdMenuFilesMain_PATH_SYSTEM);
		popup_menu.add_line ("Module", PatEdMenuFilesMain_PATH_MODULE);
		popup_menu.add_line ("Preferences", PatEdMenuFilesMain_PATH_PREFS);
		popup_menu.add_line ("Sample", PatEdMenuFilesMain_PATH_SAMPLE);
		popup_menu.add_line ("Instrument", PatEdMenuFilesMain_PATH_INSTR);
		popup_menu.add_line ("Autoload (mod)", PatEdMenuFilesMain_PATH_AUTOMOD);
		popup_menu.add_line ("Autoload (spl)", PatEdMenuFilesMain_PATH_AUTOSPL);
		popup_menu.add_line ("Miscellaneous", PatEdMenuFilesMain_PATH_MISC);
		line = popup_menu.select_radio_by_code (_disk_path_type);
		ret_code = popup_menu.manage (line);
		if (ret_code >= 0)
		{
			_disk_path_type = (int) ret_code;
			refresh ();
		}
		break;

	/* Path */
	case	RSC_OBJ_MP_SUBM_DISK_MAIN_PATH:
		switch (_disk_path_type)
		{

		case	PatEdMenuFilesMain_PATH_SYSTEM:
			path = FNAM_get_full_path (FILE_program_pathname) + "*.*";
			filename = "";
			break;

		case	PatEdMenuFilesMain_PATH_MODULE:
			path = FNAM_get_full_path (FILE_module_filename) + FILE_module_maskname;
			filename = FNAM_get_full_filename (FILE_module_filename);
			break;

		case	PatEdMenuFilesMain_PATH_PREFS:
			path = FNAM_get_full_path (FILE_prefs_filename) + FILE_prefs_maskname;
			filename = FNAM_get_full_filename (FILE_prefs_filename);
			break;

		case	PatEdMenuFilesMain_PATH_SAMPLE:
			path = FNAM_get_full_path (FILE_sample_filename) + FILE_sample_maskname;
			filename = FNAM_get_full_filename (FILE_sample_filename);
			break;

		case	PatEdMenuFilesMain_PATH_INSTR:
			path = FNAM_get_full_path (FILE_instrument_filename) + FILE_instrument_maskname;
			filename = FNAM_get_full_filename (FILE_instrument_filename);
			break;

		case	PatEdMenuFilesMain_PATH_AUTOMOD:
			path = FNAM_get_full_path (FILE_auto_module_filename) + "*.*";
			filename = FNAM_get_full_filename (FILE_auto_module_filename);
			break;

		case	PatEdMenuFilesMain_PATH_AUTOSPL:
			path = FNAM_get_full_path (FILE_auto_sample_pathname) + FILE_auto_sample_maskname;
			filename = "";
			break;

		case	PatEdMenuFilesMain_PATH_MISC:
			path = FNAM_get_full_path (FILE_misc_filename) + "*.*";
			filename = FNAM_get_full_filename (FILE_misc_filename);
			break;
		}

		file_selector_ptr = new FileSelector (path.c_str (), filename.c_str (), "Select path:", "All files\n*.*\n");
		if (file_selector_ptr == NULL)
		{
			LOG_printf ("Error: couldn't create file selector object.\n");
			break;
		}

		do
		{
			exit_button = file_selector_ptr->manage ();
		}
		while (exit_button == FileSelector::BUTTON_NONE);

		path = file_selector_ptr->get_pathname ();
		mask = file_selector_ptr->get_mask ();
		filename = file_selector_ptr->get_filename ();
		if (exit_button == FileSelector::BUTTON_OK)
		{
			switch (_disk_path_type)
			{

			case	PatEdMenuFilesMain_PATH_SYSTEM:
				FILE_program_pathname = path;
				break;

			case	PatEdMenuFilesMain_PATH_MODULE:
				FILE_module_filename = path + filename;
				FILE_module_maskname = mask;
				break;

			case	PatEdMenuFilesMain_PATH_PREFS:
				FILE_prefs_filename = path + filename;
				FILE_prefs_maskname = mask;
				break;

			case	PatEdMenuFilesMain_PATH_SAMPLE:
				FILE_sample_filename = path + filename;
				FILE_sample_maskname = mask;
				break;

			case	PatEdMenuFilesMain_PATH_INSTR:
				FILE_instrument_filename = path + filename;
				FILE_instrument_maskname = mask;
				break;

			case	PatEdMenuFilesMain_PATH_AUTOMOD:
				FILE_auto_module_filename = path + filename;
				break;

			case	PatEdMenuFilesMain_PATH_AUTOSPL:
				FILE_auto_sample_pathname = path;
				FILE_auto_sample_maskname = mask;
				break;

			case	PatEdMenuFilesMain_PATH_MISC:
				FILE_misc_filename = path + filename;
				break;
			}
		}
		delete file_selector_ptr;

		refresh ();
		break;

	// MRU
	case RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES:
		{
			const int      clicked_line =
				  (  INTR_mouse.y
				   - RSC_absolute_object_pixypos [RSC_OBJ_MP_SUBM_DISK_MAIN_MRU_FILES])
				/ RSC_CHAR_H;
			const std::vector <std::string>  mru_arr = MODS_get_mru_file_list ();
			if (clicked_line >= 0 && clicked_line < int (mru_arr.size ()))
			{
				const std::string &  path = mru_arr [clicked_line];
				if (! FILE_file_exist (path.c_str ()))
				{
					INTR_dialog_box (
						"LOAD MODULE",
						(path + "\ndoesn't exist.").c_str (),
						"Cancel",
						0,
						0
					);
					MODS_remove_from_mru_file_list (clicked_line);
				}
				else
				{
					MODS_load_module (false, path.c_str ());
				}
				refresh ();
				MPAN_display_main_pannel ();
			}
		}
		break;
	}
}



/*==========================================================================*/
/*      Nom: activate                                                       */
/*      Description: Active ou desactive le menu. Celui-ci n'est pas        */
/*                   reaffiche.                                             */
/*      Parametres en entree:                                               */
/*        - activated_flag: indique si le menu doit etre active ou          */
/*                          desactive.                                      */
/*==========================================================================*/

void	PatEdMenuFilesMain::activate (bool activated_flag)
{
	RSC_pos_flag (RSC_OBJ_MP_SUBM_DISK_MAIN, RSC_ATTR_NOTDISP, ! activated_flag);
	RSC_pos_flag (RSC_OBJ_MP_SUBM_DISK_PICN_MAIN, RSC_ATTR_SELECTED, activated_flag);
}



/*\\\ METHODES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/****************************************************************************/
/*                                                                          */
/*                                                                          */
/*                                                                          */
/****************************************************************************/



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/
