// Emacs style mode select   -*- C++ -*- 
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//
// $Log:$
//
// DESCRIPTION:
//	Main loop menu stuff.
//	Default Config File.
//	PCX Screenshots.
//
//-----------------------------------------------------------------------------

static const char
rcsid[] = "$Id: m_misc.c,v 1.6 1997/02/03 22:45:10 b1 Exp $";

#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <io.h>
//#include <unistd.h>
#include <direct.h>

#include <ctype.h>


#include "doomdef.h"

#include "z_zone.h"

#include "m_swap.h"
#include "m_argv.h"

#include "w_wad.h"

#include "i_system.h"
#include "i_video.h"
#include "v_video.h"

#include "hu_stuff.h"

// State.
#include "doomstat.h"

// Data.
#include "dstrings.h"

#include "m_misc.h"

//
// M_DrawText
// Returns the final X coordinate
// HU_Init must have been called to init the font
//
extern patch_t*		hu_font[HU_FONTSIZE];

int
M_DrawText
( int		x,
  int		y,
  boolean	direct,
  char*		string )
{
    int 	c;
    int		w;

    while (*string)
    {
	c = toupper(*string) - HU_FONTSTART;
	string++;
	if (c < 0 || c> HU_FONTSIZE)
	{
	    x += 4;
	    continue;
	}
		
	w = SHORT (hu_font[c]->width);
	if (x+w > SCREENWIDTH)
	    break;
	if (direct)
	    V_DrawPatch(x, y, 0, hu_font[c]);
	else
	    V_DrawPatch(x, y, 0, hu_font[c]);
	x+=w;
    }

    return x;
}



//
// M_GetFileSize
//
#ifndef O_BINARY
#define O_BINARY 0
#endif

int M_GetFileSize( char const*	name )
   {
    int		handle;
    int		count;
	
    handle = open ( name, O_RDWR | O_BINARY);

    if (handle == -1)
        return 0;

    count = lseek(handle, 0, SEEK_END);
    close (handle);
	
    return count;
   }

//
// M_WriteFile
//
boolean M_WriteFile(char const*	name,void* source,int length)
{
    int		handle;
    int		count;
	
    handle = open( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);

    if (handle == -1)
	return false;

    count = write (handle, source, length);
    close (handle);
	
    if (count < length)
	return false;
		
    return true;
}

//
// M_AppendFile
//
boolean M_AppendFile(char const *name, void *source, int length )
   {
    int		handle;
    int		count;
	
    handle = open( name, O_RDWR | O_BINARY);

    if (handle == -1)
        return false;

    lseek(handle, 0L, SEEK_END);

    count = write (handle, source, length);
    close (handle);
	
    if (count < length)
        return false;
		
    return true;
   }


//
// M_ReadFile
//
int
M_ReadFile
( char const*	name,
  byte**	buffer )
{
    int	handle, count, length;
    struct stat	fileinfo;
    byte		*buf;
	
    handle = open (name, O_RDONLY | O_BINARY, 0666);
    if (handle == -1)
	I_Error ("Couldn't read file %s", name);
    if (fstat (handle,&fileinfo) == -1)
	I_Error ("Couldn't read file %s", name);
    length = fileinfo.st_size;
    buf = Z_Malloc (length, PU_STATIC, NULL);
    count = read (handle, buf, length);
    close (handle);
	
    if (count < length)
	I_Error ("Couldn't read file %s", name);
		
    *buffer = buf;
    return length;
}


//
// DEFAULTS
//
int		usemouse;
int		usejoystick;

extern int	key_right;
extern int	key_left;
extern int	key_up;
extern int	key_down;

extern int	key_strafeleft;
extern int	key_straferight;

extern int	key_fire;
extern int	key_use;
extern int	key_strafe;
extern int	key_speed;

extern int  key_mvert;

extern int  always_run;
extern int  swap_stereo;
extern int  mvert;
extern int  keylink;

