//	Zinc Application Framework - P_APP.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

//#define ZAF_LOADABLE	// loadable from a command-line target shell

#include <z_app.hpp>
#include <z_error.hpp>	// For Beep().

#include "sys_conf.h"

#include <cxx/init_cxx.h>
#include <psoscfg.h>
#include <drv_intf.h>
#include <phile.h>
#include <prepc.h>
#include <pna.h>

// _mainTaskID is the task id of the application.  We need to keep track of
// the task id so we can send it an event in UnBlock.  If we move to a 
// "multitasking" (shared) version of ZAF, we will need to modify how we
// keep track of it.
unsigned long _mainTaskID;
ZafIChar **_driveNames;
int _driveCount;

#define NULLF ((void (*)(ioparms *)) 0)

int GetDriveNames(ZafIChar **[]);

// ----- main ---------------------------------------------------------------

void ZafPSOSMain(unsigned long tid)
{
	InitCxxRuntime(16, 2048);
#if !defined(ZAF_LOADABLE)
	unsigned long iopb[4], ioretval, rc;
	void *data;
	_driveCount = GetDriveNames(&_driveNames);

	if (_driveCount)
	{
		for (int cnt = 0; cnt < _driveCount; ++cnt)
		{
        	pcmount_vol(_driveNames[cnt], SM_IMMED_WRITE);
			if (cnt == 0)
			{
				char rootname[20];
    			strcpy(rootname, _driveNames[cnt]);
    			strcat(rootname,"/");
		    	change_dir(rootname);
			}
		}
	}
#endif

	{
		// Call the application program.
		ZafApplication application(0, 0);
		if (application.Error() == ZAF_ERROR_CONSTRUCTOR)
		{
			// The ZafApplication object was not fully constructed.
			ZafErrorStub::Beep();
		}
		else
			application.Main();

#if defined(SC_PREPC)
		fclose(0);
#endif
#if defined(SC_PHILE)
		close_f(0);
#endif
#if defined(SC_PNA)
		close(0);
#endif
#if defined(SC_PREPC)
		free((void *)-1);
#endif

	}

#if !defined(ZAF_LOADABLE)
	if (_driveCount)
		for (int cnt = 0; cnt < _driveCount; ++cnt)
        	unmount_vol(_driveNames[cnt]);
#else
	ev_send(tid, 1);
#endif
    if (t_delete(0L))
		ZafErrorStub::Beep();
}

extern "C"
{
#if !defined(ZAF_LOADABLE)
void root(void)
#else
void root(unsigned long tid)
#endif
{
	unsigned long args[4];

#if !defined(ZAF_LOADABLE)
	args[0] = 0;
#else
	args[0] = tid;
#endif

	t_create("main", 200, ZAF_PSOS_SSTACK_SIZE, ZAF_PSOS_USTACK_SIZE, T_LOCAL | T_NOFPU, &_mainTaskID);
	t_start(_mainTaskID, T_SUPV | T_NOASR | T_PREEMPT | T_TSLICE, (void (*)())ZafPSOSMain, args);

#if !defined(ZAF_LOADABLE)
	t_suspend(0L);
//	t_delete(0L);
#else
#if defined(SC_PREPC)
		free((void *)-1);
#endif
	// Task is deleted by the shell.
	t_suspend(0L);
#endif
}
}

int GetDriveNames(ZafIChar **getDriveName[])
{
	unsigned long iopb[4], ioretval, rc;
	void *data;
	unsigned long device;
	static int drives = 0;

#if defined(DEV_IDE)

	struct ide_ctl_iopb ide_iopb;

	// de_init only works the first time it is called.
	static bool firstTime = true;
	if (firstTime)
	{
		firstTime = false;

		// If de_init() fails, we can assume there is no IDE driver present.
		if (de_init(DEV_IDE, iopb, &ioretval, &data) != 0)
    		return 0;
	}
	else if (!drives)
	{
		if (getDriveName)
		{
			ZafIChar **driveNames = new ZafIChar *[1];
			driveNames[drives] = ZAF_NULLP(ZafIChar);
		}
		return 0;
	}

	// Poll to see what IDE devices are present.                         
	for (device = DEV_IDE; device < DEV_IDE + 4; device++)
    {
    	ide_iopb.function = IDE_CTL_INFO;
    	if (de_cntrl(device, &ide_iopb, &ioretval) == 0)
        {
        	for (rc=0; rc<IDE_MAX_PART; rc++)
           	{
            	if (ide_iopb.u.info.partition_info[rc].begin || 
                	ide_iopb.u.info.partition_info[rc].size)
					++drives;
           	}
        }
    }

	if (getDriveName)
	{
		ZafIChar **driveNames = new ZafIChar *[drives + 1];
		driveNames[drives] = ZAF_NULLP(ZafIChar);
		ZafIChar volname[16];
		int disk;
		int index = 0;

		for (device = DEV_IDE; device < DEV_IDE + 4; device++)
    	{
    		ide_iopb.function = IDE_CTL_INFO;
    		if (de_cntrl(device, &ide_iopb, &ioretval) == 0)
        	{
        		for (rc=0; rc<IDE_MAX_PART; rc++)
           		{
            		if (ide_iopb.u.info.partition_info[rc].begin || 
                		ide_iopb.u.info.partition_info[rc].size)
               		{
                    	disk = device | ((rc+1)<< 8);
						sprintf(volname,"%d.%d.%d",
       						(disk >> 16), (disk & 0xff), (disk >> 8) & 0xff);
						driveNames[index++] = strdup(volname);
               		}
           		}
        	}
    	}

		*getDriveName = driveNames;
	}

	return (drives);

#elif defined(DEV_SCSI)
#endif

}

