//Copyright (c) 1998 - 1999 Microsoft Corporation

// subcomp.cpp
// implementation a default sub component

#include "stdafx.h"
#include "subcomp.h"


OCMSubComp::OCMSubComp ()
{
    m_lTicks = 0;
}

BOOL OCMSubComp::Initialize ()
{

    return TRUE;
}

BOOL OCMSubComp::GetCurrentSubCompState () const
{
    return GetHelperRoutines().QuerySelectionState(
        GetHelperRoutines().OcManagerContext,
        GetSubCompID(),
        OCSELSTATETYPE_CURRENT);
}

BOOL OCMSubComp::GetOriginalSubCompState () const
{
    return GetHelperRoutines().QuerySelectionState(
        GetHelperRoutines().OcManagerContext,
        GetSubCompID(),
        OCSELSTATETYPE_ORIGINAL);
}

BOOL OCMSubComp::HasStateChanged () const
{
    //
    // returns true if current selection state is different from previous.
    //
    return GetCurrentSubCompState() != GetOriginalSubCompState();

}

//
// this functions ticks the gauge for the specified count
// keep traks of the count reported to the OC_QUERY_STEP_COUNT
//
void OCMSubComp::Tick (DWORD  dwTickCount /* = 1 */)
{
    if (m_lTicks > 0)
    {
        m_lTicks -= dwTickCount;
        while(dwTickCount--)
            GetHelperRoutines().TickGauge( GetHelperRoutines().OcManagerContext );

    }
    else
    {
        m_lTicks = 0;
    }
}

//
// completes the remaining ticks.
//
void OCMSubComp::TickComplete ()
{
    ASSERT(m_lTicks >= 0);
    while (m_lTicks--)
        GetHelperRoutines().TickGauge( GetHelperRoutines().OcManagerContext );
}

DWORD OCMSubComp::OnQueryStepCount()
{
    m_lTicks = GetStepCount() + 2;
    return m_lTicks;
}

DWORD OCMSubComp::GetStepCount () const
{
    return 0;
}


DWORD OCMSubComp::OnQueryState ( UINT uiWhichState ) const
{
	LOGMESSAGE1(_T("In OCMSubComp::OnQueryState  for %s"), GetSubCompID());

    ASSERT(OCSELSTATETYPE_ORIGINAL == uiWhichState ||
           OCSELSTATETYPE_CURRENT == uiWhichState ||
           OCSELSTATETYPE_FINAL == uiWhichState );

    return SubcompUseOcManagerDefault;

}

DWORD OCMSubComp::OnQuerySelStateChange (BOOL /* bNewState */, BOOL /* bDirectSelection */) const
{
    return TRUE;
}

DWORD OCMSubComp::LookupTargetSection(LPTSTR szTargetSection, DWORD dwSize, LPCTSTR lookupSection)
{
    DWORD dwError = GetStringValue(GetComponentInfHandle(), GetSubCompID(), lookupSection, szTargetSection, dwSize);
    if (dwError == ERROR_SUCCESS)
    {
        LOGMESSAGE2(_T("sectionname = <%s>, actual section = <%s>"), lookupSection, szTargetSection);
    }
    else
    {
        AssertFalse();
        LOGMESSAGE1(_T("ERROR:GetSectionToBeProcess:GetStringValue failed GetLastError() = %lu"), dwError);
    }

    return dwError;
}

DWORD OCMSubComp::GetTargetSection(LPTSTR szTargetSection, DWORD dwSize, ESections eSectionType, BOOL *pbNoSection)
{
    ASSERT(szTargetSection);
    ASSERT(pbNoSection);

    //
    // get section to be processed
    //
    LPCTSTR szSection = GetSectionToBeProcessed( eSectionType );

    if (szSection == NULL)
    {
        *pbNoSection = TRUE;
        return NO_ERROR;
    }
    else
    {
        //
        // there is a section to be processed.
        //
        *pbNoSection = FALSE;
    }


    //
    // look for the target section
    //
    return LookupTargetSection(szTargetSection, dwSize, szSection);

}

DWORD OCMSubComp::OnCalcDiskSpace ( DWORD addComponent, HDSKSPC dspace )
{
	LOGMESSAGE1(_T("In OCMSubComp::OnCalcDiskSpace for %s"), GetSubCompID());

    TCHAR TargetSection[S_SIZE];
    BOOL bNoSection = FALSE;

    DWORD rc = GetTargetSection(TargetSection, S_SIZE, kDiskSpaceAddSection, &bNoSection);

    //
    // if there is no section to be processed. just return success.
    //
    if (bNoSection)
    {
        return NO_ERROR;
    }

    if (rc == NO_ERROR)
    {
        if (addComponent)
        {
            LOGMESSAGE1(_T("Calculating disk space for add section =  %s"), TargetSection);
            rc = SetupAddInstallSectionToDiskSpaceList(
                dspace,
                GetComponentInfHandle(),
                NULL,
                TargetSection,
                0,
                0);
        }
        else
        {
            LOGMESSAGE1(_T("Calculating disk space for remove section =  %s"), TargetSection);
            rc = SetupRemoveInstallSectionFromDiskSpaceList(
                dspace,
                GetComponentInfHandle(),
                NULL,
                TargetSection,
                0,
                0);
        }

        if (!rc)
            rc = GetLastError();
        else
            rc = NO_ERROR;

    }

    return rc;
}