extern int	mousebfire;
extern int	mousebstrafe;
extern int	mousebforward;

extern int	mouseb1;
extern int	mouseb2;
extern int	mouseb3;

extern int	joybfire;
extern int	joybstrafe;
extern int	joybuse;
extern int	joybspeed;

extern int  joyb1;
extern int  joyb2;
extern int  joyb3;
extern int  joyb4;

extern int	viewwidth;
extern int	viewheight;

extern int	mouseSensitivity;
extern int	showMessages;

extern int	detailLevel;

extern int	screenblocks;

extern int	showMessages;

// machine-independent sound params
extern	int	numChannels;


// UNIX hack, to be removed.
#ifdef SNDSERV
extern char*	sndserver_filename;
extern int	mb_used;
#endif

#ifdef LINUX
char*		mousetype;
char*		mousedev;
#endif

extern char*	chat_macros[];



typedef struct
{
    char*	name;
    int*	location;
    int		defaultvalue;
    int		scantranslate;		// PC scan code hack
    int		untranslated;		// lousy hack
} default_t;

default_t	defaults[] =
{
    {"mouse_sensitivity",&mouseSensitivity, 5},
    {"sfx_volume",&snd_SfxVolume, 8},
    {"music_volume",&snd_MusicVolume, 8},
    {"show_messages",&showMessages, 1},
    

#ifdef NORMALUNIX
    {"key_right",&key_right, KEY_RIGHTARROW},
    {"key_left",&key_left, KEY_LEFTARROW},
    {"key_up",&key_up, KEY_UPARROW},
    {"key_down",&key_down, KEY_DOWNARROW},
    {"key_strafeleft",&key_strafeleft, ','},
    {"key_straferight",&key_straferight, '.'},

    {"key_fire",&key_fire, KEY_RCTRL},
    {"key_use",&key_use, ' '},
    {"key_strafe",&key_strafe, KEY_RALT},
    {"key_speed",&key_speed, KEY_RSHIFT},

// UNIX hack, to be removed. 
#ifdef SNDSERV
    {"sndserver", (int *) &sndserver_filename, (int) "sndserver"},
    {"mb_used", &mb_used, 2},
#endif
    
#endif

#ifdef LINUX
    {"mousedev", (int*)&mousedev, (int)"/dev/ttyS0"},
    {"mousetype", (int*)&mousetype, (int)"microsoft"},
#endif

    {"use_mouse",&usemouse, 1},
    {"mouseb_fire",&mousebfire,0},
    {"mouseb_strafe",&mousebstrafe,1},
    {"mouseb_forward",&mousebforward,2},

    {"use_joystick",&usejoystick, 0},
    {"joyb_fire",&joybfire,0},
    {"joyb_strafe",&joybstrafe,1},
    {"joyb_use",&joybuse,3},
    {"joyb_speed",&joybspeed,2},

    {"screenblocks",&screenblocks, 9},
    {"detaillevel",&detailLevel, 0},

    {"snd_channels",&numChannels, 3},



    {"usegamma",&usegamma, 0},

    {"chatmacro0", (int *) &chat_macros[0], (int) HUSTR_CHATMACRO0 },
    {"chatmacro1", (int *) &chat_macros[1], (int) HUSTR_CHATMACRO1 },
    {"chatmacro2", (int *) &chat_macros[2], (int) HUSTR_CHATMACRO2 },
    {"chatmacro3", (int *) &chat_macros[3], (int) HUSTR_CHATMACRO3 },
    {"chatmacro4", (int *) &chat_macros[4], (int) HUSTR_CHATMACRO4 },
    {"chatmacro5", (int *) &chat_macros[5], (int) HUSTR_CHATMACRO5 },
    {"chatmacro6", (int *) &chat_macros[6], (int) HUSTR_CHATMACRO6 },
    {"chatmacro7", (int *) &chat_macros[7], (int) HUSTR_CHATMACRO7 },
    {"chatmacro8", (int *) &chat_macros[8], (int) HUSTR_CHATMACRO8 },
    {"chatmacro9", (int *) &chat_macros[9], (int) HUSTR_CHATMACRO9 }

};

