#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "WSshutdown.h"

#define MAIN_PNL	1

#define TIMER_CLEARBTTN	1

#define INFO_NAV	998

// Make our class visible to the outside world
EXPORT_BNCS_SCRIPT( WSshutdown )


// Constructor - equivalent to ApplCore STARTUP
WSshutdown::WSshutdown(bncs_client_callback *parent, const char *path) : bncs_script_helper(parent, path)
{
	area = "";		// Set default values - area name to blank
	wsID = 0;		// Workstation ID
	sdMode = 0;		// No shutdown/reboot
	for (int i = 0; i <= MAX_WS; i++)
	{
		// Clear workstation ID and flag arrays
		wList[i] = 0;
		selWS[i] = 0;
		wsOpSys[i] = 0;
	}

	// Find our workstation id
	wsID = workstation();

	// Use the workstation settings to get the area and screen width
	bncs_string myArea = getWorkstationSetting("myarea");
	screenWidth = getWorkstationSetting("screenwidth");

	if (myArea.lower().startsWith("stc"))	area = "stc";
	if (myArea.lower().startsWith("sta"))	area = "sta";
	// Studio A uses 1024 by 768 screens. Studio C uses 1280 by 1024 screens
	// The two user interface designs are called 1280.bncs_u1 and 1024.bncs_ui
	panelName = screenWidth + ".bncs_ui";

	// If the area is neither "sta" or "stc", do not show a panel and return.
	if (area == "") return;
	
	// Use the studio name to find the list of workstations to shutdown or reboot
	// The list comprises pairs of entries such as "60,XP" The first element is the 
	// workstation id, the second is the operating system it runs. Supported OS names
	// are XP (standard XP) W7 (Windows 7) W10 (Windows 10) XPE (Windows XP Embedded)
	// Windows XP is the problem one, as it uses a different shutdown command.
	wslist = bncs_stringlist(getObjectSetting("ws_shutdown", area));
	wList[0] = wslist.count() / 2;			// Put the count of workstations in slot 0

	for (int i = 1, idx=1; i <= (wList[0]*2); i +=2, idx++)	// Put the workstation IDs in memories 1 to (max) 10
	{
		wList[idx] = wslist[i - 1];						// Saveworkstation number
		if (wslist[i] == "XPE") wsOpSys[idx] = 1;		// XP embedded has index code of 1
		else if (wslist[i] == "XP") wsOpSys[idx] = 2;	// Standard XP Pro or XP Home
		else if (wslist[i] == "W7") wsOpSys[idx] = 3;	// Windows 7 (any)
		else if (wslist[i] == "W10") wsOpSys[idx] = 4;	// Windows 10
	}

	// Show relevant panel
	panelShow(MAIN_PNL, panelName);

	// Disable one control
	controlDisable(MAIN_PNL, "Confirm");
}

// Destructor - equivalent to ApplCore CLOSEDOWN
WSshutdown::~WSshutdown()
{
}

// All button pushes and notifications come here.
void WSshutdown::buttonCallback( buttonNotify *b )
{
	if (b->panel() == MAIN_PNL)
	{
		// Check for workstation select button
		if (b->id().startsWith("WS_"))
		{
			int idx = b->id().firstInt();	// Extract number element
			selWS[idx] ^= 1;				// Toggle the select bit
			textPut("statesheet", (selWS[idx] == 0) ? "alarm_ignore" : "alarm_alarm", MAIN_PNL, b->id());
			ConfirmEnable();
			return;
		}

		// Select all workstations
		if (b->id() == "AllWS")
		{
			for (int idx = 1; idx <= wList[0]; idx++)
			{
				selWS[idx] = 1;						// Set the select bit
				textPut("statesheet", (selWS[idx] == 0)? "alarm_ignore": "alarm_alarm", MAIN_PNL, bncs_string("WS_%1").arg(idx,'0',2U));
				ConfirmEnable();
			}
			return;
		}

		// Type of restart required
		if (b->id() == "Shutdown")
		{
			sdMode = 1;
			closeBootShow(sdMode);
			ConfirmEnable();
		}

		if (b->id() == "Restart")
		{
			sdMode = 2;
			closeBootShow(sdMode);
			ConfirmEnable();
		}

		if (b->id() == "Cancel")
		{
			// Clear any workstation selections out.
			clearButtons();
			return;
		}

		if (b->id() == "Confirm")
		{
			// Windows XP embedded uses different shutdown program to windows XP
			// So this code supports potential for up to 4 different commands
			// that depend on the OS data read from Objects.xml
			bncs_string command;
			bncs_string options;
			bncs_string message;

			// Process the list of workstations and send the data at infodriver 998
			if (wList[0] > 0)		// Just being defensive!
			{
				// Cycle through the workstations that are selected for action and set the slot in the infodriver
				// for the workstation number
				for (int idx = 1; idx <= wList[0]; idx++)
				{
					if (selWS[idx] > 0)
					{
						switch (wsOpSys[idx])
						{
							case 0:
								// Not valid OS
								break;

							case 1:			// Windows XP Embedded
								command = "PX c:\\windows\\system32\\XpePM.exe";
								options = (sdMode == 1) ? " -Shutdown" : " -Restart";	// shutdown or restart
								message = command + options;
								infoWrite(INFO_NAV, message, wList[idx], true);
								break;

							case 2:			// Windows XP
							case 3:			// Windows 7
							case 4:			// Windows 10
								command = "PX c:\\windows\\system32\\shutdown.exe";
								options = (sdMode == 1) ? " /s /t 2" : " /r /t 2";	// shutdown or restart
								message = command + options;
								infoWrite(INFO_NAV, message, wList[idx], true);
								break;
						}
					}
				}

				// Start a timer that will clear down the buttons as part of it's service routine.
				timerStart(TIMER_CLEARBTTN, 250);

			}	// End of if (wList[0] > 0)	
		}	// End of "Confirm" button processin
	}	// End of if (b->panel() == MAIN_PNL)
}


