/*****************************************************************************
                    The Dark Mod GPL Source Code
 
 This file is part of the The Dark Mod Source Code, originally based 
 on the Doom 3 GPL Source Code as published in 2011.
 
 The Dark Mod 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 3 of the License, 
 or (at your option) any later version. For details, see LICENSE.TXT.
 
 Project: The Dark Mod (http://www.thedarkmod.com/)
 
******************************************************************************/

#include "precompiled.h"
#pragma hdrstop



#include "qe3.h"
#include <direct.h>
#include <sys/stat.h>
#include "WaitDlg.h"

QEGlobals_t g_qeglobals;

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void WINAPI QE_CheckOpenGLForErrors(void) {
	CString strMsg;
	int		i = qglGetError();
	if (i != GL_NO_ERROR) {
		if (i == GL_OUT_OF_MEMORY) {
			//
			// strMsg.Format("OpenGL out of memory error %s\nDo you wish to save before
			// exiting?", gluErrorString((GLenum)i));
			//
			if (g_pParentWnd->MessageBox(strMsg, EDITOR_WINDOWTEXT " Error", MB_YESNO) == IDYES) {
				Map_SaveFile(NULL, false);
			}

			exit(1);
		}
		else {
			// strMsg.Format("Warning: OpenGL Error %s\n ", gluErrorString((GLenum)i));
			common->Printf(strMsg.GetBuffer(0));
		}
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
bool DoesFileExist(const char *pBuff, long &lSize) {
	CFile	file;
	if (file.Open(pBuff, CFile::modeRead | CFile::shareDenyNone)) {
		lSize += file.GetLength();
		file.Close();
		return true;
	}

	return false;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
bool ExtractPath_and_Filename(const char *pPath, CString &strPath, CString &strFilename) {
	CString strPathName = pPath;
	int		nSlash = strPathName.ReverseFind('\\');
	if (nSlash >= 0) {
		strPath = strPathName.Left(nSlash + 1);
		strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1);
	}
	else {
		strFilename = pPath;
	}

	return true;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void Map_Snapshot() {
	CString strMsg;

	//
	// we need to do the following 1. make sure the snapshot directory exists (create
	// it if it doesn't) 2. find out what the lastest save is based on number 3. inc
	// that and save the map
	//
	CString strOrgPath, strOrgFile;
	ExtractPath_and_Filename(currentmap, strOrgPath, strOrgFile);
	AddSlash(strOrgPath);
	strOrgPath += "snapshots";

	bool			bGo = true;
	struct _stat	Stat;
	if (_stat(strOrgPath, &Stat) == -1) {
		bGo = (_mkdir(strOrgPath) != -1);
	}

	AddSlash(strOrgPath);
	if (bGo) {
		int		nCount = 0;
		long	lSize = 0;
		CString strNewPath = strOrgPath;
		strNewPath += strOrgFile;

		CString strFile;
		while (bGo) {
			strFile.Format("%s.%i", strNewPath, nCount);
			bGo = DoesFileExist(strFile, lSize);
			nCount++;
		}

		// strFile has the next available slot
		Map_SaveFile(strFile.GetBuffer(0), false);
		Sys_SetTitle(currentmap);
		if (lSize > 12 * 1024 * 1024) { // total size of saves > 4 mb
			common->Printf
			(
				"The snapshot files in the [%s] directory total more than 4 megabytes. You might consider cleaning the directory up.",
				strOrgPath
			);
		}
	}
	else {
		strMsg.Format("Snapshot save failed.. unabled to create directory\n%s", strOrgPath);
		g_pParentWnd->MessageBox(strMsg);
	}
}

/*
 =======================================================================================================================
    QE_CheckAutoSave If five minutes have passed since making a change and the map hasn't been saved, save it out.
 =======================================================================================================================
 */
void QE_CheckAutoSave(void) {
	static bool inAutoSave = false;
	static bool autoToggle = false;
	if (inAutoSave) {
		Sys_Status("Did not autosave due recursive entry into autosave routine\n");
		return;
	}

	if ( !mapModified ) {
		return;
	}

	inAutoSave = true;

	if ( g_PrefsDlg.m_bAutoSave ) {
		CString strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving...";
		Sys_Status(strMsg.GetBuffer(0), 0);

		if (g_PrefsDlg.m_bSnapShots && stricmp(currentmap, "unnamed.map") != 0) {
			Map_Snapshot();
		} else {
			Map_SaveFile(ValueForKey(g_qeglobals.d_project_entity, (autoToggle == 0) ? "autosave1" : "autosave2" ), false, true);
			autoToggle ^= 1;
		}
		Sys_Status("Autosaving...Saved.", 0);
		mapModified = 0;		// DHM - _D3XP
	} else {
		common->Printf("Autosave skipped...\n");
		Sys_Status("Autosave skipped...", 0);
	}

	inAutoSave = false;
}

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

const char	*g_pPathFixups[] = {
	"basepath",

	// "remotebasepath",
	"entitypath",

	// "texturepath",
	"autosave",

	// "mapspath"
};

const int	g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof (const char *);

/*
 =======================================================================================================================
    QE_LoadProject
 =======================================================================================================================
 */
bool QE_LoadProject(char *projectfile) {
	char		*data;
	ID_TIME_T		time;

	common->Printf("QE_LoadProject (%s)\n", projectfile);

	if ( fileSystem->ReadFile( projectfile, reinterpret_cast < void ** > (&data), &time) <= 0 ) {
		return false;
	}

	g_strProject = projectfile;
	g_PrefsDlg.m_strLastProject = projectfile;
	g_PrefsDlg.SavePrefs();

	CString strData = data;

	fileSystem->FreeFile( data );

	StartTokenParsing(strData.GetBuffer(0));
	g_qeglobals.d_project_entity = Entity_Parse(true);
	if (!g_qeglobals.d_project_entity) {
		Error("Couldn't parse %s", projectfile);
	}

	// set here some default project settings you need
	if (strlen(ValueForKey(g_qeglobals.d_project_entity, "brush_primit")) == 0) {
		SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", "0");
	}

	g_qeglobals.m_bBrushPrimitMode = IntForKey(g_qeglobals.d_project_entity, "brush_primit");

	Eclass_InitForSourceDirectory(ValueForKey(g_qeglobals.d_project_entity, "entitypath"));
	g_Inspectors->FillClassList();	// list in entity window

	Map_New();

	// FillTextureMenu();
	FillBSPMenu();

	return true;
}

/*
 =======================================================================================================================
    QE_SaveProject £
 =======================================================================================================================
 */
bool QE_SaveProject(const char *pProjectFile) {

	idFile *file = fileSystem->OpenFileWrite(pProjectFile);
	if ( !file ) {
		return false;
	}

	file->Write("{\n", 2);

	int count = g_qeglobals.d_project_entity->epairs.GetNumKeyVals();
	for (int i = 0; i < count; i++) {
		file->WriteFloatString( "\"%s\" \"%s\"\n", g_qeglobals.d_project_entity->epairs.GetKeyVal(i)->GetKey().c_str(), g_qeglobals.d_project_entity->epairs.GetKeyVal(i)->GetValue().c_str());
	}

	file->Write("}\n", 2);

	fileSystem->CloseFile( file );

	return true;
}

/* QE_KeyDown */
#define SPEED_MOVE	32
#define SPEED_TURN	22.5

/*
 =======================================================================================================================
    ConnectEntities Sets target / name on the two entities selected from the first selected to the secon
 =======================================================================================================================
 */
void ConnectEntities(void) {
	entity_t	*e1;
	const char		*target;
	idStr strTarget;
	int i, t;

	if (g_qeglobals.d_select_count < 2) {
		Sys_Status("Must have at least two brushes selected.", 0);
		Sys_Beep();
		return;
	}

	e1 = g_qeglobals.d_select_order[0]->owner;

	for (i = 0; i < g_qeglobals.d_select_count; i++) {
		if (g_qeglobals.d_select_order[i]->owner == world_entity) {
			Sys_Status("Can't connect to the world.", 0);
			Sys_Beep();
			return;
		}
	}

	for (i = 1; i < g_qeglobals.d_select_count; i++) {
		if (e1 == g_qeglobals.d_select_order[i]->owner) {
			Sys_Status("Brushes are from same entity.", 0);
			Sys_Beep();
			return;
		}
	}

	target = ValueForKey(e1, "target");
	if ( target && *target) {
		for (t = 1; t < 2048; t++) {
			target = ValueForKey(e1, va("target%i", t));
			if (target && *target) {
				continue;
			} else {
				break;
			}
		}
	} else {
		t = 0;
	}

	for (i = 1; i < g_qeglobals.d_select_count; i++) {
		target = ValueForKey(g_qeglobals.d_select_order[i]->owner, "name");
		if (target && *target) {
			strTarget = target;
		} else {
			UniqueTargetName(strTarget);
		}
		if (t == 0) {
			SetKeyValue(e1, "target", strTarget);
		} else {
			SetKeyValue(e1, va("target%i", t), strTarget);
		}
		t++;
	}

	Sys_UpdateWindows(W_XY | W_CAMERA);

	Select_Deselect();
	Select_Brush(g_qeglobals.d_select_order[1]);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
bool QE_SingleBrush(bool bQuiet, bool entityOK) {
	if ((selected_brushes.next == &selected_brushes) || (selected_brushes.next->next != &selected_brushes)) {
		if (!bQuiet) {
			Sys_Status("Error: you must have a single brush selected\n");
		}

		return false;
	}

	if (!entityOK && selected_brushes.next->owner->eclass->fixedsize) {
		if (!bQuiet) {
			Sys_Status("Error: you cannot manipulate fixed size entities\n");
		}

		return false;
	}

	return true;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void QE_Init(void) {
	/* initialize variables */
	g_qeglobals.d_gridsize = 8;
	g_qeglobals.d_showgrid = true;

	/*
	 * other stuff £
	 * FIXME: idMaterial Texture_Init (true); Cam_Init (); XY_Init ();
	 */
	Z_Init();
}


int g_numbrushes, g_numentities;

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void QE_CountBrushesAndUpdateStatusBar(void) {
	static int	s_lastbrushcount, s_lastentitycount;
	static bool s_didonce;

	// entity_t *e;
	brush_t		*b, *next;

	g_numbrushes = 0;
	g_numentities = 0;

	if (active_brushes.next != NULL) {
		for (b = active_brushes.next; b != NULL && b != &active_brushes; b = next) {
			next = b->next;
			if (b->brush_faces) {
				if (!b->owner->eclass->fixedsize) {
					g_numbrushes++;
				}
				else {
					g_numentities++;
				}
			}
		}
	}

	/*
	 * if ( entities.next != NULL ) { for ( e = entities.next ; e != &entities &&
	 * g_numentities != MAX_MAP_ENTITIES ; e = e->next) { g_numentities++; } }
	 */
	if (((g_numbrushes != s_lastbrushcount) || (g_numentities != s_lastentitycount)) || (!s_didonce)) {
		Sys_UpdateStatusBar();

		s_lastbrushcount = g_numbrushes;
		s_lastentitycount = g_numentities;
		s_didonce = true;
	}
}