int	numdefaults;
char*	defaultfile;

char DoomDir[128], szValue[32];
void GetININame(void);

//
// M_SaveDefaults
//
void M_SaveDefaults (void)
{
/*
    int		i;
    int		v;
    FILE*	f;
*/
	
    GetININame();
    sprintf(szValue, "%d", mouseSensitivity);
    WritePrivateProfileString("DEFAULTS", "mouse_sensitivity", szValue, DoomDir);
    sprintf(szValue, "%d", snd_SfxVolume);
    WritePrivateProfileString("DEFAULTS", "sfx_volume", szValue, DoomDir);
    sprintf(szValue, "%d", snd_MusicVolume);
    WritePrivateProfileString("DEFAULTS", "music_volume", szValue, DoomDir);
    sprintf(szValue, "%d", showMessages);
    WritePrivateProfileString("DEFAULTS", "show_messages", szValue, DoomDir);

    sprintf(szValue, "%d", key_right);
    WritePrivateProfileString("DEFAULTS", "key_right", szValue, DoomDir);
    sprintf(szValue, "%d", key_left);
    WritePrivateProfileString("DEFAULTS", "key_left", szValue, DoomDir);
    sprintf(szValue, "%d", key_up);
    WritePrivateProfileString("DEFAULTS", "key_up", szValue, DoomDir);
    sprintf(szValue, "%d", key_down);
    WritePrivateProfileString("DEFAULTS", "key_down", szValue, DoomDir);

    sprintf(szValue, "%d", key_mvert);
    WritePrivateProfileString("DEFAULTS", "key_mvert", szValue, DoomDir);

    sprintf(szValue, "%d", key_strafeleft);
    WritePrivateProfileString("DEFAULTS", "key_strafeleft", szValue, DoomDir);
    sprintf(szValue, "%d", key_straferight);
    WritePrivateProfileString("DEFAULTS", "key_straferight", szValue, DoomDir);

    sprintf(szValue, "%d", key_fire);
    WritePrivateProfileString("DEFAULTS", "key_fire", szValue, DoomDir);
    sprintf(szValue, "%d", key_use);
    WritePrivateProfileString("DEFAULTS", "key_use", szValue, DoomDir);
    sprintf(szValue, "%d", key_strafe);
    WritePrivateProfileString("DEFAULTS", "key_strafe", szValue, DoomDir);
    sprintf(szValue, "%d", key_speed);
    WritePrivateProfileString("DEFAULTS", "key_speed", szValue, DoomDir);

    sprintf(szValue, "%d", always_run);
    WritePrivateProfileString("DEFAULTS", "always_run", szValue, DoomDir);
    sprintf(szValue, "%d", swap_stereo);
    WritePrivateProfileString("DEFAULTS", "swap_stereo", szValue, DoomDir);
    sprintf(szValue, "%d", mvert);
    WritePrivateProfileString("DEFAULTS", "mvert", szValue, DoomDir);
    sprintf(szValue, "%d", keylink);
    WritePrivateProfileString("DEFAULTS", "keylink", szValue, DoomDir);


    sprintf(szValue, "%d", usemouse);
    WritePrivateProfileString("DEFAULTS", "use_mouse", szValue, DoomDir);
    sprintf(szValue, "%d", mousebfire);
    WritePrivateProfileString("DEFAULTS", "mouseb_fire", szValue, DoomDir);
    sprintf(szValue, "%d", mousebstrafe);
    WritePrivateProfileString("DEFAULTS", "mouseb_strafe", szValue, DoomDir);
    sprintf(szValue, "%d", mousebforward);
    WritePrivateProfileString("DEFAULTS", "mouseb_forward", szValue, DoomDir);

    sprintf(szValue, "%d", mouseb1);
    WritePrivateProfileString("DEFAULTS", "mouseb1", szValue, DoomDir);
    sprintf(szValue, "%d", mouseb2);
    WritePrivateProfileString("DEFAULTS", "mouseb2", szValue, DoomDir);
    sprintf(szValue, "%d", mouseb3);
    WritePrivateProfileString("DEFAULTS", "mouseb3", szValue, DoomDir);

    sprintf(szValue, "%d", usejoystick);
    WritePrivateProfileString("DEFAULTS", "use_joystick", szValue, DoomDir);
    sprintf(szValue, "%d", joybfire);
    WritePrivateProfileString("DEFAULTS", "joyb_fire", szValue, DoomDir);
    sprintf(szValue, "%d", joybstrafe);
    WritePrivateProfileString("DEFAULTS", "joyb_strafe", szValue, DoomDir);
    sprintf(szValue, "%d", joybuse);
    WritePrivateProfileString("DEFAULTS", "joyb_use", szValue, DoomDir);
    sprintf(szValue, "%d", joybspeed);
    WritePrivateProfileString("DEFAULTS", "joyb_speed", szValue, DoomDir);

    sprintf(szValue, "%d", joyb1);
    WritePrivateProfileString("DEFAULTS", "joyb1", szValue, DoomDir);
    sprintf(szValue, "%d", joyb2);
    WritePrivateProfileString("DEFAULTS", "joyb2", szValue, DoomDir);
    sprintf(szValue, "%d", joyb3);
    WritePrivateProfileString("DEFAULTS", "joyb3", szValue, DoomDir);
    sprintf(szValue, "%d", joyb4);
    WritePrivateProfileString("DEFAULTS", "joyb4", szValue, DoomDir);

    sprintf(szValue, "%d", screenblocks);
    WritePrivateProfileString("DEFAULTS", "screenblocks", szValue, DoomDir);
    sprintf(szValue, "%d", detailLevel);
    WritePrivateProfileString("DEFAULTS", "detaillevel", szValue, DoomDir);

    sprintf(szValue, "%d", usegamma);
    WritePrivateProfileString("DEFAULTS", "usegamma", szValue, DoomDir);

    sprintf(szValue, "%d", numChannels);
    WritePrivateProfileString("DEFAULTS", "snd_channels", szValue, DoomDir);
/*
    f = fopen (defaultfile, "w");
    if (!f)
	return; // can't write the file, but don't complain
		
    for (i=0 ; i<numdefaults ; i++)
    {
	if (defaults[i].defaultvalue > -0xfff
	    && defaults[i].defaultvalue < 0xfff)
	{
	    v = *defaults[i].location;
	    fprintf (f,"%s\t\t%i\n",defaults[i].name,v);
	} else {
	    fprintf (f,"%s\t\t\"%s\"\n",defaults[i].name,
		     * (char **) (defaults[i].location));
	}
    }
	
    fclose (f);
*/
   }