// All revertives come here
int WSshutdown::revertiveCallback(revertiveNotify *r)
{
	return 0;
}

// All database name changes come back here
void WSshutdown::databaseCallback(revertiveNotify *r)
{
}

// All parent notifications come here i.e. when this script is just one 
// component of another dialog then our host might want to tell us things
bncs_string WSshutdown::parentCallback(parentNotify *p)
{
	if( p->command() == "return" )
	{
		if( p->value() == "all" )
		{	
			// Persisting values for bncs_vis_ed
			bncs_stringlist sl;
			sl << bncs_string( "" );
			return sl.toString( '\n' );
		}
	}

	// ***** CONNECTIONS EVENTS HELPER LIST *****
	else if( p->command() == "_events" )
	{	
		// Helper-list of everything in this component generated by hostNotify's
		bncs_stringlist sl;
		sl << "notify=*";		
		return sl.toString( '\n' );
	}

	// ***** CONNECTIONS COMMANDS HELPER LIST *****
	else if( p->command() == "_commands" )
	{	
		// Helper-list of any commands/parameters you might want to set at run-time
		bncs_stringlist sl;
		sl << "myParam=[value]";
		return sl.toString( '\n' );
	}
	return "";
}

// Timer events come here
void WSshutdown::timerCallback( int id )
{
	switch( id )
	{
	case TIMER_CLEARBTTN:
		// Triggered by Restart/Reboot Confirm button. Need to clear active buttons states
		timerStop(id);
		clearButtons();	// Call service routine to clear down the buttons.
		break;

	default:	// Unhandled timer event
		timerStop(id);
		break;
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////
// closeBootShow(int mode) manages the button highlighting of the Reboot and Shutdown buttons.
// Parameter mode has three valuid values - 0 = no selection, 1 = Shutdown workstation
// 2 = Reboot workstation
void WSshutdown::closeBootShow(int mode)
{
	switch (mode)
	{
	case 0:
		textPut("statesheet", "alarm_ignore", MAIN_PNL, "Shutdown");
		textPut("statesheet", "alarm_ignore", MAIN_PNL, "Restart");
		break;

	case 1:
		textPut("statesheet", "alarm_alarm", MAIN_PNL, "Shutdown");
		textPut("statesheet", "alarm_ignore", MAIN_PNL, "Restart");
		break;

	case 2:
		textPut("statesheet", "alarm_ignore", MAIN_PNL, "Shutdown");
		textPut("statesheet", "alarm_alarm", MAIN_PNL, "Restart");
		break;
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////
// ConfirmEnable(void) checks that at least one workstation is selected, and that either shutdown
// or reboot has been selected. If the two conditions are met, the Confirm button is enabled,
// otherwise it is disabled.
void WSshutdown::ConfirmEnable(void)
{
	int count = 0;

	// Count the number of active workstations.
	for (int i = 1; i <= MAX_WS; i++)
	{
		if (selWS[i] > 0) count++;
	}

	if (((sdMode == 1) || (sdMode == 2)) && (count > 0))
	{
		
		controlEnable(MAIN_PNL, "Confirm");		// Enable the button
	}
	else
	{
		controlDisable(MAIN_PNL, "Confirm");	// Disable the button
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////
// clearButtons(void) is called to deselect any selected workstation buttons, and disable the 
// Confirm button.
void WSshutdown::clearButtons(void)
{
	// Clear any workstation selections out.
	for (int idx = 1; idx <= wList[0]; idx++)
	{
		if (selWS[idx] > 0)
		{
			selWS[idx] = 0;
			textPut("statesheet", "alarm_ignore", MAIN_PNL, bncs_string("WS_%1").arg(idx, '0', 2U));
		}
	}

	if (sdMode > 0)
	{
		sdMode = 0;					// Set mode to unselected
		closeBootShow(sdMode);		// Update button highlights
		ConfirmEnable();			// Disable the confirm button
	}
}