DWORD OCMSubComp::OnQueueFiles ( HSPFILEQ queue )
{
	LOGMESSAGE1(_T("In OCMSubComp::OnQueueFiles for %s"), GetSubCompID());

    TCHAR TargetSection[S_SIZE];
    BOOL bNoSection = FALSE;
    DWORD rc = GetTargetSection(TargetSection, S_SIZE, kFileSection, &bNoSection);

    //
    // if there is no section to be processed. just return success.
    //
    if (bNoSection)
    {
        return NO_ERROR;
    }


    if (rc == NO_ERROR)
    {
        LOGMESSAGE1(_T("Queuing Files from Section = %s"), TargetSection);
        if (!SetupInstallFilesFromInfSection(
            GetComponentInfHandle(),
            NULL,
            queue,
            TargetSection,
            NULL,
            0  // this should eliminate the warning about overwriting newer file.
            ))
        {
            rc = GetLastError();
            LOGMESSAGE2(_T("ERROR:OnQueueFileOps::SetupInstallFilesFromInfSection <%s> failed.GetLastError() = <%ul)"), TargetSection, rc);
        }
        else
        {
            return NO_ERROR;
        }

    }

    return rc;
}

DWORD OCMSubComp::OnCompleteInstall ()
{
	LOGMESSAGE1(_T("In OCMSubComp::OnCompleteInstall for %s"), GetSubCompID());
    if (!BeforeCompleteInstall ())
    {
        LOGMESSAGE0(_T("ERROR:BeforeCompleteInstall failed!"));
    }

    TCHAR TargetSection[S_SIZE];
    BOOL bNoSection = FALSE;
    DWORD dwError = GetTargetSection(TargetSection, S_SIZE, kRegistrySection, &bNoSection);

    //
    // if there is no section to be processed. just go ahead.
    //
    if (!bNoSection)
    {
        LOGMESSAGE1(_T("Setting up Registry/Links/RegSvrs from section =  %s"), TargetSection);
        dwError = SetupInstallFromInfSection(
            NULL,                                // hwndOwner
            GetComponentInfHandle(),             // inf handle
            TargetSection,                       //
            SPINST_ALL & ~SPINST_FILES,          // operation flags
            NULL,                                // relative key root
            NULL,                                // source root path
            0,                                   // copy flags
            NULL,                                // callback routine
            NULL,                                // callback routine context
            NULL,                                // device info set
            NULL                                 // device info struct
            );

        if (dwError == 0)
            LOGMESSAGE1(_T("ERROR:while installating section <%lu>"), GetLastError());
    }

    Tick();

    if (!AfterCompleteInstall ())
    {
        LOGMESSAGE0(_T("ERROR:AfterCompleteInstall failed!"));
    }

    TickComplete();
    return NO_ERROR;
}

BOOL OCMSubComp::BeforeCompleteInstall  ()
{
    return TRUE;
}

BOOL OCMSubComp::AfterCompleteInstall   ()
{
    return TRUE;
}

DWORD OCMSubComp::OnAboutToCommitQueue  ()
{
    return NO_ERROR;
}

void
OCMSubComp::SetupRunOnce( HINF hInf, LPCTSTR SectionName )
{
    INFCONTEXT  sic;
    TCHAR CommandLine[ RUNONCE_CMDBUFSIZE ];
    BOOL b;
    STARTUPINFO startupinfo;
    PROCESS_INFORMATION process_information;
    DWORD dwErr;

    if (!SetupFindFirstLine( hInf, SectionName, NULL , &sic))
    {
        LOGMESSAGE1(_T("WARNING: nothing in %s to be processed."), SectionName);
    }
    else
    {
        do  {
            if (!SetupGetStringField(&sic, 1, CommandLine, RUNONCE_CMDBUFSIZE, NULL))
            {
                LOGMESSAGE1(_T("WARNING: No command to be processed."), SectionName);
                break;
            }

            LOGMESSAGE1(_T("RunOnce: spawning process %s"), CommandLine);


            ZeroMemory( &startupinfo, sizeof(startupinfo) );
            startupinfo.cb = sizeof(startupinfo);
            startupinfo.dwFlags = STARTF_USESHOWWINDOW;
            startupinfo.wShowWindow = SW_HIDE | SW_SHOWMINNOACTIVE;

            b = CreateProcess( NULL,
                               CommandLine,
                               NULL,
                               NULL,
                               FALSE,
                               CREATE_DEFAULT_ERROR_MODE,
                               NULL,
                               NULL,
                               &startupinfo,
                               &process_information );
            if ( !b )
            {
                LOGMESSAGE1(_T("ERROR: failed to spawn %s process."), CommandLine);
                continue;
            }

            dwErr = WaitForSingleObject( process_information.hProcess, RUNONCE_DEFAULTWAIT );
            if ( dwErr != NO_ERROR )
            {
                LOGMESSAGE1(_T("ERROR: process %s failed to complete in time."), CommandLine);

                // Don't terminate process, just go on to next one.
            }
            else
            {
                LOGMESSAGE1(_T("INFO: process %s completed successfully."), CommandLine);
            }

            CloseHandle( process_information.hProcess );
            CloseHandle( process_information.hThread );
        } while ( SetupFindNextLine( &sic, &sic ) );
    }

    return;
}