//
// M_LoadDefaults
//
extern byte	scantokey[128];

void WriteDebug(char *);
char MsgText[256];

void GetININame()
{
    GetProfileString("WINDOOM", "DIRECTORY", "", DoomDir, 128 );
    if (strlen(DoomDir) == 0)
	{
        getcwd(DoomDir, 128);
        WriteProfileString("WINDOOM", "DIRECTORY", DoomDir );
	}
    strcat(DoomDir, "\\windoom.INI");
}

void M_LoadDefaults (void)
{
/*
    int		i;
    int		len;
    FILE*	f;
    char	def[80];
    char	strparm[100];
    char*	newstring;
    int		parm;
    boolean	isstring;
*/    

    GetININame();

    mouseSensitivity = GetPrivateProfileInt("DEFAULTS", "mouse_sensitivity", 5, DoomDir);
    snd_SfxVolume = GetPrivateProfileInt("DEFAULTS", "sfx_volume", 15, DoomDir);
    snd_MusicVolume = GetPrivateProfileInt("DEFAULTS", "music_volume", 8, DoomDir);
    showMessages = GetPrivateProfileInt("DEFAULTS", "show_messages", 1, DoomDir);

    key_right = GetPrivateProfileInt("DEFAULTS", "key_right", KEY_RIGHTARROW, DoomDir);
    key_left = GetPrivateProfileInt("DEFAULTS", "key_left", KEY_LEFTARROW, DoomDir);
    key_up = GetPrivateProfileInt("DEFAULTS", "key_up", KEY_UPARROW, DoomDir);
    key_down = GetPrivateProfileInt("DEFAULTS", "key_down", KEY_DOWNARROW, DoomDir);

    key_strafeleft = GetPrivateProfileInt("DEFAULTS", "key_strafeleft", KEY_COMMA, DoomDir);
    key_straferight = GetPrivateProfileInt("DEFAULTS", "key_straferight", KEY_PERIOD, DoomDir);

    key_fire = GetPrivateProfileInt("DEFAULTS", "key_fire", KEY_RCTRL, DoomDir);
    key_use = GetPrivateProfileInt("DEFAULTS", "key_use", KEY_SPACE, DoomDir);
    key_strafe = GetPrivateProfileInt("DEFAULTS", "key_strafe", KEY_RALT, DoomDir);
    key_speed = GetPrivateProfileInt("DEFAULTS", "key_speed", KEY_RSHIFT, DoomDir);

    key_mvert = GetPrivateProfileInt("DEFAULTS", "key_mvert", KEY_SLASH, DoomDir);

    always_run = GetPrivateProfileInt("DEFAULTS", "always_run", FALSE, DoomDir);
    swap_stereo = GetPrivateProfileInt("DEFAULTS", "swap_stereo", FALSE, DoomDir);
    mvert = GetPrivateProfileInt("DEFAULTS", "mvert", 1, DoomDir);
    keylink = GetPrivateProfileInt("DEFAULTS", "keylink", TRUE, DoomDir);

    usemouse = GetPrivateProfileInt("DEFAULTS", "use_mouse", 1, DoomDir);
    mousebfire = GetPrivateProfileInt("DEFAULTS", "mouseb_fire", 0, DoomDir);
    mousebstrafe = GetPrivateProfileInt("DEFAULTS", "mouseb_strafe", 1, DoomDir);
    mousebforward = GetPrivateProfileInt("DEFAULTS", "mouseb_forward", 2, DoomDir);

    mouseb1 = GetPrivateProfileInt("DEFAULTS", "mouseb1", key_fire, DoomDir);
    mouseb2 = GetPrivateProfileInt("DEFAULTS", "mouseb2", key_strafe, DoomDir);
    mouseb3 = GetPrivateProfileInt("DEFAULTS", "mouseb3", key_up, DoomDir);

    usejoystick = GetPrivateProfileInt("DEFAULTS", "use_joystick", 0, DoomDir);
    joybfire = GetPrivateProfileInt("DEFAULTS", "joyb_fire", 0, DoomDir);
    joybstrafe = GetPrivateProfileInt("DEFAULTS", "joyb_strafe", 1, DoomDir);
    joybuse = GetPrivateProfileInt("DEFAULTS", "joyb_use", 3, DoomDir);
    joybspeed = GetPrivateProfileInt("DEFAULTS", "joyb_speed", 2, DoomDir);

    joyb1 = GetPrivateProfileInt("DEFAULTS", "joyb1", key_fire, DoomDir);
    joyb2 = GetPrivateProfileInt("DEFAULTS", "joyb2", key_strafe, DoomDir);
    joyb3 = GetPrivateProfileInt("DEFAULTS", "joyb3", key_use, DoomDir);
    joyb4 = GetPrivateProfileInt("DEFAULTS", "joyb4", key_speed, DoomDir);

    screenblocks = GetPrivateProfileInt("DEFAULTS", "screenblocks", 10, DoomDir);
    detailLevel = GetPrivateProfileInt("DEFAULTS", "detaillevel", 0, DoomDir);

    usegamma = GetPrivateProfileInt("DEFAULTS", "usegamma", 0, DoomDir);

    numChannels = GetPrivateProfileInt("DEFAULTS", "snd_channels", 256, DoomDir);
}
/*
snd_musicdevice		3
snd_sfxdevice		3
snd_sbport		544
snd_sbirq		5
snd_sbdma		1
snd_mport		816

chatmacro0		"no macro"
chatmacro1		"no macro"
chatmacro2		"no macro"
chatmacro3		"no macro"
chatmacro4		"no macro"
chatmacro5		"no macro"
chatmacro6		"no macro"
chatmacro7		"no macro"
chatmacro8		"no macro"
chatmacro9		"no macro"
*/

//
// SCREEN SHOTS
//


typedef struct
{
    char		manufacturer;
    char		version;
    char		encoding;
    char		bits_per_pixel;

    unsigned short	xmin;
    unsigned short	ymin;
    unsigned short	xmax;
    unsigned short	ymax;
    
    unsigned short	hres;
    unsigned short	vres;

    unsigned char	palette[48];
    
    char		reserved;
    char		color_planes;
    unsigned short	bytes_per_line;
    unsigned short	palette_type;
    
    char		filler[58];
    unsigned char	data;		// unbounded
} pcx_t;


//
// WritePCXfile
//
void
WritePCXfile
( char*		filename,
  byte*		data,
  int		width,
  int		height,
  byte*		palette )
{
    int		i;
    int		length;
    pcx_t*	pcx;
    byte*	pack;
	
    pcx = Z_Malloc (width*height*2+1000, PU_STATIC, NULL);

    pcx->manufacturer = 0x0a;		// PCX id
    pcx->version = 5;			// 256 color
    pcx->encoding = 1;			// uncompressed
    pcx->bits_per_pixel = 8;		// 256 color
    pcx->xmin = 0;
    pcx->ymin = 0;
    pcx->xmax = SHORT(width-1);
    pcx->ymax = SHORT(height-1);
    pcx->hres = SHORT(width);
    pcx->vres = SHORT(height);
    memset (pcx->palette,0,sizeof(pcx->palette));
    pcx->color_planes = 1;		// chunky image
    pcx->bytes_per_line = SHORT(width);
    pcx->palette_type = SHORT(2);	// not a grey scale
    memset (pcx->filler,0,sizeof(pcx->filler));


    // pack the image
    pack = &pcx->data;
	
    for (i=0 ; i<width*height ; i++)
    {
	if ( (*data & 0xc0) != 0xc0)
	    *pack++ = *data++;
	else
	{
	    *pack++ = 0xc1;
	    *pack++ = *data++;
	}
    }
    
    // write the palette
    *pack++ = 0x0c;	// palette ID byte
    for (i=0 ; i<768 ; i++)
	*pack++ = gammatable[usegamma][*palette++];
    
    // write output file
    length = pack - (byte *)pcx;
    M_WriteFile (filename, pcx, length);

    Z_Free (pcx);
}


//
// M_ScreenShot
//
void M_ScreenShot (void)
{
    int		i;
    byte*	linear;
    char	lbmname[12];
    
    // munge planar buffer to linear
    linear = screens[2];
    I_ReadScreen (linear);
    
    // find a file name to save it to
    strcpy(lbmname,"DOOM00.pcx");
		
    for (i=0 ; i<=99 ; i++)
    {
	lbmname[4] = i/10 + '0';
	lbmname[5] = i%10 + '0';
	if (access(lbmname,0) == -1)
	    break;	// file doesn't exist
    }
    if (i==100)
	I_Error ("M_ScreenShot: Couldn't create a PCX");
    
    // save the pcx file
    WritePCXfile (lbmname, linear,
		  SCREENWIDTH, SCREENHEIGHT,
		  W_CacheLumpName ("PLAYPAL",PU_CACHE));
	
    players[consoleplayer].message = "screen shot";
}


